当我们开发一个功能,不是一时半会可以完成的时候,为了保护代码不丢失,通常会把这次的修改先 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界面,类似这样:
注意:观察头部的commit清单,确保你要保留的那条commit出现在内。一切顺利的话,它会出现在顶部第一条。
3. 修改 pick
为 squash
vi指令i
进入编辑模式,修改你不想保留的commit记录前的 pick
为 squash
(或者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!