Rebases are how changes should pass from the top of hierarchy downwards and merges are how they flow back upwards.
git merge 和 git rebase 都可以用来合并分支。
git merge 分支名 # 将分支合并到当前分支
git rebase 分支名 #也是把分支合并到当前分支
Different
假设你现在基于远程分支"origin",创建一个叫"mywork"的分支。
git checkout -b mywork origin
假设远程分支"origin"已经有了2个提交,如图
现在我们在这个分支做一些修改,然后生成两个提交(commit)。但是与此同时,有些人也在"origin"分支上做了一些修改并且做了提交了,这就意味着"origin"和"mywork"这两个分支各自"前进"了,它们之间产生"分叉"了。
你可以用"git pull"命令把"origin"分支上的修改拉下来并且和你的修改合并,使用git pull时默认是merge,所以结果看起来就像一个新的"合并的提交"(merge commit)
git merge
git merge 会生成一个新得合并节点,而rebase不会。使用merge合并, 为分支合并自动识别出最佳的同源合并点。
git rebase
如果你想让"mywork"分支历史看起来像没有经过任何合并一样,你也许可以用 git rebase
git checkout mywork
git rebase origin
这些命令会把你的"mywork"分支里的每个提交(commit)取消掉,并且把它们临时保存为补丁(patch)(这些补丁放到".git/rebase"目录中),然后把"mywork"分支更新 为最新的"origin"分支,最后把保存的这些补丁应用到"mywork"分支上。
当'mywork'分支更新之后,它会指向这些新创建的提交(commit),而那些老的提交会被丢弃。 如果运行垃圾收集命令(pruning garbage collection), 这些被丢弃的提交就会删除. (git gc)
Solve Conflicts
在rebase的过程中出现冲突,git会暂停rebase并让你去解决冲突,在解决完冲突后,用"git add"命令去更新这些内容的索引(index), 然后,你无需执行 git-commit,只要执行:
git rebase --continue #这样git会继续应用(apply)余下的补丁
在任何时候,你可以用--abort参数来终止rebase的行动,并且"mywork" 分支会回到rebase开始前的状态。
git rebase --abort
但是rebase会基于每次commit都解决一次冲突,所以如果当别人小步提交的话,解决冲突起来会特别酸爽,不断重复直到冲突解决。
而merge 会为分支合并自动识别出最佳的同源合并点。
log history
我们假设C3提交于9:00AM,C5提交于10:00AM,C4提交于11:00AM,C6提交于12:00AM
- 对于使用git rebase来合并所看到的commit的顺序(从新到旧)是:C6‘,C5',C4,C3,C2,C1
因为C6'提交只是C6提交的克隆,C5'提交只是C5提交的克隆,
从用户的角度看使用git rebase来合并后所看到的commit的顺序(从新到旧)是:C6,C5,C4,C3,C2,C1 - 对于使用git merge来合并所看到的commit的顺序(从新到旧)是:C7 ,C6,C4,C5,C3,C2,C1
对于两个分支而言,rebase和merge没有区别,但是rebase更干净,因为log hisitory是线性的,但commit不一定按日期先后排,而是local commit总在后面。merge之后history变得比较复杂,但是commit按日期排序。所以当我们使用git log来参看commit时,merge 和 rebase 的commit的顺序也有所不同。
个人把merge理解为显性的处理冲突,rebase是隐性的处理冲突。
Pay attention
在merge的时候,有时并没有产生一个commit。可是不是说merge时会产生一个merge commit吗?
注意:只有在冲突的时候,解决完冲突才会自动产生一个commit。
如果想在没有冲突的情况下也自动生成一个commit,记录此次合并就可以用:git merge --no-ff命令,
git merge 和 git merge --no-ff的区别
默认情况下,git执行"快进式合并"(fast-farward merge),会直接将master分支指向dev分支。使用--no-ff参数后,会执行正常合并,在master分支上生成一个新节点
Question
需求:想保证每天分支上代码和master上一致且维护同一分支
解决方案:
1.在分支上merge master ,commit 顺序不会出问题,log history 会很复杂,不利于review 代码
2.在分支上rebase master,log history 会很清晰,但是遇到冲突必须挨个commit 解决,同时commit的顺序会错乱
尝试解决给出的方案
在分支上merge master , 然后利用github 的 pull request 来review 代码
走过的坑
假设有master,friends,delete-box 三个分支,其中friends 基于master,delete-box基于friends,需要在delete-box上rebase master 的时候,不能直接在delete-box上rebase master,这样会导致master 的代码跑到delete-box 的‘头上’,分支提交顺序错乱,正确做法是先在friends上rebase master,然后去delete-box 分支上rebase friends
未完...
至此...还是没有找到一个很好的方式来保证在维护同一分支的前提下,每天分支上的代码和master保持同步,也许可以把每次把分支merge回master之后新拉分支的步骤用脚本封装一层...做到所谓的自动化...
参考资料
http://gitbook.liuhui998.com/4_2.html
https://www.visualstudio.com/en-us/docs/git/pull-requests