Git Merge & Git Rebase

作者: MoZhou | 来源:发表于2016-11-07 01:14 被阅读777次

    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

    merge

    git merge 会生成一个新得合并节点,而rebase不会。使用merge合并, 为分支合并自动识别出最佳的同源合并点。

    git rebase

    如果你想让"mywork"分支历史看起来像没有经过任何合并一样,你也许可以用 git rebase


    rebase
    git checkout mywork
    git rebase origin
    

    这些命令会把你的"mywork"分支里的每个提交(commit)取消掉,并且把它们临时保存为补丁(patch)(这些补丁放到".git/rebase"目录中),然后把"mywork"分支更新 为最新的"origin"分支,最后把保存的这些补丁应用到"mywork"分支上。

    当'mywork'分支更新之后,它会指向这些新创建的提交(commit),而那些老的提交会被丢弃。 如果运行垃圾收集命令(pruning garbage collection), 这些被丢弃的提交就会删除. (git gc)


    运行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

    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分支上生成一个新节点


    git merge 和 git merge --no-ff的区别

    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

    相关文章

      网友评论

      • 有色眼镜的世界:之前好像强哥总结过这样一句话:不同分支用merge,相同分支用rebase
      • 简书扛把子:从来只用merge,rebase没用过,第一次知道区别……

      本文标题:Git Merge & Git Rebase

      本文链接:https://www.haomeiwen.com/subject/rkzguttx.html