git进阶之合并多次commit

当我们开发一个功能,不是一时半会可以完成的时候,为了保护代码不丢失,通常会把这次的修改先 commit,等到这个功能完全做好,再 push。不过这样一来,就会有很多零碎的 commit 记录,这会使远程的提交历史显得杂乱。

必要的时候,我们需要将这些相近的 commit 合并为一个 commit 再 push。当然了,如果你想合并远程的 commit 也是可以的,但请一定要提前跟团队里的其他人说一声,免得有人也在跟你做同样的事情,导致没必要的代码冲突(所以合并 commit 尽量在 push 前)。

操作步骤:

1. git log 查看commit节点id

1
git log --oneline

参数--oneline可以让你的commit log在一行输出,比较紧凑,coimmit id也以简短的位数展示,比较便于查看。
找到你要保留的那条commit的上一条commit(这样可以保证你要保留的那一条commit出现在pick清单的顶部),复制这条commit的id。

2. git rebase 变基

1
git rebase -i [commit_id]

[commit_id]就放你在第1步复制的那个值。
然后就会进入rebase界面,类似这样:

git-rebase.jpg

注意:观察头部的commit清单,确保你要保留的那条commit出现在内。一切顺利的话,它会出现在顶部第一条。

3. 修改 picksquash

vi指令i进入编辑模式,修改你不想保留的commit记录前的 picksquash(或者s)。git 会把前面为 squash的commit记录与它的上一条记录合并为一条。

注意要确保第一条为 pick,因为squash的作用是把commit合并到上一个提交,所以必须保证至少第一个提交被pick

如果你不小心把所有的pick都改为了s,然后保存退出,会收到一个错误提示:cannot 'squash' without a previous commit。不要怕,根据它的下一个提示操作就可以了:

1
2
You can fix this with 'git rebase --edit-todo' and then run 'git rebase --continue'.
Or you can abort the rebase with 'git rebase --abort'.

尽管它提示了2种方法来处理,我还是推荐你使用git rebase --abort,然后重来一次rebase,这样最稳妥。

4. 处理合并后的commit message

如果第3步顺利的话,esc之后,:进入指令模式,输入vi指令wq,保存并退出vi界面,然后会进入另一个vi界面,在这里它会把你合并的这些commit的日志列出来,便于你编辑。
同样使用vi指令i进入编辑模式,编辑完后,esc+:+wq回车退出。然后会出现Successfully rebased and updated refs/heads/xxx.说明commit合并成功了。

5. 如果修改的是远程的commit,则强制push一把

1
git push -f

如果你还没push,只是处理本地的commit,则不需要这一步。否则,就需要把这次的rebase强制覆盖远程分支。

done!

现在可以git log --oneline看下,是不是commit数量已经减少了,并且你指定的那些commit都合并为了一条,message就是你在第4步处理的内容。

GoodLuck!