git rebase
$ git rebase -i origin/master
-i 参数表示互动 interactive,这时 git 会使用你设定的编辑器,让你对 git 历史记录做详细修改。
举例:
# 开始开发一个新 feature
$ git checkout -b dev-new master
# 改了一些代码
$ git commit -a -m "Start developing a feature"
# 刚刚的修改有点问题,再改一下
$ git commit -a -m "Fix something from the previous commit"
# 紧急修复,直接在 master 分支上改点东西
$ git checkout master
# 改了一些代码
$ git commit -a -m "Fix security hole"
# 开始交互式地 rebase 了
$ git checkout dev-new
$ git rebase -i master
这时 git 会打开编辑器,你会看到 new-feature 分支上的 2 个最新 commit,以及一些指引提示
pick 32618c4 Start developing a feature
pick 62eed47 Fix something from the previous commit
# 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 前有一个操作命令,默认是 pick ,表示该行被选中,需要进行 rebase 操作。下面一堆注释的指引中还有几个指令,我们常用到的是以下 2 个
- squash:将这一行的 commit 与上一个 commit 进行合并
- fixup:与 squash 相同,只是不会保留这行commit 的提交 message 信息
1、squash
比如上面的例子,我们在编辑器中修改指令为:
pick 32618c4 Start developing a feature
squash 62eed47 Fix something from the previous commit
完成修改后保存文件,git执行自动合并过程,并提示:
Successfully rebased and updated refs/heads/dev-new.
这样一改,保存执行后,new-feature 分支就只剩下 1 个 commit 了,这个合并后的 commit 提交的信息包含之前 2 个 commit 的信息
Start developing a feature
Fix something from the previous commit
消除了一个多余的不那么重要的 commit,达到了我们的目的。最后,只需 fast-forward merge 到 master
$ git checkout master
$ git merge dev-new
在别人看来,你就是一个天才开发者,没有出差错地一次实现了 new-feature ,项目的 commit 历史记录显得干净而有意义。
2、fixup
如果我们在编辑器中不用 squash 指令,而使用 fixup 指令,这样改
pick 32618c4 Start developing a feature
fixup 62eed47 Fix something from the previous commit
则结果一样,还是只剩 1 个 commit,但是合并后的提交消息,就只有之前第一个 commit 的消息,第二个的 commit 消息被注释掉了
Start developing a feature
这样也达到了我们的目的,消除了曾经发生过 2 个 commit 的痕迹。在别人看来,这个新功能的分支是按计划一次性开发好的,中途并未发生 “错别字” 之类的意外,简直完美。