#前言
git rebase命令经常被认为是Git的巫术,初学者应该远离它,但它实际上可以让开发团队在使用时更加轻松。今天,我们将git rebase与相关git merge命令进行比较。
#概念
首先要理解的是git rebase和git merge解决了同样的问题。这两个命令都旨在将更改从一个分支集成到另一个分支 - 它们只是以不同的方式进行。试想一下当你开始在专用分支中开发新功能时另一个团队成员以新提交更新master分支会发生什么。这会出现分叉历史记录,对于使用Git作为协作工具的任何人来说都应该很熟悉。
当合并master分支到你的feature分支时,你有两个选择:merge或rebase。
#Merge
最简单最常用的是将master分支合并到feature分支中:
git checkout feature git merge master 或者,你可以简化为一行: git merge master feature
这会在feature分支中创建一个新的“merge commit”,它将两个分支的历史联系在一起,为你生成如下所示的分支结构:
合并很好,因为它是一种非破坏性的操作。现有分支结构不会以任何方式更改。这避免了rebase的所有潜在缺陷(下面细说)。另一方面,这也意味着每次上游更改时feature都需要合并,且有无关的合并提交。如果master改动非常频繁,这可能会严重污染你分支的历史记录。尽管可以使用高级git log选项减轻此问题的影响,但它可能使其他开发人员难以理解项目的历史更改记录。
#Rebase
作为merge的替代方法,你可以使用以下命令将feature分支rebase到master分支上:
git checkout feature git rebase master
这会将整个feature分支移动到master分支的顶端,从而有效地整合了所有master的新提交。但是,rebase不是使用merge commit,而是通过为原始分支中的每个提交创建全新的提交来重写项目历史记录。
rebase的主要好处是可以获得更清晰的项目历史记录。首先,它消除了不必要的git merge产生的merge commit。其次,正如在上图中所看到的,rebase也会产生完美线性的项目历史记录 - 你可以从feature分支顶端一直跟随到项目的开始而没有任何的分叉。
这使得它比命令git log,git bisect和gitk更容易浏览项目。但是,对这个原始的提交历史记录有两个权衡:安全性和可追溯性。如果你不遵循rebase的黄金法则,重写项目历史记录可能会对你的协作工作流程造成灾难性后果。其次rebase会丢失merge commit提供的上下文 - 你无法看到上游更改何时合并到功能中。
#Interactive Rebase
Interactive rebase使你有机会在将提交移动到新分支时更改提交。这比自动rebase更强大,因为它提供了对分支提交历史的完全控制。通常,这用于在合并特征分支到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无法做到的事情。
rebase的黄金法则
一旦你理解了什么是rebase,最重要的是了解什么时候不使用它。git rebase的黄金法则是永远不要在公共分支使用它。例如,想想如果你把master分支rebase到你的feature分支会发生什么:
rebase将master所有提交移动到feature顶端。问题是这只发生在你的仓库中。所有其他开发人员仍在使用原始版本master。由于rebase导致全新的提交,
Git会认为你的master分支的历史与其他人的历史不同。同步两个master分支的唯一方法是将它们合并在一起,从而产生额外的合并提交和两组包含相同更改的提交(原始提交和来自rebase分支的更改)。
这将是一个非常令人困惑的情况。因此,在你运行git rebase之前,总是问自己,“还有其他人在用这个分支吗?”如果答案是肯定的,那就把你的手从键盘上移开,考虑使用非破坏性的方式进行(例如,git revert命令)。否则,你可以随心所欲地重写历史记录。
强制推
如果你尝试将rebase过的master分支推到远程仓库,Git将阻止你这样做,因为它与远程master分支冲突。但是,你可以通过传递--force标志来强制推送,如下所示:
#这个命令要非常小心! git push --force
这将覆盖远程master分支以匹配rebase过的分支,并使团队的其他成员感到困惑。因此,只有在确切知道自己在做什么时才能非常小心地使用此命令。
工作流rebase可以根据你团队的需要尽多地或少量地整合到你现有的Git工作流程中。在本节中,我们将了解rebase在功能开发的各个阶段的好处。任何工作流程git rebase的第一步是为每个功能创建专用分支。这为你提供了必要的分支结构,以安全地利用rebase:
本地清理
将rebase加入工作流程的最佳方法之一是清理本地正在进行的功能。通过定期执行交互式rebase,你可以确保功能中的每个提交都具有针对性和意义。这使你可以写代码而无需担心将其分解为隔离多个的提交 - 你可以在事后修复它。
调用git rebase时,有两个基(base)选项:feature的父分支(例如master),或feature中的历史提交。我们在Interactive Rebasing部分看到了第一个选项的示例。当你只需要修复最后几次提交时,后一种选择很好。例如,以下命令仅针对最后3次提交的交互式rebase。
git checkout feature git rebase -i HEAD~3
通过指定HEAD~3为新的基,你实际上并没有移动分支 - 你只是交互式地重写其后的3个提交。请注意,这不会将上游更改合并到feature分支中。
如果要使用此方法重写整个功能,git merge-base命令可用于查找feature分支的原始基。以下内容返回原始基础的提交ID,然后你可以将其传递给
git rebase: git merge-base feature master
交互式rebase的使用是引入git rebase工作流的好方法,因为它只影响本地分支。其他开发人员唯一能看到的就是你的成品,这应该是一个简洁易懂的分支历史记录。
但同样,这仅适用于私有功能分支。如果你通过相同的分支与其他开发人员协作,则该分支是公共的,并且你能重写其历史记录。
#总结
这就是你需要知道的关于rebase你的分支。如果你更喜欢提交的干净,消除不必要合并的线性历史记录,那么你在继承另一分支的更改时应该使用git rebase 而不是git merge。
另一方面,如果你想保留项目的完整历史记录并避免重写公共提交的风险,你可以仍然使用git merge。这两种选择都是完全可以的,但至少可以选择利用git rebase有它的好处。
全部0条评论
快来发表一下你的评论吧 !