Description
大家都知道 Git 是一种分布式的版本控制工具。正因为它有「分布式」这个特性,所以理论上我们其实可以不需要连接网络,就可以进行版本管理。然而,在实际上这是不可能的,因为你还需要上网查 Git 的 中种命令(逃
哈哈,玩笑开完,进入正题吧!
我为什么要写这篇文章呢?因为实在太多同学跑来问我「到底怎么合并 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 的历史长成这样:
* b1b8189 - (HEAD -> master) Commit-3
* 5756e15 - Commit-2
* e7ba81d - Commit-1
* 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
按下回车后,我们会进入到这么一个界面:
pick e7ba81d Commit-1
pick 5756e15 Commit-2
pick b1b8189 Commit-3
# Rebase 5d39ff2..b1b8189 onto 5d39ff2 (3 command(s))
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
前面三行是我们需要操作的三个 Commit,每行最前面的是对该 Commit 操作的 Command。关于每个 Command 具体做什么,下面的注释写得非常清楚。为了完成我们的需求,我们可以关注到这两个命令:
s, squash = use commit, but meld into previous commit
f, fixup = like "squash", but discard this commit's log message
为了让大家看得更明白,我不厌其烦地翻译一下:
squash
:使用该 Commit,但会被合并到前一个 Commit 当中fixup
:就像squash
那样,但会抛弃这个 Commit 的 Commit message
看样子两个命令都可以完成我们的需求,那么让我们先试一下 squash
!由于我们是想把三个 Commit 都合并在一起,并且使 Commit Message 写成 Commit-1
,所以我们需要把 5756e15(Commit-2)
和 b1b8189(Commit-3)
前面的 pick
都改为squash
,于是它看起来像这样:
pick e7ba81d Commit-1
squash 5756e15 Commit-2
squash b1b8189 Commit-3
当然,因为我很懒,所以通常我会使用它的缩写:
pick e7ba81d Commit-1
s 5756e15 Commit-2
s b1b8189 Commit-3
完成后,使用 :wq
保存并退出。这个时候,我们进入到了下一个界面:
# This is a combination of 3 commits.
# The first commit's message is:
Commit-1
# This is the 2nd commit message:
Commit-2
# This is the 3rd commit message:
Commit-3
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Tue Jan 5 23:27:22 2016 +0800
#
# rebase in progress; onto 5d39ff2
# You are currently editing a commit while rebasing branch 'master' on '5d39ff2'.
#
# Changes to be committed:
# modified: a
通过下面的注释,我们可以知道,这里其实就是一个编写 Commit Message 的界面,带 #
的行会被忽略掉,其余的行就会作为我们的新 Commit Message。为了完成我们的需求,我们修改成这样:
Commit-1
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Tue Jan 5 23:27:22 2016 +0800
#
# rebase in progress; onto 5d39ff2
# You are currently editing a commit while rebasing branch 'master' on '5d39ff2'.
#
# Changes to be committed:
# modified: a
使用 :wq
后,再看一下我们的 log:
* 2d7b687 - (HEAD -> master) Commit-1
* 5d39ff2 - Commit-0
任务完成!
至于 fixup
怎么用,我觉得大家现在应该已经知道了,因为我已经展示过 squash
的用法了,相信你再去看一下上面的 fixup
的解释就能明白了。
那么这篇文章就这样粗略地讲了一下 git rebase -i
的最基础的用法,希望能帮助到大家,有任何问题可以直接在评论里问我吧~
Activity
jaysimon commentedon Jun 15, 2017
Q:最好能说明一下最后的a文件时什么样的状态,处在commit 几的状态
kevin1202 commentedon Aug 8, 2017
很清楚,感谢
yanhaijing commentedon Aug 8, 2017
差评,一个图都没有
gzhjs commentedon Aug 8, 2017
赞!!但是感觉会导致大家滥用rebase,毕竟它会导致一些历史被丢掉
yanhaijing commentedon Aug 8, 2017
@gzhjs push的就不能rebase了
GeeLaw commentedon Aug 8, 2017
@gzhjs 我经常把弱智的错误通过
fixup
弄掉。@yanhaijing 可以
--force
,虽然会让别人很麻烦(如果别人pull
了你的 branch)。yanhaijing commentedon Aug 9, 2017
@GeeLaw 这样不好,最好的就是 禁止push -f
countzj commentedon Sep 5, 2017
这个太麻烦,用tortoiseGit可以轻松搞定,调出提交日志,选择需要合并的日志,就会出来合并按钮,修改一个注释就搞定了!
countzj commentedon Sep 5, 2017
还没发现sourcetree怎么合并commit,知道的可以分享一下
yanhaijing commentedon Sep 5, 2017
命令行多好用,一次学会,受益终身
keer3 commentedon Sep 11, 2017
如果想把
这两个commit合并有什么办法?
countzj commentedon Sep 11, 2017
如果合并commit-2和commit-1,就在git rebase -i 后面跟上commit1和2的序列号就可以了吧
GeeLaw commentedon Sep 11, 2017
@SUNSHUMIN
之后 commit-3 的 hash 自然会变化。
15 remaining items