虽然 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 ,从而产生如下所示的项目历史记录: