首先是吐嘈

如果你正在 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> 的结果大概会是这样的:

中间的分叉线路图很清晰的显示这些提交都是为了实现 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 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

Git:pull --rebase 和 merge --no-ff的更多相关文章

  1. 聊下git pull --rebase

    有一种场景是经常发生的. 大家都基于develop拉出分支进行并行开发,这里的分支可能是多到数十个.然后彼此在进行自己的逻辑编写,时间可能需要几天或者几周.在这期间你可能需要时不时的需要pull下远程 ...

  2. git pull --rebase

    git reset --hard orgin/master $ git push bit 1.8-subchannels To git@bitbucket.org:cms.git ! [rejecte ...

  3. Difference between git pull and git pull --rebase

    个人博客地址:  http://www.iwangzheng.com/ 推荐一本非常好的书 :<Pro Git>  http://iissnan.com/progit/ 构造干净的 Git ...

  4. 对比git pull和git pull --rebase

    1.使用下面的关系区别这两个操作:git pull = git fetch + git mergegit pull --rebase = git fetch + git rebase 2 一.基本 g ...

  5. git pull以及git pull --rebase

    git pull的作用是将远程库中的更改代码合并到当前分支中,默认为:git fetch + git merge git fetch 的作用就相当于是从远程库中获取最新版本到本地分支,不会自动进行gi ...

  6. 简单对比git pull和git pull --rebase的使用

    使用下面的关系区别这两个操作:git pull = git fetch + git mergegit pull --rebase = git fetch + git rebase 现在来看看git m ...

  7. 【Git】git pull和git pull --rebase的使用

    git pull = git fetch + git mergegit pull --rebase = git fetch + git rebase 现在来看看git merge和git rebase ...

  8. git fetch 、git pull 与 git pull --rebase

    1. git fetch 与 git pull 都是从远程拉取代码到本地,git fetch只是拉取到本地,git pull不仅拉取到本地还merge到本地分支中.所以git pull是git fet ...

  9. git pull --rebase的使用

    原文:http://www.cnblogs.com/kevingrace/p/5896706.html 使用下面的关系区别这两个操作:git pull = git fetch + git mergeg ...

随机推荐

  1. 【angularjs基础】ng-repeat嵌套循环报错angular.min.js:89 Error: [ngRepeat:dupes]

    再写嵌套循环的时候,提示一个错误 angular.min.js: Error: [ngRepeat:dupes] 代码如下 <table class="GridViewTable mt ...

  2. linux prefix

    指定安装路径不指定prefix,则可执行文件默认放在/usr /local/bin,库文件默认放在/usr/local/lib,配置文件默认放在/usr/local/etc.其它的资源文件放在/usr ...

  3. python基础---->python的使用(七)

    这里记录python关于io.装饰器和序列化的一些知识.面对大河我无限惭愧,我年华虚度,空有一身疲倦,和所有以梦为马的诗人一样,岁月易逝 一滴不剩. python的一些知识 一.python中的装饰器 ...

  4. Qt编写输入法终极版V2018

    输入法是很多Qt+嵌入式linux开发的同学的痛,自从5.7自带了输入法后,这个痛终于缓解了不少,不过还有大量的嵌入式linux程序停留在qt4时代,为此特意选择了QWidget来写这个输入法,为了兼 ...

  5. Sencha Touch 实战开发培训 视频教程 第二期 第三节

    2014.4.11晚上8:10分开课. 本节课耗时一小时以上. 本期培训一共八节,前两节免费,后面的课程需要付费才可以观看. 本节内容:             本地储存.扩展按钮控件.微博分享 实现 ...

  6. FTP协议的粗浅学习--利用wireshark抓包分析相关tcp连接

    一.为什么写这个 昨天遇到个ftp相关的问题,关于ftp匿名访问的.花费了大量的脑细胞后,终于搞定了服务端的配置,现在客户端可以像下图一样,直接在浏览器输入url,即可直接访问. 期间不会弹出输入用户 ...

  7. 查看JVM使用的默认的垃圾收集器

    一.查看步骤 cmd执行命令: java -XX:+PrintCommandLineFlags -version 输出如下(举例): 针对上述的-XX:UseParallelGC,这边我们引用< ...

  8. C语言位操作--不用中间变量交换两数值

    1.使用加法与减法交换两数值: #define SWAP(a, b) ((&(a) == &(b)) || \ (((a) -= (b)), ((b) += (a)), ((a) = ...

  9. 把握这两点,抢占下一个电商风口|2016最新中国电商App排名&研究报告

    序言 电商,是随着中国互联网经济的持续发展所成长起来的.淘宝.京东这些电商从交易额和影响力上看都位列中国最为成功.最具话题性的互联网企业之中.尽管近几年中国经济有所放缓,但中国消费市场的增长速度仍有望 ...

  10. Rails secret token bug

    ArgumentError (A secret is required to generate an integrity hash for cookie session data. Use confi ...