Git Idioms 2

Posted on | 1322 words | ~3 mins
Git

上一篇文章讲了git revertgit reset。这一篇在记录一下git rebase的简单用法。有很多个场景可以使用git rebase来更好的提交代码。

场景1:推送到远程仓库前清理commit

为了实现一个功能,向本地代码库commit了太多次。希望将多次commit合并为一次,避免合并到主仓库后,污染主仓库的commit列表。操作前后,commit history状态如下图:

git_rebase_scenario_1

具体操作过程为如下。可以看到最后2个commit都是有关YUV的内容,但却分成了2个commit。

1$ git log --oneline --graph
23bffa83 (HEAD -> master) more details for YUV
33e4b863 add YUV
4b6a1d4a add tongji and new article
5e62d9b7 add package import article
613f7895 add my own theme

如果我们希望将最后2个commit合并成1个commit,可以执行git rebase -i b6a1d4a。请注意-i之后跟着的commit id是git log中第一个不需要加入rebase的commit id。如果执行命令后,遇到如下提示。说明本地有未提交的修改,请先git stash将修改暂存。

1$ git rebase -i b6a1d4a
2Cannot rebase: Your index contains uncommitted changes.
3Please commit or stash them.

完成stash之后,重新执行git rebase -i b6a1d4a,则会进入文本编辑器用于选择哪些commit需要保留,哪些需要压缩

rebase_2

使用p表示该commit需要保留。使用s表示该commit要压缩到前一个保留的commit中。故至少要有一个commit被标记为p;且第一个commit(最老的那个commit)必须是p。

rebase_3

保存文件后,会进入commit message修改界面。

rebase_4

需要给rebase后的commit填写一个新的commit message。

rebase_5

如果rebase过程中出现问题,可以执行git rebase --edit-todo修改rebase中的错误。修改完毕执行git rebase --continue继续完成rebase。完成后执行git log --oneline --graph,可以看到b6a1d4acommit之前的2个commit被压缩为一个新commit。

1$ git log --oneline --graph
2689e189 (HEAD -> master) add YUV
3b6a1d4a add tongji and new article
4e62d9b7 add package import article
513f7895 add my own theme

场景2:两个分支间的合并

有时候,我们新开分支feature进行新功能开发。然后突然接到紧急修复bug的要求,会切换回master分支进行修复开发。修复开发结束后,要将分支feature合并到master中。这个时候因为两个分支的commit历史并不一致,我们需要进行合并。有两个方法

当前commit历史状态

git_rebase_scenario_2_1

方法1:通过git merge操作。完成合并后,在commit历史上会多出一个commit,包含commit 4和commit 5合并后的代码。

git_rebase_scenario_2_2

方法2:通过git rebase操作。在feature分支上,执行git rebase masterfeature分支上的改动Replay到master分支上

git_rebase_scenario_2_3

最后只需切换回master分支,执行git merge feature即可。可以看到,用第二种方法进行合并,commit历史上更加干净清晰。

场景3:两个仓库间的合并

当多人工作在同一个远程仓库,同一分支时,我们向远程仓库提交本地的commit,可能由于本地仓库和远程仓库(其他人在我们最后一次pull之后,提交了代码)的提交历史不一致而失败。这时也可以使用git rebase来完成提交历史的合并。本质上这个场景和上一个场景相同,只不过是跨两个仓库完成。