GIT PULL, MERGE - FETCH, REBASE, RESET, REVERT
About:
以前自己单打独斗的时候,使用git主要是记录版本,很少用git来协作,协作也不过是两个人的小打小闹,一直在pull, 或者fetch merge,大家也都在修改master分支,没有明确的管理,进了新公司,需要比较严格的code review,主分支的管理都是确定的,这时候用rebase,reset,revert代替pull, fetch , merge之类的就好的多啦。
Why:
为什么要从pull和merge迁移到rebase,reset,revert呢?
我们看看如下几个场景中直接merge会产生什么问题:
一.
协作人数:两人,A和B
项目权限:所有人对master可写
分支状况: A:develop-A, B:develop-B
A 产生了 commitA1, B产生了commitB1,
1.因为B觉得自己的更改是有效的,所以B首先提交了一次自己的更改给master, 此时,A的develop分支落后于主分支,所以A对于B提交的commitB1进行了一次pull(pull = fetch + merge) ,commit 记录里多了一次Merge,此时A将自己的分支develop -A 直接push到master分支,B如果再要更新Master,就必须先运行一起pull,将A的提交中包含Merge的commit合并到自己的本地分支,这样又会多产生一次分支。
如此推算……n次之后,整个项目的master分支产生了诸多难以维护的“Merge”提交,因为两个人始终再Merge对方的提交。
—————-
从第一个例子我们可以看出,只有一个人管理Master分支(使用pull的模式)的情况下,对于主分支的管理将会非常混乱,所以这种时候使用pull进行管理将会非常麻烦,而且每次产生冲突,则需要N个人同时处理冲突,失去了协作管理的意义,git也不再是分布式,变成了中心式。
二.
协作人数:两人,A和B
项目权限:A对Master可以写
分支状况: A:develop-A, B:develop-B
此时,如果master产生了两个bug,而两个人需要分开开发,两个人分别领先于主分支,创建了两个“补丁” BugFixA1和BugFixB1。
此时,为了使两个补丁单独可以被回退,需要使整个历史变成单条线性前进,
master---->BugFixA1---->BugFixB1
而不是
develop-A-->BugFixA1--|
|
master-------------->Merge------->NewMaster
|
develop-B-->BugFixB1--|
这个时候就需要是用rebase了
关于具体怎么用rebase修改分支,参考 :http://gitbook.liuhui998.com/4_2.html
三.
开发完成后, master分支有如下的commit
+--------+ +---------+ +---------+ +----------+
| | | | | | | |
| c1 +--------> c2 +-------> c3 +------> c3 |
| | | | | | | |
+--------+ +---------+ +---------+ +----------+
1.需要修改一个commit 2,而commit2位于整个版本历史的中间位置
2.最后一次修改现在不想要了,想要删除这次提交
对于场景1,只能用rebase
范例
git rebase -i HEAD~3 #修改最后三次提交
对于场景2,既能使用rebase, 又能使用reset。
详细内容,参考
Git-重写历史 http://git-scm.com/book/zh/v1/Git-%E5%B7%A5%E5%85%B7-%E9%87%8D%E5%86%99%E5%8E%86%E5%8F%B2
Git-revert和reset http://my.oschina.net/MinGKai/blog/144932
git cherry-pick. 如何把已经提交的commit, 从一个分支放到另一个分支 http://sg552.iteye.com/blog/1300713