rebase

在 Git 中整合来自不同分支的修改主要有两种方法:merge 以及 rebase。 在本节中我们将学习什么是“rebase”,怎样使用“rebase”,并将展示该操作的惊艳之处,以及指出在何种情况下你应避免使用它。

rebase的基本操作

整合分支最容易的方法是 merge 命令。 它会把两个分支的最新快照(C3 和 C4)以及二者最近的共同祖先(C2)进行三方merge,merge的结果是生成一个新的快照(并提交)。

还有一种方法:你可以提取在 C4 中引入的补丁和修改,然后在 C3 的基础上应用一次。 在 Git 中,这种操作就叫做 rebase。 你可以使用 rebase 命令将提交到某一分支上的所有修改都移至另一分支上,就好像“重新播放”一样。

在上面这个例子中,运行:

$ git checkout experiment
$ git rebase master
First, rewindingheadto replay your work on top of it...
Applying: added staged command

它的原理是首先找到这两个分支(即当前分支 experiment、rebase操作的目标基底分支 master)的最近共同祖先 C2,然后对比当前分支相对于该祖先的历次提交,提取相应的修改并存为临时文件,然后将当前分支指向目标基底 C3, 最后以此将之前另存为临时文件的修改依序应用。

现在回到 master 分支,进行一次快进merge。

$ git checkout master
$ git merge experiment

此时,C4' 指向的快照就和上面使用 merge 命令的例子中 C5 指向的快照一模一样了。 这两种整合方法的最终结果没有任何区别,但是rebase使得提交历史更加整洁。 你在查看一个经过rebase的分支的历史记录时会发现,尽管实际的开发工作是并行的,但它们看上去就像是串行的一样,提交历史是一条直线没有分叉。

一般我们这样做的目的是为了确保在向远程分支推送时能保持提交历史的整洁——例如向某个其他人维护的项目贡献代码时。 在这种情况下,你首先在自己的分支里进行开发,当开发完成时你需要先将你的代码rebase到 origin/master 上,然后再向主项目提交修改。 这样的话,该项目的维护者就不再需要进行整合工作,只需要快进merge便可。

请注意,无论是通过rebase,还是通过三方merge,整合的最终结果所指向的快照始终是一样的,只不过提交历史不同罢了。 rebase是将一系列提交按照原有次序依次应用到另一分支上,而merge是把最终结果合在一起。

更有趣的rebase例子

在对两个分支进行rebase时,所生成的“重放”并不一定要在目标分支上应用,你也可以指定另外的一个分支进行应用。 你创建了一个特性分支 server,为服务端添加了一些功能,提交了 C3 和 C4。 然后从 C3 上创建了特性分支 client,为客户端添加了一些功能,提交了 C8 和 C9。 最后,你回到 server 分支,又提交了 C10

假设你希望将 client 中的修改合并到主分支并发布,但暂时并不想merge server 中的修改,因为它们还需要经过更全面的测试。 这时,你就可以使用 git rebase 命令的 --onto 选项,选中在 client 分支里但不在 server 分支里的修改(即 C8 和 C9),将它们在 master 分支上重放:

$ git rebase --onto master server client

以上命令的意思是:“取出 client 分支,找出处于 client 分支和 server 分支的共同祖先之后的修改,然后把它们在 master 分支上重放一遍”。 这理解起来有一点复杂,不过效果非常酷。

现在可以快进merge master 分支了。

$ git checkout master
$ git merge client

接下来你决定将 server 分支中的修改也整合进来。 使用 git rebase [basebranch] [topicbranch] 命令可以直接将特性分支(即本例中的 server)rebase到目标分支(即 master)上。这样做能省去你先切换到 server 分支,再对其执行rebase命令的多个步骤。

$ git rebase master server

然后就可以快进merge主分支 master 了:

$ git checkout master
$ git merge server

至此,client 和 server 分支中的修改都已经整合到主分支里了,你可以删除这两个分支,最终提交历史会变成图 最终的提交历史 中的样子:

$ git branch -d client
$ git branch-d server

rebase的风险

呃,奇妙的rebase也并非完美无缺,要用它得遵守一条准则:

Do not rebase commits that exist outside your repository.

如果你遵循这条金科玉律,就不会出差错。

rebase操作的实质是丢弃一些现有的提交,然后相应地新建一些内容一样但实际上不同的提交。 如果你已经将提交推送至某个仓库,而其他人也已经从该仓库拉取提交并进行了后续工作,此时,如果你用 git rebase 命令重新整理了提交并再次推送,你的同伴因此将不得不再次将他们手头的工作与你的提交进行整合,如果接下来你还要拉取并整合他们修改过的提交,事情就会变得一团糟。

让我们来看一个在公开的仓库上执行rebase操作所带来的问题。 假设你从一个中央服务器克隆然后在它的基础上进行了一些开发。 你的提交历史如图所示:

然后,某人又向中央服务器提交了一些修改,其中还包括一次merge。 你抓取了这些在远程分支上的修改,并将其merge到你本地的开发分支,然后你的提交历史就会变成这样:

接下来,这个人又决定把merge操作回滚,改用rebase;继而又用 git push --force 命令覆盖了服务器上的提交历史。 之后你从服务器抓取更新,会发现多出来一些新的提交。

结果就是你们两人的处境都十分尴尬。 如果你执行 git pull 命令,你将merge来自两条提交历史的内容,生成一个新的merge提交,最终仓库会如图所示:

此时如果你执行 git log 命令,你会发现有两个提交的作者、日期、日志居然是一样的,这会令人感到混乱。 此外,如果你将这一堆又推送到服务器上,你实际上是将那些已经被rebase抛弃的提交又找了回来,这会令人感到更加混乱。 很明显对方并不想在提交历史中看到 C4 和 C6,因为之前就是他把这两个提交通过rebase丢弃的。

如果你 真的 遭遇了类似的处境,Git 还有一些高级魔法可以帮到你。 参考 https://git-scm.com/book/zh/v2/Git-%E5%88%86%E6%94%AF-%E5%8F%98%E5%9F%BA

rebase vs. merge

至此,你已在实战中学习了rebase和merge的用法,你一定会想问,到底哪种方式更好。 在回答这个问题之前,让我们退后一步,想讨论一下提交历史到底意味着什么。

有一种观点认为,仓库的提交历史即是 记录实际发生过什么。 它是针对历史的文档,本身就有价值,不能乱改。 从这个角度看来,改变提交历史是一种亵渎,你使用_谎言_掩盖了实际发生过的事情。 如果由merge产生的提交历史是一团糟怎么办? 既然事实就是如此,那么这些痕迹就应该被保留下来,让后人能够查阅。

另一种观点则正好相反,他们认为提交历史是 项目过程中发生的事。 没人会出版一本书的第一版草稿,软件维护手册也是需要反复修订才能方便使用。 持这一观点的人会使用 rebase 及 filter-branch 等工具来编写故事,怎么方便后来的读者就怎么写。

现在,让我们回到之前的问题上来,到底merge还是rebase好?希望你能明白,这并没有一个简单的答案。 Git 是一个非常强大的工具,它允许你对提交历史做许多事情,但每个团队、每个项目对此的需求并不相同。 既然你已经分别学习了两者的用法,相信你能够根据实际情况作出明智的选择。

总的原则是,只对尚未推送或分享给别人的本地修改执行rebase操作清理历史,从不对已推送至别处的提交执行rebase操作,这样,你才能享受到两种方式带来的便利。

转载于:https://www.cnblogs.com/chenny7/p/7644318.html

git rebase 的使用相关推荐

  1. git rebase 和 git merger

    & git merge 在上图中,每一个绿框均代表一个commit.除了c1,每一个commit都有一条有向边指向它在当前branch当中的上一个commit. 图中的项目,在c2之后就开了另 ...

  2. 合并代码还在用git merge吗?我们都用git rebase!

    欢迎关注方志朋的博客,回复"666"获面试宝典 git merge 和 git rebase的区别 目的都是将一个分支的 commit 合并到到另外一个分支中去. git merg ...

  3. git merge 和 git rebase详解

    git merge 和 git rebase 都是用来合并两个分支的. git merge b   #把b分支合并到当前分支 git rebase b   #把b分支合并到当前分支 --------- ...

  4. 你什么时候使用git rebase而不是git merge?

    什么时候建议使用git rebase与git merge ? 成功改造后我还需要合并吗? #1楼 在合并/ rebase之前: A <- B <- C [master] ^\D <- ...

  5. git rebase用法

    开发任务分叉到两个不同分支,又各自提交了更新 整合分支最容易的方法是 merge 命令. 它会把两个分支的最新快照(C3 和 C4)以及二者最近的共同祖先(C2)进行三方合并,合并的结果是生成一个新的 ...

  6. git rebase和git merge的用法

    http://softlab.sdut.edu.cn/blog/subaochen/2016/01/git-rebase%E5%92%8Cgit-merge%E7%9A%84%E7%94%A8%E6% ...

  7. git Rebase 代替合并

    虽然合并(merge)操作可以用来简单和方便地整合改动,但是它却不是唯一的方法."Rebase" 就是另一种替代手段. 注释 虽然 rebase 相对于我们已知的整合操作来说有着比 ...

  8. git Rebase 变基 教程

    在上一节我们看到了,多人在同一个分支上协作时,很容易出现冲突.即使没有冲突,后push的童鞋不得不先pull,在本地合并,然后才能push成功. 每次合并再push后,分支变成了这样: $ git l ...

  9. 用git rebase合并

    合并issue3分支的时候,使用rebase可以使提交的历史记录显得更简洁. 现在暂时取消刚才的合并. $ git reset --hard HEAD~ 切换到issue3分支后,对master执行r ...

  10. git rebase -i 修改提交

    教程3 改写提交! 6. 用rebase -i 修改提交 为了节省时间,这个教程使用现有的历史记录作为本地数据库. 从这里下载 我们进入stepup-tutorial/tutorial6目录.本地端的 ...

最新文章

  1. 吊打一切的YOLOv4的tricks汇总!
  2. 【必懂】C语言水仙花数题解
  3. html让时间只展示年月日_如何用html写代码,使得在网页上显示当前的时间和日期...
  4. audio 上一首 下一首 自定义样式_被 iPhone 吹爆的最香功能,安卓也终于安排上了...
  5. python的read函数调用报错_从零开始学Python(七):文件存储I/O流和异常捕捉
  6. 通过nginx反向代理解决跨域
  7. DXUT实战3:HLSL(withEffect)+D3D9+DXUT(june_2010) . .
  8. 《R in Action》读书笔记(3) 数据变换
  9. The most impressed error
  10. 阿里云 centos7 tomcat 启动巨慢的解决方法(几分钟)
  11. QTP的那些事--weblist中相关的内容获取
  12. 论文写作 之 Related work
  13. Qt widget事件传递顺序以及监听特定控件是否接收某个事件
  14. I/O 设备模型-3
  15. DataGridView 单击选中一整行,只能单选,不能选择多行,只能选择一行
  16. 低版本android无法连接iPhone手机个人热点问题
  17. 数据集FFHQ和LSUN介绍
  18. 关于 android 虚拟机显示在了界面里面,怎么把模拟器放到到android studio窗口外面这件事
  19. (转)对冲基金:AQR合伙人:“沉闷”股票回报更好
  20. 淘宝京东拼多多优惠券,买东西省钱的秘密

热门文章

  1. MongoDB C#:如何将包含DateTime的JSON反序列化为正确的BsonDocument DateTime值
  2. java虚拟机相同吗_Java虚拟机是否真的是与VMWare或Parallels文件相同的虚拟机?
  3. java隔一个逗号读入文件_将逗号分隔的文本文件读入HashMap,其中文件在多行Java中具有相同的键...
  4. 创建一个delete触发器_基于 Django 信号机制实现类似触发器的效果
  5. 计算机课程中lnA怎么打,《计算机基础》考试模拟题(含答案)
  6. 螺旋进刀非法平面选择_进刀方法、刀片类型、术语...螺纹加工重点知识你都知道吗?...
  7. ionic4 组件的使用(一)
  8. java局部变量的描述正确的是_【Java入门课|这才是Java局部变量的正确使用方法,你真的会用这些吗】- 环球网校...
  9. MySQL Workbench Failed to Connect to MySQL at 127.0.0.1:3306 with user root Bad handshake
  10. c语言 存储,c语言存储类