GIT系列四:在push之前对本地commit进行整理


在系列三中描述了commit消息的规范,但在实际操作中很难时刻做到那么严格的
控制,尤其是在本地做一些实验性的工作的时候。
但是如果需要push到远端去,则就必须保证commit消息的规范和commit的独立性。
因此就有了这样一个需求:在执行git push之前对本地的commit日志进行整理。


一个好习惯

本文讨论的一个重要前提是在执行git push之前,对于在本地还未提交commit进行整理!!!
本文讨论的一个重要前提是在执行git push之前,对于在本地还未提交commit进行整理!!!
本文讨论的一个重要前提是在执行git push之前,对于在本地还未提交commit进行整理!!!
重要的事情说三遍。
那为什么在git push之后不宜使用这些命令呢?
主要是因为本文设计到的命令都会重新提交commit,尽管有commit msg有时候不会变,但commit对应的SHA1哈希值会被改变。如果是已经push了的commit被改变了SHA1,则会造成比较严重的混乱。

所以这里推荐一个好习惯

保持重要分支(如master)与远端的同步,开发一定要新开分支。  

这样一来就能够快速的识别那些属于还未push的本地commit。
接下来就详细介绍整理本地commit的几个重要命令:amemd, reset和rebase


amend

amend会使用一个新的commit去替换最近的一次commit。
amend适用于:
a. 在提交commit后,才发现漏掉了某些修改,文件的情况
b. 修正一些typo

// 先进行一些修改,然后使用--amend选项重新提交一次commit
# git commit -a --amend             // 弹出编辑窗口,重新提交新commit
# git commit -a --amend -C HEAD     // 直接上一个commit消息

reset

amend仅能替换最近一次commit,功能不够强大。比如想要快速的将working tree的修改和最近的两次commit合并得到一个新的commit则需要用到reset啦。
reset适用于:
a. 需要修改多个commit的情况,但也受限于修改从HEAD~开始连续的多个commit
b. 完全的删除前几个commit

# git reset --soft HEAD~2       // 删掉前两个commit,并保留文件更改
# git reset --hard HEAD~2       // 删掉前两个commit,并删除文件更改

另外,万一如果需要修改的commit已经push出去了(是否应该避免?),又最好不要reset,那么该怎么做呢?
那就需要使用revert命令,revert命令会接着重新提交一个新的commit,用以回滚上一个commit的修改。有点负负得正的感觉。


rebase

reset受限于只能将从HEAD~开始的连续多个commit删除或(人工)合并。也还是不够强大。比如想要合并HEAD~2到HEAD~3的commit,删除HEAD~4的commit,则需要使用到rebase命令。
那到底什么是rebase呢?

rebase的核心含义就是重新设定基准!  

什么意思呢?
git对于commit的管理可以理解为一个有向无环图,你的某个branch一定是从另一个分支的某个节点开始分离出来的。比如下面情况下的dev分支的base就可以理解是B节点。
更专业的说法应该是:B是E(dev)和C(master)的最小公共祖先。

A -- B -- C   <= master
      \
       D -- E <= dev

rebase可以用于干什么?
a. 仅修改某些commit的msg
b. 变更commit顺序
c. 删掉某一个commit
d. 修改某一个commit对应的内容

rebase的基本命令就是git rebase -i HEAD~n啦,具体的操作流程在执行的时候都有详细的引导,这里就不再重复。想了解细节的推荐看这篇tutorial — 其实更推荐找个git仓库实践一把。

下面来介绍一下怎样处理常见的rebas冲突,至于rebase进阶用法,将在后续的wiki上介绍。

解决rebase冲突

当发生rebase无法顺利进行的时候,有以下几种选择:

// a. 放弃rebase  
# git rebase --abort
// b. 忽视冲突  -- 一般很少用
# git rebase --skip

// c. 解决冲突
# git status                // 查看冲突类型,常见的是编辑冲突
# vim conflict-file.md      // 编辑冲突文件
# git add conflict-file.md  // 重新添加冲突文件
# git rebase --continue     // 继续rebase

参考资料

rolling back changes with revert
Git 版本控制系統3 - 還沒 push 前可以做的事