[Git & GitHub] 合并多个commit

大家都知道 Git 是一种分布式的版本控制工具。正因为它有「分布式」这个特性,所以理论上我们其实可以不需要连接网络,就可以进行版本管理。然而,在实际上这是不可能的,因为你还需要上网查 Git 的各种命令。

我为什么要写这篇文章呢?因为实在太多同学跑来问我「怎么减少Pull Request中的commit记录?到底怎么合并 commit?pull request有太多commit记录?」了,每次都重复讲一遍这种做法完全不符合程序猿的风格啊!

那么,就先让我们来看这么一个情况,我们执行以下命令获得四个 Commit:

mkdir test
cd test

git init

echo "0" >> a
git add a
git commit -m "Commit-0"

echo "1" >> a
git add a
git commit -m "Commit-1"

echo "2" >> a
git add a
git commit -m "Commit-2"

echo "3" >> a
git add a
git commit -m "Commit-3"

我们可以看到 Git 的历史长成这样:

 
  1.  
    * b1b8189 - (HEAD -> master) Commit-3
  2.  
    * 5756e15 - Commit-2
  3.  
    * e7ba81d - Commit-1
  4.  
    * 5d39ff2 - Commit-0
 

那么问题来了,如何把 e7ba81d(Commit-1)5756e15(Commit-2)b1b8189(Commit-3) 合并到一起,并且只保留 e7ba81d(Commit-1) 的 Git message Commit-1 呢?

这个时候我们就要祭出我们这篇文章的主角—— git rebase -i 了!
这里我不想直接搬出写文档的那套,把所有的选项都介绍完,我们就把这次要用到的讲一下。

-i 实际上就是 --interactive 的简写,在使用 git rebase -i 时,我们要在后面再添加一个参数,这个参数应该是 最新的一个想保留的 Commit。这句话读起来有点坳口,所以这个情况下通常需要举个例子。就我们前面提到的那个例子中,这个「最新的一个想保留的 Commit」就是 5d39ff2(Commit-0),于是我们的命令看起来就长这样:

git rebase -i 5d39ff2

当然,我们也可以通过 HEAD~3 来指定该 Commit:

git rebase -i HEAD~3

按下回车后,我们会进入到这么一个界面:

 
  1.  
    pick e7ba81d Commit-1
  2.  
    pick 5756e15 Commit-2
  3.  
    pick b1b8189 Commit-3
  4.  
     
  5.  
    # Rebase 5d39ff2..b1b8189 onto 5d39ff2 (3 command(s))
  6.  
    #
  7.  
    # Commands:
  8.  
    # p, pick = use commit
  9.  
    # r, reword = use commit, but edit the commit message
  10.  
    # e, edit = use commit, but stop for amending
  11.  
    # s, squash = use commit, but meld into previous commit
  12.  
    # f, fixup = like "squash", but discard this commit's log message
  13.  
    # x, exec = run command (the rest of the line) using shell
  14.  
    #
  15.  
    # These lines can be re-ordered; they are executed from top to bottom.
  16.  
    #
  17.  
    # If you remove a line here THAT COMMIT WILL BE LOST.
  18.  
    #
  19.  
    # However, if you remove everything, the rebase will be aborted.
  20.  
    #
  21.  
    # Note that empty commits are commented out
 

前面三行是我们需要操作的三个 Commit,每行最前面的是对该 Commit 操作的 Command。关于每个 Command 具体做什么,下面的注释写得非常清楚。为了完成我们的需求,我们可以关注到这两个命令:

 
  1.  
    s, squash = use commit, but meld into previous commit
  2.  
    f, fixup = like "squash", but discard this commit's log message
  3.  
     
 

为了让大家看得更明白,我不厌其烦地翻译一下:

  • squash:使用该 Commit,但会被合并到前一个 Commit 当中
  • fixup:就像 squash 那样,但会抛弃这个 Commit 的 Commit message

看样子两个命令都可以完成我们的需求,那么让我们先试一下 squash!由于我们是想把三个 Commit 都合并在一起,并且使 Commit Message 写成 Commit-1,所以我们需要把 5756e15(Commit-2) 和 b1b8189(Commit-3) 前面的 pick 都改为squash,于是它看起来像这样:

 
  1.  
    pick e7ba81d Commit-1
  2.  
    squash 5756e15 Commit-2
  3.  
    squash b1b8189 Commit-3
 

当然,因为我很懒,所以通常我会使用它的缩写:

 
  1.  
    pick e7ba81d Commit-1
  2.  
    s 5756e15 Commit-2
  3.  
    s b1b8189 Commit-3
 

完成后,使用 :wq 保存并退出。这个时候,我们进入到了下一个界面:

 
  1.  
    # This is a combination of 3 commits.
  2.  
    # The first commit's message is:
  3.  
    Commit-1
  4.  
     
  5.  
    # This is the 2nd commit message:
  6.  
     
  7.  
    Commit-2
  8.  
     
  9.  
    # This is the 3rd commit message:
  10.  
     
  11.  
    Commit-3
  12.  
     
  13.  
    # Please enter the commit message for your changes. Lines starting
  14.  
    # with '#' will be ignored, and an empty message aborts the commit.
  15.  
    #
  16.  
    # Date: Tue Jan 5 23:27:22 2016 +0800
  17.  
    #
  18.  
    # rebase in progress; onto 5d39ff2
  19.  
    # You are currently editing a commit while rebasing branch 'master' on '5d39ff2'.
  20.  
    #
  21.  
    # Changes to be committed:
  22.  
    # modified: a
 

通过下面的注释,我们可以知道,这里其实就是一个编写 Commit Message 的界面,带 # 的行会被忽略掉,其余的行就会作为我们的新 Commit Message。为了完成我们的需求,我们修改成这样:

 
  1.  
    Commit-1
  2.  
     
  3.  
    # Please enter the commit message for your changes. Lines starting
  4.  
    # with '#' will be ignored, and an empty message aborts the commit.
  5.  
    #
  6.  
    # Date: Tue Jan 5 23:27:22 2016 +0800
  7.  
    #
  8.  
    # rebase in progress; onto 5d39ff2
  9.  
    # You are currently editing a commit while rebasing branch 'master' on '5d39ff2'.
  10.  
    #
  11.  
    # Changes to be committed:
  12.  
    # modified: a
 

使用 :wq 后,再看一下我们的 log:

 
  1.  
    * 2d7b687 - (HEAD -> master) Commit-1
  2.  
    * 5d39ff2 - Commit-0
 

任务完成!

至于 fixup 怎么用,我觉得大家现在应该已经知道了,因为我已经展示过 squash 的用法了,相信你再去看一下上面的 fixup 的解释就能明白了。

 

转自:https://github.com/Jisuanke/tech-exp/issues/13

猜你喜欢

转载自blog.csdn.net/dietime1943/article/details/85113142