尽管 merging 和 rebasing 在 git 中类似时,但他们提供不同的性能。为了让你的历史尽可能的洁净和残缺,你应该晓得以下几点。
git rebase
命令已 神奇的 Git voodoo 而闻名,初学者应该远离它,但它实际上能够让开发团队在应用时更加轻松。在本章中,咱们将 把 git rebase
和与之有关联的 git merge
命令相比拟,并在典型的 Git 工作流 中从新定位,辨认其所有潜在的机会。
概述
首先要明确对于 git rebase
的事件是它像 git merge
一样解决雷同的问题。git rebase 和 git merge 一样都是被设计用于从一个分支获取并合并到以后分支,然而他们采取不同的工作形式。
考虑一下,当你开始在 一个专用的分支上开发新个性,与此同时另一个团队成员用新的提交来更新了 master
分支时,会产生什么呢?这会导致分叉的历史记录,对于这个问题,应用 Git 作为协同工具的任何人来说都应该很相熟。
当初,假如你在工作时在 master
上的新提交与新个性相干。为了将新提交合并到你的 feature
分支上,你有两种抉择:merging 或者 rebasing。
Merge 选项
最简略的选项是应用以下命令将 master
分支合并到 feature
分支:
git checkout feature
git merge master
或者,你能够简化成一句:
git merge master feature
这将在 feature
分支上创立一个新“合并提交”,并把两个分支的历史分割在一起。分支构造显示如下:
Merging 之所以好是因为它是一个不可逆的操作。在任何状况下,现有分支不能被更改。这防止了所有 rebasing 的潜在陷阱(详见下文)。
另一方面,这也意味着每次须要合并上游更改时,feature
分支都将有一个额定的 merge 提交产生。如果 master
十分沉闷,这可能毁坏你全副的 feature 分支的历史。应用高级的 git log
选项来减缓这个问题是有可能的,也让其余开发人员很难了解这个我的项目的历史记录。
Rebase 选项
作为 merging 的一个替代品,你能够应用以下命令将 feature
分支合并到 master
分支:
git checkout feature
git rebase master
这将整个 feature
分支从 master
分支的顶端开始,无效地将所有新的提交合并到主分支中。然而,并不是应用合并提交,而是通过为每个在原始分支上的提交创立全新的提交来重写我的项目历史。
rebasing 最次要的好处是你将取得一个非常洁净整洁的我的项目历史。首先,它通过 git merge
排除多余的 merge 提交需要;其次,正如你在上图所看到的那样,rebasing 也会产生完满线性的我的项目历史记录—你能够顺着 feature
始终到我的项目的起始地位而没有任何分支。能够不便的应用 git log
,git bisect
和 gitk
追踪提交记录。
然而,对于新的提交历史有两点须要衡量:安全性和可追溯性。如果你不遵循 Rebasing 的黄金法令,为你的合作工作流重写我的项目历史可能会成为潜在的劫难。另外,不重要的是,rebasing 会失落合并提交所提供的上下文—你不能看到何时合并到 feature 分支中的上游变动。
交互式的 Rebasing
当他们挪动到新的分支上,交互式合并给你机会来批改提交。自从它提供齐全管制整个分支的提交历史之后,它比主动合并更弱小。具备代表性的,在合并一个 feature 分支到 master
时,它是被用来革除谬误的历史。
要开始一个交互式的重基会话,请将 i
选项传递给 git rebase
命令:
git checkout feature
git rebase -i master
这将关上一个文本编辑器列出所有要被挪动的提交:
pick 33d5b7a Message for commit #1
pick 9480b3d Message for commit #2
pick 5c67e61 Message for commit #3
此列表精确定义了执行 rebase 后分支的外观。通过扭转 pick
命令或调整条目程序来扭转分支的提交历史,你能够让分支看起来像任何你想要的样子。举例说,如果第二次提交是为了修复第一次提交中的一个小问题,你能够应用 fixup
命令把他们简化成一个简略的命令:
pick 33d5b7a Message for commit #1
fixup 9480b3d Message for commit #2
pick 5c67e61 Message for commit #3
当你保留并敞开文件时,Git 将依据你的指令来执行 rebase,从而产生如下所示的我的项目历史记录:
像这样排除不重要的提交使你的个性历史相当易懂。这一点是 git merge
无法比拟的。
Rebasing 的黄金规定
一旦你明确什么是 rebasing,最重要的事件是学习什么时候不必它。git rebase
的黄金法令是永远不要在私有分支上应用它。
举例说,设想一下如果你将 master
分支合并到 feature
分支上会产生什么:
rebase 操作将 master
中所有提交挪动到 feature
的头部,但问题是这所有都产生在你的仓库中。其余开发者仍然在原来的 master
分支上持续工作。自从 rebasing 产生了全新的提交,Git 将会认为你的 master
分支的历史记录与其他人的历史记录不同。
使两个 master
分支 同步的惟一办法是将他们合并到一起,导致呈现一个额定的合并操作和两组都蕴含雷同扭转(最原始的那个,和那些来自你从新建设的分支)的提交。不用说,这是一个十分凌乱的场景。
因而,在你运行 git rebase
之前,肯定要问本人,“还有其他人在看这个分支吗?”,如果答复是必定的,那么把你的手从键盘上拿开并开始思考让你的扭转没有破坏性(例如,git revert
命令)。否则,你能够得心应手地重写历史。
Force-Pushing
如果你尝试将合并的 master
分支推送到近程库中,Git 将避免你这样做,因为它与近程 master
分支有抵触。然而,你能够通过传递 --force
标记来强制推送,就像这样:
# Be very careful with this command!
git push --force
该操作会将近程仓库的 master
分支替换为 rebase 过的 master
分支,这会给团队的其余成员带来困扰。因而,当你确切的晓得你要做什么的时候,才要十分小心的应用这些命令。
推送一个公有新个性分支到近程仓库(例如,用于备份)。这就如同是说,“哎呦,我不想推送 feature 分支的原始版本,拿以后的版本替换吧。”再强调一次,没有人在 feature 分支的原始版本中工作是很重要的。
工作流演练
Rebasing 可能依据团队的须要或多或少的被合并到你现存的 Git 工作流 中。在这个选项中,咱们将查看 rebasing 提供在不同阶段的 feature 分支开发的益处。
在任何工作流中,首先第一步是利用 git rebase
为每一个 feature 创立一个专用的分支。这给你必要分支构造来平安应用 rebasing:
本地革除
最好的办法之一是合并 rebasing 到你的 工作流 以此来清理本地正在进行的 feature 分支。通过定期的执行一个交互式的 rebase,你能够确保每一个在你的 feature 分支中的提交是集中且有意义的。这将让你编写你本人的代码而不须要在独立提交中放心毁坏它—你能够在预先修复它。
当调用 git rebase
,对于新的分支你有两个选项:feature 父类分支(举例说,master
分支),或者在你的 feature 分支中较早的提交。咱们查看了在 交互式的 Rebasing 章节中首个选项的示例。当你仅仅须要修复最新提交时,后者的抉择最好。举例说,交互式 rebase 的最初 3 次提交显示如下:
git checkout feature
git rebase -i HEAD~3
通过指定 HEAD~3
作为新的根底,事实上你并没有挪动分支—你只是交互式的重写了接下来的 3 次提交。请留神,这不会将上游更改合并到 feature
分支。
如果你想应用这个办法重写整个 feature,git merge-base
命令对于找到 feature
分支的原始起始点十分有用。以下返回原始起始点的提交 ID,而后传递给 git rebase
:
git merge-base feature master
交互式 rebasing 的作用在于当他仅仅影响本地分支时,它是一个 引进 git rebase
到工作流中的好形式。其余开发人员惟一能看到的是你最初提交的成绩,这应该是一个简略且易于了解的 feature 分支历史记录。
然而在刚开始,这仅仅只为公有 feature 分支工作。如果你借助雷同 feature 分支与其余开发者合作,分支是共有的,你也不被容许重写它的历史记录。
没有 git merge
之外的其余抉择时能够应用交互式 rebase 来革除本地提交。
合并上游更改到 Feature 中
在开篇章节中,咱们晓得了 feature 分支如何应用 git merge
或 git rebase
合并 master
分支的上游提交。当 rebasing 通过挪动你的 feature 分支到 master
分支的头部来创立一个线性历史时,Merging 是一个用于爱护你仓库的整个历史记录的平安选项。
git rebase
的作用与本地革除类似(可能同时被执行),然而在此过程中,它合并了 master
的上游提交。
牢记,近程分支取代 master
分支是齐全非法的。这产生在其余开发者在同一个 feature 分支上合作时和你须要合并他们的更改到你的仓库中时。
举例说明,如果你和一个名为 John 的开发人员增加了对 feature
分支的提交,从 John 的仓库中获取近程 feature
分支后,你的仓库看起来像如下所示:
你能够用与 master
分支集成上游更改雷同的办法来解决这个分叉:或者你本地的 feature
分支与 john/feature
分支合并,或者 rebase 你本地 feature
分支到 john/feature
分支的头部。
请留神,任何事件在未更改之前,rebase 不能违反 Rebasing 的黄金法令 ,因为 feature
仅仅挪动了本地提交。这就如同是在说,“将我的更改增加到 John 曾经实现了的操作中。”在大多数状况下,这比通过合并提交与近程分支同步更为直观。
默认状况下,git pull
命令执行合并,然而你能够强制通过应用 rebase 的 --rebase
选项整合近程分支。
应用 Pull 申请测验 feature 分支
如果你应用 Pull 申请作为代码的审计过程,创立的 pull 申请之后,你须要防止应用 git rebase
。一旦你收回 pull 申请,其余开发人员就能看到你的提交,这就意味着它是一个私有分支。重写它的历史记录将使 Git 和你的队友无奈追踪到任何增加到 feature 分支上的后续提交。
任何来自其余开发者的更改须要应用 git merge
取代 git rebase
来被合并。
为此,在提交你的 pull 申请之前,应用交互式 rebase 清理你的代码,通常是一个好主见。
整合认可的 feature
在 feature 分支被你的团队认可之后,在应用 git merge
整合 feature 分支到主代码库之前,你有一个 rebasing feature 分支到 master
分支的选项。
合并上游更改到 feature 分支是一个相似的状况,然而,自从你不被容许在 master
中重写提交,你最初不得不应用 git merge
来整合 feature 分支。然而,通过在合并之前执行 rebase 确保 merge 将疾速进行,造成完满的线性历史。这也给了你在 pull 申请期间将任何后续提交塞入到 feature 分支中的机会。
如果你对 git rebase
感到不太难受,你能够在长期分支中始终执行 rebase。那样,如果你一不小心搞砸了你的 feature 分支历史记录,你能够屡次查看原始分支。例如:
git checkout feature
git checkout -b temporary-branch
git rebase -i master
# [Clean up the history]
git checkout master
git merge temporary-branch
总结
在你开始 rebasing 你的分支之前,这是所有你真正须要晓得:如果您想要一个没有不必要的洁净的合并提交的线性历史记录,你应该争取 git rebase
代替 git merge
整合来自另一个分支的扭转。
另一方面,如果你想保留你我的项目的残缺历史并且防止重写私有提交的危险,你能够保持应用 git merge
。任何一个选项都是齐全无效的,至多当初你是有选择性的利用 git rebase
的益处。
本文作者:Tim Pettersen,翻译:Queena
原文链接:https://dzone.com/articles/me…
译文首发:http://didispace.com/git-merg…
本文有 spring4all 技术翻译组实现,更多国外前沿常识和干货好文,欢送关注公众号:后端面试那些事儿。