建议何时使用Git rebase与Git merge?
成功改组后是否仍需要合并?
建议何时使用Git rebase与Git merge?
成功改组后是否仍需要合并?
Answers:
那你什么时候用哪一个呢?
init
新存储库,add
文件和创建目录commit
。签出一个新的功能分支(checkout -b feature
。)更改文本文件,提交并重复,以便在功能分支上有两个新的提交。然后checkout master
和merge feature
。在中log
,我看到了对master的最初提交,然后是从feature合并的两个提交。如果您将merge --squash feature
功能部件合并到主服务器中,但未提交,那么对主服务器的唯一新提交将是您自己进行的提交。
这很简单。使用rebase,您说要使用另一个分支作为工作的新基础。
例如,如果有一个branch master
,则创建一个分支来实现新功能,并说出它的名字cool-feature
,当然master分支是新功能的基础。
现在,您要在某个点上添加您在master
分支中实现的新功能。您可以只切换master
并合并cool-feature
分支:
$ git checkout master
$ git merge cool-feature
但是这样就添加了一个新的虚拟提交。如果您想避免意大利面的历史,可以重新设置基准:
$ git checkout cool-feature
$ git rebase master
然后合并到master
:
$ git checkout master
$ git merge cool-feature
这次,由于主题分支具有相同的master提交以及具有新功能的提交,因此合并将是一种快速的方式。
but this way a new dummy commit is added, if you want to avoid spaghetti-history
-不好吗?
Sean Schofield
在评论中说:“ Rebase也很好,因为一旦您最终将您的内容重新合并回master(这已经很微不足道了),您就将它放在您提交历史的“顶端”。项目可能会编写功能,但几周后就合并了,您不想将它们合并到母版中,因为它们会“塞入”历史中的母版中。我个人很喜欢能够执行git log并查看该最新功能就在“顶部”。请注意,提交日期将保留-重新设置不会更改该信息
merge
,rebase
,fast-forward
等),指的是向无环图的具体操作。考虑到这种心理模型,他们变得更容易推理。
在合并之前,进行rebase通常是一个好主意,因为该主意是您将要合并的分支Y
的工作集成到分支中B
。
但同样,合并之前,你解决任何冲突的分支(即:“重订”,如“重播我在我的分支工作从分支最近的点开始B
)。
如果做得正确的话,以后的合并从你的分支分支B
可以快进。
合并会直接影响目标分支B
,这意味着合并最好是微不足道的,否则合并B
可能很长才能恢复到稳定状态(解决所有冲突的时间)
重组后的合并点?
在我所描述的情况下,我重新建立B
了分支机构,只是有机会从上一个较近的位置重播我的工作B
,而又留在了分支机构中。
在这种情况下,仍然需要合并以将我的“重播”作品带入B
。
另一种情况(例如,在Git Ready中进行了描述)是B
通过重新部署直接保存您的工作(这确实保存了所有不错的提交,甚至为您提供了通过交互式重新部署重新排序它们的机会)。
在那种情况下(当您在B分支中时变基),您是对的:不需要进一步的合并:
当我们没有合并或重新建立基础时,默认情况下是一个Git树
我们通过重新定级得到:
第二种情况是关于:如何使新功能重新掌握。
通过描述第一个rebase场景,我的意思是提醒大家,rebase也可以用作此操作的第一步(即“将新功能重新掌握”)。
您可以使用rebase首先将主节点“引入”新功能分支:rebase将重播来自的新功能提交HEAD master
,但仍在newfeature分支中,从而有效地将分支起点从旧的主提交移至HEAD-master
。
这让你解决任何冲突的分支(意思是,在隔离,同时允许主继续同步发展,如果你的解决冲突的阶段时间过长)。
然后,你可以切换到主和合并new-feature
(或重订new-feature
到master
,如果你想保留做你的提交new-feature
科)。
所以:
master
。如有疑问,请使用合并。
重新设置和合并之间的唯一区别是:
因此,简短的答案是根据您希望历史记录的样子选择变基或合并。
选择要使用的操作时,应考虑一些因素。
如果是这样,请不要重新设置基准。Rebase破坏了分支,除非使用,否则这些开发人员将拥有损坏/不一致的存储库git pull --rebase
。这是快速使其他开发人员感到沮丧的好方法。
变基是一种破坏性操作。这意味着,如果未正确应用它,则可能会丢失已完成的工作和/或破坏其他开发人员存储库的一致性。
我曾在团队中工作,开发人员全部来自公司可以聘请专门人员处理分支和合并的时代。这些开发人员对Git并不了解很多,也不想了解太多。在这些团队中,我不会因为任何原因而建议重新定级。
一些团队使用每个功能的分支模型,其中每个分支代表一个功能(或错误修正或子功能等)。在此模型中,该分支有助于标识相关的提交集。例如,可以通过还原该分支的合并来快速还原功能(公平地说,这是一种罕见的操作)。或通过比较两个分支来比较特征(更常见)。重新设置基准将破坏分支,这将不是直接的。
我也曾在使用每个开发人员分支模型的团队中工作(我们都去过那里)。在这种情况下,分支本身不会传达任何其他信息(提交已经具有作者)。重新部署不会有任何危害。
与还原合并相比,还原(如撤消)还原非常困难和/或不可能(如果还原有冲突)。如果您认为有机会恢复,请使用合并。
需要使用相应的来拉基础操作git pull --rebase
。如果您是自己工作,则可以记住在适当的时间应该使用哪种工具。如果您在团队中工作,这将很难协调。这就是为什么大多数变基工作流都建议对所有合并(和git pull --rebase
所有提取)使用变基。
假设您有以下合并:
B -- C
/ \
A--------D
有人会指出,合并会“破坏”提交历史记录,因为如果仅查看master分支(A-D)的日志,则会错过B和C中包含的重要提交消息。
如果这是真的,我们就不会有这样的问题。基本上,您将看到B和C,除非您明确要求不看它们(使用--first-parent)。自己尝试很容易。
两种方法的合并方式不同,但是尚不清楚哪种方法总是比另一种更好,并且这可能取决于开发人员的工作流程。例如,如果开发人员倾向于定期提交(例如,他们每天从工作到家中进行两次提交),那么对于给定的分支可能会有很多提交。这些提交中的许多看起来可能都不像最终产品(我倾向于对每个功能重构一次或两次)。如果其他人正在处理相关的代码领域,并且他们试图重新整理我的更改,那可能是一个相当繁琐的操作。
如果您想将别名别名rm
为rm -rf
“节省时间”,那么也许适合您。
我一直认为,总有一天,我会遇到一个场景,其中Git rebase是解决问题的出色工具。就像我认为我会遇到一种情况,其中Git reflog是一个很好的工具,可以解决我的问题。我已经与Git合作超过五年了。没发生
乱七八糟的历史从来就不是我真正的问题。我从来没有像一部激动人心的小说那样阅读我的提交历史。在大多数情况下,我需要历史记录,无论如何我都会使用Git责备或Git对分。在那种情况下,进行合并提交实际上对我有用,因为如果合并引起了问题,那对我来说是有意义的信息。
我不得不提一下,尽管我的一般建议仍然成立,但我个人还是对使用rebase感到软化。我最近与Angular 2 Material项目进行了很多互动。他们使用rebase来保持非常干净的提交历史记录。这使我可以非常轻松地查看是什么提交修复了给定的缺陷,以及该提交是否包含在发行版中。它是正确使用rebase的一个很好的例子。
这里有很多答案说,合并会将您的所有提交变成一个提交,因此建议使用rebase保留您的提交。这是不正确的。这是一个坏主意,如果您已经推送了您的提交。
合并并不能抹杀你的提交。合并保存历史!(仅查看gitk)Rebase重写了历史记录,这在您按下后是一件坏事。
使用合并-不重新设置基准在您已经推送时。
这是Linus(Git的作者)的看法(现在托管在我自己的博客上,由Wayback Machine恢复))。这真是一本好书。
或者,您可以在下面阅读我自己的相同想法版本。
在master上重新分支:
相反,将主题分支合并到master:
TLDR:这取决于最重要的部分-整洁的历史或对发展顺序的真实表示
如果整洁的历史记录最重要,那么您首先需要重新设置基础,然后合并所做的更改,因此很清楚新代码是什么。如果您已经推动了分支机构,那么除非可以处理后果,否则不要重新建立基础。
如果最重要的是顺序的真实表示,那么您无需合并即可合并。
合并意味着:创建一个新的提交,将我的更改合并到目标中。注意:此新提交将具有两个父级-您的提交字符串中的最新提交以及您要合并的另一个分支的最新提交。
Rebase的意思是:使用我当前的提交集作为提示,创建一个全新的提交系列。换句话说,计算一下如果我从我的基础上开始进行更改,我将会看到什么样的更改。因此,在重新设置基准之后,您可能需要重新测试所做的更改,并且在重新基准设置期间,您可能会遇到一些冲突。
鉴于此,您为什么要重新定基?只是为了保持发展历史清晰。假设您正在使用功能X,并在完成后将更改合并到其中。目标现在将具有一个提交,该提交将沿“添加的功能X”的内容进行说明。现在,如果不进行合并,而是先进行基础合并再合并,则目标开发历史记录将在单个逻辑进程中包含所有单个提交。这样一来,以后审查更改就变得容易得多。想象一下,如果50名开发人员一直在合并各种功能,那么很难回顾一下开发历史。
也就是说,如果您已经将要处理的分支推送到上游,则不应该重新设置基础,而应该合并。对于尚未推送到上游的分支,请进行基础,测试和合并。
另一个可能需要重新设置基准的时间是,您希望在推向上游之前摆脱分支的提交。例如:提早引入一些调试代码的提交,以及其他进一步清理代码的提交。唯一的方法是执行交互式变基:git rebase -i <branch/commit/tag>
更新:当您使用Git连接到不支持非线性历史记录的版本控制系统(例如Subversion)时,您还希望使用rebase 。当使用git-svn桥时,非常重要的一点是,合并回Subversion的更改是中继的最新更改之上的顺序更改列表。只有两种方法可以做到:(1)手动重新创建更改;(2)使用rebase命令,这要快得多。
更新2:另一种思考变基的方法是,它可以实现从开发样式到要提交的存储库中接受的样式的某种映射。假设您喜欢以很小的小块来提交。您可以进行一次提交来解决打字错误,一次提交可以摆脱未使用的代码,依此类推。当您完成需要做的工作时,您将进行一系列的提交。现在,假设您要提交的存储库鼓励进行较大的提交,因此对于您正在执行的工作,人们可能希望进行一次或两次提交。您如何获取提交字符串并将其压缩到期望的值?您将使用交互式基准,并将您的微小提交压缩为更少的较大块。如果需要反向操作,也是如此-如果您的样式是一些大型提交,但是存储库需要一长串的小型提交。您也可以使用rebase来做到这一点。如果已合并,则现在将提交样式嫁接到主存储库中。如果有很多开发人员,您可以想象一段时间后要遵循几种不同的提交样式的历史记录会多么困难。
更新3:Does one still need to merge after a successful rebase?
是的,您知道。原因是重新设置本质上涉及提交的“转移”。就像我上面说的,这些提交是经过计算的,但是如果从分支的角度来看有14个提交,那么假设您的rebase没有任何问题,那么之后(在重新设置基准之前)将有14个提交重新设置完成。在重新设置基准之前,您有一个分支。之后,您将具有相同长度的分支。在发布更改之前,您仍然需要合并。换句话说,根据需要进行多次变基(同样,仅当您尚未将更改推送到上游时)。仅在重新设置基准后才合并。
git merge
支持--no-ff
强制执行合并提交的选项。
虽然合并无疑是集成更改的最简单,最常见的方法,但它并不是唯一的方法:Rebase是替代的集成方法。
了解合并会更好
当Git执行合并时,它将查找三个提交:
快进或合并提交
在非常简单的情况下,两个分支之一自分支发生以来就没有任何新提交-它的最新提交仍然是共同的祖先。
在这种情况下,执行集成非常简单:Git可以将其他分支的所有提交添加到公共祖先提交之上。在Git中,这种最简单的集成形式称为“快进”合并。然后,两个分支共享完全相同的历史记录。
但是,在很多情况下,两个分支机构都各自向前移动。
为了进行集成,Git必须创建一个包含它们之间差异的新提交-合并提交。
人类承诺与合并承诺
通常,提交是由人类精心创建的。这是一个有意义的单元,它仅包装相关的更改并用注释对其进行注释。
合并提交有点不同:它不是由开发人员创建的,而是由Git自动创建的。与其包装一组相关的更改,它的目的是像打结一样连接两个分支。如果以后要了解合并操作,则需要查看两个分支的历史以及相应的提交图。
与Rebase集成
有些人更喜欢没有这种自动合并提交。相反,他们希望项目的历史看起来像是沿着一条直线发展的。没有迹象表明它在某个时刻被拆分为多个分支。
让我们逐步完成一个变基操作。该场景与前面的示例相同:我们希望将分支B的更改集成到分支A,但现在要使用rebase。
我们将分三步进行
git rebase branch-A // Synchronises the history with branch-A
git checkout branch-A // Change the current branch to branch-A
git merge branch-B // Merge/take the changes from branch-B to branch-A
首先,Git将“撤消”分支A上行开始分支之后(公共祖先提交之后)发生的所有提交。但是,当然,它不会丢弃它们:相反,您可以将这些提交视为“暂时保存”。
接下来,它将应用我们要集成的分支B的提交。此时,两个分支看起来完全相同。
在最后一步中,现在重新应用分支A上的新提交-但是在分支B的集成提交之上的新位置上(它们是基于新提交的)。
结果似乎是直线发展了。保留了原来的提交结构,而不是包含所有合并更改的合并提交。
最后,您将获得一个干净的分支branch-A,并且没有不需要的和自动生成的提交。
合并/变基之前:
A <- B <- C [master]
^
\
D <- E [branch]
之后git merge master
:
A <- B <- C
^ ^
\ \
D <- E <- F
之后git rebase master
:
A <- B <- C <- D' <- E'
(A,B,C,D,E和F为提交)
该示例以及有关Git的详细说明可以在《Git基础教程》中找到。
这个答案围绕Git Flow展开。这些表是使用漂亮的ASCII表生成器生成的,而历史树则使用此命令(别名为git lg
):
git log --graph --abbrev-commit --decorate --date=format:'%Y-%m-%d %H:%M:%S' --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%ad%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n'' %C(white)%s%C(reset) %C(dim white)- %an%C(reset)'
表按时间倒序排列,以便与历史记录树更加一致。另请参阅git merge
和之间的区别git merge --no-ff
(您通常希望使用git merge --no-ff
它,因为这会使您的历史看起来更接近现实):
git merge
命令:
Time Branch "develop" Branch "features/foo"
------- ------------------------------ -------------------------------
15:04 git merge features/foo
15:03 git commit -m "Third commit"
15:02 git commit -m "Second commit"
15:01 git checkout -b features/foo
15:00 git commit -m "First commit"
结果:
* 142a74a - YYYY-MM-DD 15:03:00 (XX minutes ago) (HEAD -> develop, features/foo)
| Third commit - Christophe
* 00d848c - YYYY-MM-DD 15:02:00 (XX minutes ago)
| Second commit - Christophe
* 298e9c5 - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git merge --no-ff
命令:
Time Branch "develop" Branch "features/foo"
------- -------------------------------- -------------------------------
15:04 git merge --no-ff features/foo
15:03 git commit -m "Third commit"
15:02 git commit -m "Second commit"
15:01 git checkout -b features/foo
15:00 git commit -m "First commit"
结果:
* 1140d8c - YYYY-MM-DD 15:04:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/foo' - Christophe
| * 69f4a7a - YYYY-MM-DD 15:03:00 (XX minutes ago) (features/foo)
| | Third commit - Christophe
| * 2973183 - YYYY-MM-DD 15:02:00 (XX minutes ago)
|/ Second commit - Christophe
* c173472 - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git merge
与 git rebase
第一点:始终将功能合并到开发中,永远不要从功能中重新建立开发基础。这是重新定购黄金法则的结果:
的黄金法则
git rebase
是永远不要在公共分支上使用它。
换句话说:
切勿使您推送到任何地方的内容变基。
我个人要补充:除非是功能分支,并且您和您的团队都知道后果。
因此,git merge
vs 问题git rebase
几乎仅适用于要素分支(在以下示例中,--no-ff
合并时始终使用它)。请注意,由于我不确定是否有更好的解决方案(存在争论),因此我仅提供两种命令的行为方式。就我而言,我更喜欢使用git rebase
它,因为它会产生更好的历史树:)
git merge
命令:
Time Branch "develop" Branch "features/foo" Branch "features/bar"
------- -------------------------------- ------------------------------- --------------------------------
15:10 git merge --no-ff features/bar
15:09 git merge --no-ff features/foo
15:08 git commit -m "Sixth commit"
15:07 git merge --no-ff features/foo
15:06 git commit -m "Fifth commit"
15:05 git commit -m "Fourth commit"
15:04 git commit -m "Third commit"
15:03 git commit -m "Second commit"
15:02 git checkout -b features/bar
15:01 git checkout -b features/foo
15:00 git commit -m "First commit"
结果:
* c0a3b89 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/bar' - Christophe
| * 37e933e - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| | Sixth commit - Christophe
| * eb5e657 - YYYY-MM-DD 15:07:00 (XX minutes ago)
| |\ Merge branch 'features/foo' into features/bar - Christophe
| * | 2e4086f - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | | Fifth commit - Christophe
| * | 31e3a60 - YYYY-MM-DD 15:05:00 (XX minutes ago)
| | | Fourth commit - Christophe
* | | 98b439f - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \ \ Merge branch 'features/foo' - Christophe
| |/ /
|/| /
| |/
| * 6579c9c - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | Third commit - Christophe
| * 3f41d96 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ Second commit - Christophe
* 14edc68 - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git rebase
命令:
Time Branch "develop" Branch "features/foo" Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10 git merge --no-ff features/bar
15:09 git merge --no-ff features/foo
15:08 git commit -m "Sixth commit"
15:07 git rebase features/foo
15:06 git commit -m "Fifth commit"
15:05 git commit -m "Fourth commit"
15:04 git commit -m "Third commit"
15:03 git commit -m "Second commit"
15:02 git checkout -b features/bar
15:01 git checkout -b features/foo
15:00 git commit -m "First commit"
结果:
* 7a99663 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/bar' - Christophe
| * 708347a - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| | Sixth commit - Christophe
| * 949ae73 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | Fifth commit - Christophe
| * 108b4c7 - YYYY-MM-DD 15:05:00 (XX minutes ago)
| | Fourth commit - Christophe
* | 189de99 - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \ Merge branch 'features/foo' - Christophe
| |/
| * 26835a0 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | Third commit - Christophe
| * a61dd08 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ Second commit - Christophe
* ae6f5fc - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
develop
到要素分支git merge
命令:
Time Branch "develop" Branch "features/foo" Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10 git merge --no-ff features/bar
15:09 git commit -m "Sixth commit"
15:08 git merge --no-ff develop
15:07 git merge --no-ff features/foo
15:06 git commit -m "Fifth commit"
15:05 git commit -m "Fourth commit"
15:04 git commit -m "Third commit"
15:03 git commit -m "Second commit"
15:02 git checkout -b features/bar
15:01 git checkout -b features/foo
15:00 git commit -m "First commit"
结果:
* 9e6311a - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/bar' - Christophe
| * 3ce9128 - YYYY-MM-DD 15:09:00 (XX minutes ago) (features/bar)
| | Sixth commit - Christophe
| * d0cd244 - YYYY-MM-DD 15:08:00 (XX minutes ago)
| |\ Merge branch 'develop' into features/bar - Christophe
| |/
|/|
* | 5bd5f70 - YYYY-MM-DD 15:07:00 (XX minutes ago)
|\ \ Merge branch 'features/foo' - Christophe
| * | 4ef3853 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | | Third commit - Christophe
| * | 3227253 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ / Second commit - Christophe
| * b5543a2 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | Fifth commit - Christophe
| * 5e84b79 - YYYY-MM-DD 15:05:00 (XX minutes ago)
|/ Fourth commit - Christophe
* 2da6d8d - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git rebase
命令:
Time Branch "develop" Branch "features/foo" Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10 git merge --no-ff features/bar
15:09 git commit -m "Sixth commit"
15:08 git rebase develop
15:07 git merge --no-ff features/foo
15:06 git commit -m "Fifth commit"
15:05 git commit -m "Fourth commit"
15:04 git commit -m "Third commit"
15:03 git commit -m "Second commit"
15:02 git checkout -b features/bar
15:01 git checkout -b features/foo
15:00 git commit -m "First commit"
结果:
* b0f6752 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/bar' - Christophe
| * 621ad5b - YYYY-MM-DD 15:09:00 (XX minutes ago) (features/bar)
| | Sixth commit - Christophe
| * 9cb1a16 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | Fifth commit - Christophe
| * b8ddd19 - YYYY-MM-DD 15:05:00 (XX minutes ago)
|/ Fourth commit - Christophe
* 856433e - YYYY-MM-DD 15:07:00 (XX minutes ago)
|\ Merge branch 'features/foo' - Christophe
| * 694ac81 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | Third commit - Christophe
| * 5fd94d3 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ Second commit - Christophe
* d01d589 - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git cherry-pick
当您只需要一个特定的提交时,这git cherry-pick
是一个不错的解决方案(该-x
选项在原始提交消息正文中附加了一行“ (从提交中选取的樱桃...) ”,因此通常使用它是一个好主意-git log <commit_sha1>
查看它):
命令:
Time Branch "develop" Branch "features/foo" Branch "features/bar"
------- -------------------------------- ------------------------------- -----------------------------------------
15:10 git merge --no-ff features/bar
15:09 git merge --no-ff features/foo
15:08 git commit -m "Sixth commit"
15:07 git cherry-pick -x <second_commit_sha1>
15:06 git commit -m "Fifth commit"
15:05 git commit -m "Fourth commit"
15:04 git commit -m "Third commit"
15:03 git commit -m "Second commit"
15:02 git checkout -b features/bar
15:01 git checkout -b features/foo
15:00 git commit -m "First commit"
结果:
* 50839cd - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/bar' - Christophe
| * 0cda99f - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| | Sixth commit - Christophe
| * f7d6c47 - YYYY-MM-DD 15:03:00 (XX minutes ago)
| | Second commit - Christophe
| * dd7d05a - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | Fifth commit - Christophe
| * d0d759b - YYYY-MM-DD 15:05:00 (XX minutes ago)
| | Fourth commit - Christophe
* | 1a397c5 - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \ Merge branch 'features/foo' - Christophe
| |/
|/|
| * 0600a72 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | Third commit - Christophe
| * f4c127a - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ Second commit - Christophe
* 0cf894c - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git pull --rebase
我不确定我可以比Derek Gourlay更好地解释它...基本上,使用git pull --rebase
代替git pull
:)虽然本文中缺少的是,您可以默认启用它:
git config --global pull.rebase true
git rerere
再次,在这里很好地解释。简而言之,如果启用它,则不必再多次解决相同的冲突。
Git rebase用于使历史记录清理器和存储库结构中的分支路径线性化。
它也可用于将您创建的分支保密,因为在重新建立基础并将更改推送到服务器后,如果删除分支,则不会有您在使用的分支的证据。因此,您的分支机构现在已成为您的本地事务。
重新设置基准之后,我们还摆脱了一个额外的提交,该提交用于查看我们是否进行了正常的合并。
是的,成功重新设置基准后,仍然需要进行合并,因为rebase命令只是将您的工作放在您在重新基准确定中提到的分支之上,例如master,并将分支的第一次提交作为master分支的直接后代。 。这意味着我们现在可以进行快速前向合并,以将更改从该分支引入到master分支。
一些实际的例子,在某种程度上与Gerrit的大规模开发有关用于审阅和交付集成:
当我将功能分支提升到新的远程主服务器时,我会合并。这样可以进行最少的提升工作,并且很容易在gitk中跟踪功能开发的历史。
git fetch
git checkout origin/my_feature
git merge origin/master
git commit
git push origin HEAD:refs/for/my_feature
准备交付提交时合并。
git fetch
git checkout origin/master
git merge --squash origin/my_feature
git commit
git push origin HEAD:refs/for/master
当我的交付提交由于任何原因而失败集成时,我会重新设置基础,并且需要将其更新为新的远程主服务器。
git fetch
git fetch <gerrit link>
git checkout FETCH_HEAD
git rebase origin/master
git push origin HEAD:refs/for/master
很多时候都解释了什么是基础,什么是合并,但是什么时候应该使用呢?
什么时候应该使用变基?
随着Git变基更改历史记录。因此,当其他人在同一分支上工作时/如果已推送它,则不应使用它。但是,如果您有本地分支机构,则可以在合并分支机构到母版之前进行合并变迁母版,以保留更清晰的历史记录。这样做,合并到master分支后,您将不会看到您在master分支中使用了分支-历史记录比较“干净”,因为您没有自动生成的“ merged ..”,但仍然有没有自动生成的“合并..”提交的主分支中的完整历史记录。
但是请确保使用git merge feature-branch --ff-only
,以确保在将功能合并回main时创建单个提交时没有冲突。如果您在获取功能分支的历史记录时正在处理的每个任务都使用功能分支,而不是“合并..”提交,则这很有意思。
第二种情况是,如果您从一个分支分支,并且想知道主分支中发生了什么变化。Rebase为您提供了信息,因为它包括每个单次提交。
什么时候应该使用合并?
当您不需要或不想在主分支中拥有某个功能分支的所有历史记录时,或者如果其他人正在同一分支上工作,则可以将其推送。如果您仍然想要历史记录,只需将master合并到Feature分支中,然后再将Feature分支合并到master中。这将导致快速合并,您在母版中拥有功能分支的历史记录(包括由于将母版合并到功能分支中而导致的合并提交)。
我git rebase
什么时候使用?几乎永远不会,因为它会重写历史记录。git merge
几乎总是首选,因为它尊重项目中实际发生的事情。