zoukankan      html  css  js  c++  java
  • Git:pull --rebase 和 merge --no-ff

    首先是吐嘈

    git pull --rebase

    如果你正在 code review,看到上图(下文将称之为:提交线图)之后,特别是像我这样有某种洁癖的人,是否感觉特别难受?如果是的话,请看下文吧 :)

    为什么

    Git 作为分布式版本控制系统,所有修改操作都是基于本地的,在团队协作过程中,假设你和你的同伴在本地中分别有各自的新提交,而你的同伴先于你 push 了代码到远程分支上,所以你必须先执行 git pull 来获取同伴的提交,然后才能 push 自己的提交到远程分支。而按照 Git 的默认策略,如果远程分支和本地分支之间的提交线图有分叉的话(即不是 fast-forwarded),Git 会执行一次 merge 操作,因此产生一次没意义的提交记录,从而造成了像上图那样的混乱。

    解决

    其实在 pull 操作的时候,,使用 git pull --rebase 选项即可很好地解决上述问题。 加上 --rebase 参数的作用是,提交线图有分叉的话,Git 会 rebase 策略来代替默认的 merge 策略。 使用 rebase 策略有什么好处呢?借用一下 man git-merge 中的图就可以很好地说明清楚了。

    假设提交线图在执行 pull 前是这样的:

                     A---B---C  remotes/origin/master
                    /
               D---E---F---G  master
    

    如果是执行 git pull 后,提交线图会变成这样:

                     A---B---C remotes/origin/master
                    /         
               D---E---F---G---H master
    

    结果多出了 H 这个没必要的提交记录。如果是执行 git pull --rebase 的话,提交线图就会变成这样:

                           remotes/origin/master
                               |
               D---E---A---B---C---F'---G'  master
    

    F G 两个提交通过 rebase 方式重新拼接在 C 之后,多余的分叉去掉了,目的达到。

    小结

    大多数时候,使用 git pull --rebase 是为了使提交线图更好看,从而方便 code review。

    不过,如果你对使用 git 还不是十分熟练的话,我的建议是 git pull --rebase 多练习几次之后再使用,因为 rebase 在 git 中,算得上是『危险行为』

    另外,还需注意的是,使用 git pull --rebase 比直接 pull 容易导致冲突的产生,如果预期冲突比较多的话,建议还是直接 pull。

    merge --no-ff

    上述的 git pull --rebase 策略目的是修整提交线图,使其形成一条直线,而即将要用到的 git merge --no-ff <branch-name> 策略偏偏是反行其道,刻意地弄出提交线图分叉出来。

    假设你在本地准备合并两个分支,而刚好这两个分支是 fast-forwarded 的,那么直接合并后你得到一个直线的提交线图,当然这样没什么坏处,但如果你想更清晰地告诉你同伴:这一系列的提交都是为了实现同一个目的,那么你可以刻意地将这次提交内容弄成一次提交线图分叉。

    执行 git merge --no-ff <branch-name> 的结果大概会是这样的:

    git merge --no-ff

    中间的分叉线路图很清晰的显示这些提交都是为了实现 complete adjusting user domains and tags

    更进一步

    往往我的习惯是,在合并分支之前(假设要在本地将 feature 分支合并到 dev 分支),会先检查 feature 分支是否『部分落后』于远程 dev 分支

    git checkout dev
    git pull # 更新 dev 分支
    git log feature..dev
    

    如果没有输出任何提交信息的话,即表示 feature 对于 dev 分支是 up-to-date 的。如果有输出的话而马上执行了 git merge --no-ff 的话,提交线图会变成这样:

    git-merge

    所以这时在合并前,通常我会先执行:

    git checkout feature
    git rebase dev
    

    这样就可以将 feature 重新拼接到更新了的 dev 之后,然后就可以合并了,最终得到一个干净舒服的提交线图。

    再次提醒:像之前提到的,rebase 是『危险行为』,建议你足够熟悉 git 时才这么做,否则的话是得不偿失啊。

    总结

    使用 git pull --rebasegit merge --no-ff 其实和直接使用 git pull git merge 得到的代码应该是一样。

    使用 git pull --rebase 主要是为是将提交约线图平坦化,而 git merge --no-ff 则是刻意制造分叉。

    一言以蔽之:如果你有点洁癖症状,才考虑用它们吧。

    1.git pull –rebase 理解

    这里写图片描述

    这个命令做了以下内容:
    a.把你 commit 到本地仓库的内容,取出来放到暂存区(stash)(这时你的工作区是干净的)
    b.然后从远端拉取代码到本地,由于工作区是干净的,所以不会有冲突
    c.从暂存区把你之前提交的内容取出来,跟拉下来的代码合并

    所以 rebase 在拉代码前要确保你本地工作区是干净的,如果你本地修改的内容没完全 commit 或者 stash,就会 rebase 失败。

    2.还是要听 git 提示的话,要理智,有什么不清楚的,就输入

    git status
    • 1

    根据人家提示的来,该提交的提交,stash 的 stash。

    3.删除文件后需要 git add -A, 光 git add. 不行,区别如下:

    git add 的几种参数区别

    git add -A 保存所有的修改
    git add . 保存新的添加和修改,但是不包括删除
    git add -u 保存修改和删除,但是不包括新建文件。

    当本地commit一个提交和远端服务器中的代码有冲突(别人也改了相同的文件)时可以在pull 中加 –rebase。加上 rebase 的意思是:

    git pull --rebase
    1. 把本地 repo. 从上次 pull 之后的变更暂存起來
    2. 恢复到上次 pull 时的状态
    3. 合并远端的变更到本地
    4. 最后再合并刚刚暂存下來的本地变更

    合并前:

          D---E master
         /
    A---B---C---F origin/master

    使用 merge 合并后:

          D--------E  
         /          
    A---B---C---F----G   master, origin/master

    如果是 rebase 的方式,就不會有 G 合并点:

    A---B---C---F---D'---E'   master, origin/master

    注意到,其中 D’, E’ 的 commit SHA 序号跟本來 D, E 是不同的,应为算是砍掉重新 commit 了。

    rebase vs. merge

    rebase 跟 merge 类似,出现 conflict 会暂停 rebase 动作,需要你手动修复后,然后才可以继续动作。这也是 rebase 比 merge 复杂一点的地方:merge 如果发生 conflict,你只需要解决冲突一次,然后commit 出去就完成了。而 rebase 的 conflict 可能会发生在上述步骤 4 的每一次重新套用上,所以可能需要解决冲突好几次 (rebase 时所谓的解决冲突,其实是直接修改你之前的变更內容,所以上图中变成 D’ 跟 E’ )。

    配置

    如果想要把 rebase 当做 git pull 的默认值,可以在 .git/config 加上

    [branch "master"]
      remote = origin
      merge = refs/heads/master
      rebase = true

    也可以直接加到 ~/.gitconfig 让所有的 tracked branches 都自动套用这个设定:

    [branch]  
      autosetuprebase = always
  • 相关阅读:
    Java+7入门经典 -1 简介
    优化算法动画演示Alec Radford's animations for optimization algorithms
    如何写科技论文How to write a technical paper
    开始学习深度学习和循环神经网络Some starting points for deep learning and RNNs
    用500行Julia代码开始深度学习之旅 Beginning deep learning with 500 lines of Julia
    用10张图来看机器学习Machine learning in 10 pictures
    ICLR 2013 International Conference on Learning Representations深度学习论文papers
    ICLR 2014 International Conference on Learning Representations深度学习论文papers
    卷积神经网络CNN(Convolutional Neural Networks)没有原理只有实现
    卷积神经网络Convolutional Neural Networks
  • 原文地址:https://www.cnblogs.com/welhzh/p/8028496.html
Copyright © 2011-2022 走看看