merge/rebase 的方向或顺序有区别吗?
Does the direction or order of a merge/rebase make a difference?
假设您在处理功能分支时从远程存储库中提取内容,并且新提交已添加到主分支。
您完成了功能分支的工作,提交您的更改,然后 merge/rebase 将其提交到 master。在拉取提交之前或之后,在 master 分支中的哪个位置插入了功能提交?如果您从未进行过拉动,它们会插入哪里?会得到相同的结果吗?
此外,如果您 merge/rebase 掌握功能分支而不是相反,会发生什么情况?如果你在 pull 之前或之后 merged/rebase master 插入功能分支的哪里?会有同样的结果吗?它的历史看起来与前面提到的 merge/rebase 的功能有什么不同吗?
更简洁地说,合并的方向 and/or 合并的顺序对最终的合并有不同的结果吗?我觉得没关系。
旁白:这个问题对于 Git 的人来说可能很容易回答,但是有成百上千的文档和教程资源在那里,我从未见过直接解决它。在不知道答案的情况下,Git 可能会非常难以理解。
因为操作顺序在某些 Git 概念和一般编程中很重要,所以它可能会导致某些人得出结论它有所作为。此外,我们通常倾向于认为修订是按时间顺序发生的,并期望 Git 以相同的方式工作。用户界面和命令行也通过暗示操作顺序来发挥这种作用。
其他版本跟踪工具在抽象这种认知腐蚀操作方面做得更好。
合并时,远程和本地提交都完整保留,合并提交指的是两者。
当你变基时,远程提交被保留(或者至少它们应该被保留!),并且你的本地提交被应用在它之上。永远不要试图强迫 git 向其他方向变基,这会导致灾难。
有关合并与变基差异的更多信息,请阅读此答案What's the difference between 'git merge' and 'git rebase'?
You finish working on the feature branch, commit your changes and then merge/rebase it onto master.
Where in the master branch are the feature commits inserted, before or after the pulled commits?
After: merge/rebase 将考虑 master 分支的当前状态。
如果该分支已经发展(通过拉取),那么 merge/rebase 将使用当前的主 HEAD(现在引用拉取的提交)
Where are they inserted if you never performed a pull?
相同:它将使用当前的主 HEAD(不反映任何新的提交,因为没有完成拉取)
Will it have the same result?
不,考虑到两种情况下 master HEAD 不同。
Also, what happens if you merge/rebase master onto the feature branch instead of the other way around?
首先,不要这样做:这不是最佳做法。
但如果这样做,merge/rebase 将使用 HEAD 功能。
Where is master inserted into the feature branch if you merged/rebase before or after the pull? Will it have the same result?
相同的结果,因为在这两种情况下,它都使用了 HEAD 功能,当您执行(或不执行)拉取 master 时,该功能没有改变。
TL;DR
Moreover, we normally tend to think of revisions as occurring in chronological sequence and expect Git to work the same way.
这是一个可怕的错误。 Git 按 图顺序 ,而不是时间顺序。当图形顺序是按时间顺序排列时——有时但并非总是如此——然后它工作正常。
长
(我什至不打算在这里触及 rebase。有关 rebase 的适当讨论,请参阅之前的帖子。我将专注于合并中的对称性,以及接缝可以显示的地方.)
More succinctly, do the direction of the merge and or order of the merge have different outcomes on the resulting merge? I suspect it doesn't matter.
答案既不是也不是。
要理解为什么这是答案,您需要了解关于Git的几件事。
首先,让我们考虑一下 Git 如何处理提交,与其他人做对比(大多数其他人?所有其他人?必须至少有一个其他 VCS 也这样做......)。在版本控制系统中,在 b运行ch 中提交的过程将新提交 添加到 b运行 ch;但是在 Git 中,包含提交 一旦提交 的 b运行 集合可以是,并且是动态变化的东西。也就是说,一旦提交,独立于任何 b运行ch,并且如果您愿意,可以在 no[=191] 上提交=] b运行ch.
例如,在 Mercurial 中,这是完全不可能的。虽然 Mercurial 在许多方面与 Git 非常相似,但提交 的存在需要 其 b运行ch 的存在。提交是在 on that b运行ch 上进行的,并且永远是 的 b运行ch 的一部分。这是保存提交的 only b运行ch:提交永久附加到其 b运行ch.
在Git和Mercurial中,每个提交都有一个唯一的ID,每个提交存储其parent(单数)提交的唯一ID ,如果是普通提交。通过遵循这个 backwards-looking 链,从 last 提交开始并向后工作,我们可以找到 b运行ch 上的提交历史:
... <-grandparent <-parent <-child
在 Mercurial 中,这些提交永远在它们的 b运行ch 上,所以我们可以在左边写上 b运行ch 名称:
branch-A: ...--I--J
在 Mercurial 中查找最新的提交很容易,因为提交在本地存储库中有一个简单的序列号(以及用于在存储库之间共享的唯一哈希 ID)。
在 Git 中,b运行ch names 是可移动的。在提交 J
存在之前,名称 branch-A
存储提交 I
:
的原始哈希 ID
...--H--I <-- branch-A
进行新提交时,Git 只需将新提交的哈希 ID 写入 b运行ch 名称,以便 b运行ch 指向新提交:
...--H--I--J <-- branch-A
合并既是名词又是动词
在版本控制中,合并动词,或合并一些提交,是一个过程。结果——至少在 Git 和 Mercurial 中——是一个 merge commit,我们使用 merge 这个词作为形容词修改commit,或简称,a merge(名词)。
合并提交 成为 合并提交的原因是它们有 两个 parent,将两条开发线放在一起:
...--I--J
\
M
/
...--K--L
在这里,Git 和 Mercurial 基本相同,有一个非常重要的区别:在 Mercurial 中,合并提交专门针对 one b运行ch,当你 运行 hg merge
时,无论你在哪个 b运行ch。提交——包括合并提交——永久地附在它们的 b运行ches 上。一旦合并过程完成并且存在合并提交,合并提交就在那个 b运行ch 上。在 Git 中,合并提交进入当前 b运行ch,但是因为我们可以移动 name,所以在某种意义上这并不重要。
但我们必须同时查看两个部分:动词部分 to merge,然后仔细查看名词部分 a merge. (旁白:Git 还允许合并提交有 超过两个 parent,而 Mercurial 将每个合并限制为两个 parent。没有什么这些时髦的合并,Git 调用 octopus 合并 ,可以做到你不能用一系列成对合并做的事情,但章鱼合并在某些情况下可以更清楚地显示意图.)
要合并,动词
例如,假设 branch-A
和 branch-B
在合并之前是这样的:
...--I--J <-- branch-A
...--K--L <-- branch-B
在我们合并这些之前,我们必须追溯两个历史足够远才能找到合并基础,共同提交来自这两条发展路线发生了分歧。 (在 Mercurial 中也是如此。)所以让我们再补充一点:
I--J <-- branch-A
/
...--H
\
K--L <-- branch-B
在这里,commit H
是共同的起点。在 Git 中,提交 H
同时在 两个 b运行 上 (但不是在 Mercurial 中)。小号生病了,两个版本控制系统都以几乎相同的方式执行 合并 过程:您首先选择一个提交来检出,例如使用 [=30 提交 J
=] 或 hg update branch-A
。然后使用命令的 merge
动词选择另一个提交:git merge branch-B
或 hg merge branch-B
。 VCS 找到合适的合并基础,即提交 H
,并将 H
的内容与 J
的内容进行比较,以查看 you更改:
git diff --find-renames <hash-of-H> <hash-of-J> # what we changed
并重复相同的比较以找出 他们 改变了什么:
git diff --find-renames <hash-of-H> <hash-of-L> # what they changed
Git 将这些更改合并为一个大的 "all changes",将这些更改应用到 base(提交 H
),并使新提交。
(Mercurial 做的大致相同,尽管在 Mercurial 如何知道重命名方面存在一些非常重要的差异。这些仅在您自合并基础后重命名了一些文件时才重要。如果您 重命名文件,并且有 rename/rename 冲突,合并顺序变得非常重要。但我们假设没有重命名问题。)
这里最有趣的事情是您可以控制如何更改组合。在 Git 中,您可以通过 合并策略 和 扩展策略参数 执行此操作;在 Mercurial 中,您可以通过选择的 合并工具 来完成此操作。如果您使用 "ours" strategy/tool,VCS 会完全忽略它们的更改:合并后的更改只是 您的 更改,因此 VCS 使用与当前提交中的代码相同。这里的合并顺序显然很重要:如果我们忽略 他们的 更改,我们最好确定谁是 "us"!
即使没有 "ours" 策略,您的更改和他们的更改之间也可能存在冲突。如果是这样,Git 和 Mercurial 都可以被告知:更喜欢我的 或 更喜欢他们的。这些会给出不同的结果,所以在这里,合并顺序再次很重要。当然,此时有一个对称选项:选择我的或选择他们的。如果你交换角色,你可以交换选项——所以虽然顺序很重要,但它并不那么重要。
合并,名词
让我们假设没有冲突,也没有特殊的 ours/theirs 事件,并且 运行 git checkout branch-A; git merge branch-B
。如果一切顺利,VCS 将合并提交 M
及其两个 parents:
I--J
/ \
...--H M <-- branch-A
\ /
K--L <-- branch-B
在 Mercurial 中,合并顺序在这里很重要,因为一旦提交 M
,它就会永远停留在它的 b运行ch 上。但是 Git 允许我们 在事后移动 b运行ch names。我们可以把M
做成这样,放在原处,把branch-A
往后推一步,再次指向J
,然后把branch-B
向前移动,指向M
,给出:
I--J <-- branch-A
/ \
...--H M <-- branch-B
\ /
K--L
这与我们 git checkout branch-B; git merge branch-A
得到的结果几乎相同。所以看起来在这里,合并顺序是无关紧要的(前提是 verb 部分没有任何障碍)。但是这里的图表中缺少一些东西,那就是 first 和 not-first parents![= 的概念55=]
合并提交M
的第一个parent,在Git和Mercurial中,是"same branch"parent。也就是说,由于我们在 运行 合并时提交 J
,因此 M
的 first parent 是提交 J
。这使得 L
成为 第二个 parent。如果我们将 b运行ch 标签推到 Git 周围,我们可以知道我们已经这样做了,因为第一个和第二个 parents 仍然是另一个顺序。
所以我们在这里看到对于 Git,即使 to merge 动词没有顺序问题,结果 merge commit(形容词或名词)确实有一个命令。由您(用户)决定该订单对您是否重要。如果不是,则对称性可用。如果提交 parent 顺序很重要,那么合并的 direction/order 在 Git 中和在 Mercurial 中一样重要。
图表是关键
在任何 graph-based 版本控制系统中——因此在 Git 和 Mercurial 中——图表 是 历史。特别是在 Git 中,没有 文件历史这样的东西; 该图不仅是 主要 历史,而且是 只有历史。 (Mercurial 以更常规的方式存储文件数据,因此既有提交历史 也有 文件历史,但无论如何如果没有提交历史,文件历史也没有用。)
为了能够理解 Git 的作用和原因,您需要了解足够的图论来驾车或骑车 public t运行 坐在城市周围。这并不是那么多——但如果你没有意识到 Git 有这些 one-way 铁轨/街道/桥梁,从 last 提交回来迈向第,很多事情就没有意义了。 Git 开始一个结束,然后倒退到开始。 b运行ch 名称让您进入图表,在 branch-tip 结束。其他一切都是提交图的函数。
TLDR: Merge
, merges argument branches into checkout branch,
rebase
, rebase puts checkout branch on top of argument branch (ie, ahead of, in the future, nearest to now)
合并会影响结帐分支标签的推进,顺序无关紧要
例如,提供给 git merge A B
的分支将合并到结帐分支中
(没什么大不了的,如果你写错了) 提示:git branch -f <oops-branch> <go-back-to-commit> # don't be on oops-branch
这样做
99% 的时间你想要做的是检查一些分支 git checkout A
然后将另一个分支合并到它 git merge B
✅ $ git merge B #I am on branch A, megre B into A
分支 A 标签被推进到合并提交,而 B 不是。
Rebase 顺序影响哪些提交被重写
(有点大不了,但你可以从错误中恢复) 提示:git branch -f <oops-branch> <go-back-to-commit> # don't be on oops-branch
这样做
99% 的时间你只想使用 rebase 将更改从一个分支拉到你的开发分支。此 rebase
语法与上面显示的惯用合并方式相反(即,检查分支“A”然后 merge
分支 'B' 进入 'A')
rebase
想象一下在一根棍子上烤棉花糖,最后一个棉花糖堆在前一个上面。这就是 rebase
语法的工作原理。
✅ $ git rebase main dev #I am on branch main but it doesn't matter what branch I am on bc I've explicitly told git the rebase order, rebase dev on top of main
不要这样做
你能看出这里的问题吗?
❌$ git rebase dev #I am on branch main, rebases main on top of dev
假设您在处理功能分支时从远程存储库中提取内容,并且新提交已添加到主分支。
您完成了功能分支的工作,提交您的更改,然后 merge/rebase 将其提交到 master。在拉取提交之前或之后,在 master 分支中的哪个位置插入了功能提交?如果您从未进行过拉动,它们会插入哪里?会得到相同的结果吗?
此外,如果您 merge/rebase 掌握功能分支而不是相反,会发生什么情况?如果你在 pull 之前或之后 merged/rebase master 插入功能分支的哪里?会有同样的结果吗?它的历史看起来与前面提到的 merge/rebase 的功能有什么不同吗?
更简洁地说,合并的方向 and/or 合并的顺序对最终的合并有不同的结果吗?我觉得没关系。
旁白:这个问题对于 Git 的人来说可能很容易回答,但是有成百上千的文档和教程资源在那里,我从未见过直接解决它。在不知道答案的情况下,Git 可能会非常难以理解。
因为操作顺序在某些 Git 概念和一般编程中很重要,所以它可能会导致某些人得出结论它有所作为。此外,我们通常倾向于认为修订是按时间顺序发生的,并期望 Git 以相同的方式工作。用户界面和命令行也通过暗示操作顺序来发挥这种作用。
其他版本跟踪工具在抽象这种认知腐蚀操作方面做得更好。
合并时,远程和本地提交都完整保留,合并提交指的是两者。
当你变基时,远程提交被保留(或者至少它们应该被保留!),并且你的本地提交被应用在它之上。永远不要试图强迫 git 向其他方向变基,这会导致灾难。
有关合并与变基差异的更多信息,请阅读此答案What's the difference between 'git merge' and 'git rebase'?
You finish working on the feature branch, commit your changes and then merge/rebase it onto master.
Where in the master branch are the feature commits inserted, before or after the pulled commits?
After: merge/rebase 将考虑 master 分支的当前状态。
如果该分支已经发展(通过拉取),那么 merge/rebase 将使用当前的主 HEAD(现在引用拉取的提交)
Where are they inserted if you never performed a pull?
相同:它将使用当前的主 HEAD(不反映任何新的提交,因为没有完成拉取)
Will it have the same result?
不,考虑到两种情况下 master HEAD 不同。
Also, what happens if you merge/rebase master onto the feature branch instead of the other way around?
首先,不要这样做:这不是最佳做法。
但如果这样做,merge/rebase 将使用 HEAD 功能。
Where is master inserted into the feature branch if you merged/rebase before or after the pull? Will it have the same result?
相同的结果,因为在这两种情况下,它都使用了 HEAD 功能,当您执行(或不执行)拉取 master 时,该功能没有改变。
TL;DR
Moreover, we normally tend to think of revisions as occurring in chronological sequence and expect Git to work the same way.
这是一个可怕的错误。 Git 按 图顺序 ,而不是时间顺序。当图形顺序是按时间顺序排列时——有时但并非总是如此——然后它工作正常。
长
(我什至不打算在这里触及 rebase。有关 rebase 的适当讨论,请参阅之前的帖子。我将专注于合并中的对称性,以及接缝可以显示的地方.)
More succinctly, do the direction of the merge and or order of the merge have different outcomes on the resulting merge? I suspect it doesn't matter.
答案既不是也不是。
要理解为什么这是答案,您需要了解关于Git的几件事。
首先,让我们考虑一下 Git 如何处理提交,与其他人做对比(大多数其他人?所有其他人?必须至少有一个其他 VCS 也这样做......)。在版本控制系统中,在 b运行ch 中提交的过程将新提交 添加到 b运行 ch;但是在 Git 中,包含提交 一旦提交 的 b运行 集合可以是,并且是动态变化的东西。也就是说,一旦提交,独立于任何 b运行ch,并且如果您愿意,可以在 no[=191] 上提交=] b运行ch.
例如,在 Mercurial 中,这是完全不可能的。虽然 Mercurial 在许多方面与 Git 非常相似,但提交 的存在需要 其 b运行ch 的存在。提交是在 on that b运行ch 上进行的,并且永远是 的 b运行ch 的一部分。这是保存提交的 only b运行ch:提交永久附加到其 b运行ch.
在Git和Mercurial中,每个提交都有一个唯一的ID,每个提交存储其parent(单数)提交的唯一ID ,如果是普通提交。通过遵循这个 backwards-looking 链,从 last 提交开始并向后工作,我们可以找到 b运行ch 上的提交历史:
... <-grandparent <-parent <-child
在 Mercurial 中,这些提交永远在它们的 b运行ch 上,所以我们可以在左边写上 b运行ch 名称:
branch-A: ...--I--J
在 Mercurial 中查找最新的提交很容易,因为提交在本地存储库中有一个简单的序列号(以及用于在存储库之间共享的唯一哈希 ID)。
在 Git 中,b运行ch names 是可移动的。在提交 J
存在之前,名称 branch-A
存储提交 I
:
...--H--I <-- branch-A
进行新提交时,Git 只需将新提交的哈希 ID 写入 b运行ch 名称,以便 b运行ch 指向新提交:
...--H--I--J <-- branch-A
合并既是名词又是动词
在版本控制中,合并动词,或合并一些提交,是一个过程。结果——至少在 Git 和 Mercurial 中——是一个 merge commit,我们使用 merge 这个词作为形容词修改commit,或简称,a merge(名词)。
合并提交 成为 合并提交的原因是它们有 两个 parent,将两条开发线放在一起:
...--I--J
\
M
/
...--K--L
在这里,Git 和 Mercurial 基本相同,有一个非常重要的区别:在 Mercurial 中,合并提交专门针对 one b运行ch,当你 运行 hg merge
时,无论你在哪个 b运行ch。提交——包括合并提交——永久地附在它们的 b运行ches 上。一旦合并过程完成并且存在合并提交,合并提交就在那个 b运行ch 上。在 Git 中,合并提交进入当前 b运行ch,但是因为我们可以移动 name,所以在某种意义上这并不重要。
但我们必须同时查看两个部分:动词部分 to merge,然后仔细查看名词部分 a merge. (旁白:Git 还允许合并提交有 超过两个 parent,而 Mercurial 将每个合并限制为两个 parent。没有什么这些时髦的合并,Git 调用 octopus 合并 ,可以做到你不能用一系列成对合并做的事情,但章鱼合并在某些情况下可以更清楚地显示意图.)
要合并,动词
例如,假设 branch-A
和 branch-B
在合并之前是这样的:
...--I--J <-- branch-A
...--K--L <-- branch-B
在我们合并这些之前,我们必须追溯两个历史足够远才能找到合并基础,共同提交来自这两条发展路线发生了分歧。 (在 Mercurial 中也是如此。)所以让我们再补充一点:
I--J <-- branch-A
/
...--H
\
K--L <-- branch-B
在这里,commit H
是共同的起点。在 Git 中,提交 H
同时在 两个 b运行 上 (但不是在 Mercurial 中)。小号生病了,两个版本控制系统都以几乎相同的方式执行 合并 过程:您首先选择一个提交来检出,例如使用 [=30 提交 J
=] 或 hg update branch-A
。然后使用命令的 merge
动词选择另一个提交:git merge branch-B
或 hg merge branch-B
。 VCS 找到合适的合并基础,即提交 H
,并将 H
的内容与 J
的内容进行比较,以查看 you更改:
git diff --find-renames <hash-of-H> <hash-of-J> # what we changed
并重复相同的比较以找出 他们 改变了什么:
git diff --find-renames <hash-of-H> <hash-of-L> # what they changed
Git 将这些更改合并为一个大的 "all changes",将这些更改应用到 base(提交 H
),并使新提交。
(Mercurial 做的大致相同,尽管在 Mercurial 如何知道重命名方面存在一些非常重要的差异。这些仅在您自合并基础后重命名了一些文件时才重要。如果您 重命名文件,并且有 rename/rename 冲突,合并顺序变得非常重要。但我们假设没有重命名问题。)
这里最有趣的事情是您可以控制如何更改组合。在 Git 中,您可以通过 合并策略 和 扩展策略参数 执行此操作;在 Mercurial 中,您可以通过选择的 合并工具 来完成此操作。如果您使用 "ours" strategy/tool,VCS 会完全忽略它们的更改:合并后的更改只是 您的 更改,因此 VCS 使用与当前提交中的代码相同。这里的合并顺序显然很重要:如果我们忽略 他们的 更改,我们最好确定谁是 "us"!
即使没有 "ours" 策略,您的更改和他们的更改之间也可能存在冲突。如果是这样,Git 和 Mercurial 都可以被告知:更喜欢我的 或 更喜欢他们的。这些会给出不同的结果,所以在这里,合并顺序再次很重要。当然,此时有一个对称选项:选择我的或选择他们的。如果你交换角色,你可以交换选项——所以虽然顺序很重要,但它并不那么重要。
合并,名词
让我们假设没有冲突,也没有特殊的 ours/theirs 事件,并且 运行 git checkout branch-A; git merge branch-B
。如果一切顺利,VCS 将合并提交 M
及其两个 parents:
I--J
/ \
...--H M <-- branch-A
\ /
K--L <-- branch-B
在 Mercurial 中,合并顺序在这里很重要,因为一旦提交 M
,它就会永远停留在它的 b运行ch 上。但是 Git 允许我们 在事后移动 b运行ch names。我们可以把M
做成这样,放在原处,把branch-A
往后推一步,再次指向J
,然后把branch-B
向前移动,指向M
,给出:
I--J <-- branch-A
/ \
...--H M <-- branch-B
\ /
K--L
这与我们 git checkout branch-B; git merge branch-A
得到的结果几乎相同。所以看起来在这里,合并顺序是无关紧要的(前提是 verb 部分没有任何障碍)。但是这里的图表中缺少一些东西,那就是 first 和 not-first parents![= 的概念55=]
合并提交M
的第一个parent,在Git和Mercurial中,是"same branch"parent。也就是说,由于我们在 运行 合并时提交 J
,因此 M
的 first parent 是提交 J
。这使得 L
成为 第二个 parent。如果我们将 b运行ch 标签推到 Git 周围,我们可以知道我们已经这样做了,因为第一个和第二个 parents 仍然是另一个顺序。
所以我们在这里看到对于 Git,即使 to merge 动词没有顺序问题,结果 merge commit(形容词或名词)确实有一个命令。由您(用户)决定该订单对您是否重要。如果不是,则对称性可用。如果提交 parent 顺序很重要,那么合并的 direction/order 在 Git 中和在 Mercurial 中一样重要。
图表是关键
在任何 graph-based 版本控制系统中——因此在 Git 和 Mercurial 中——图表 是 历史。特别是在 Git 中,没有 文件历史这样的东西; 该图不仅是 主要 历史,而且是 只有历史。 (Mercurial 以更常规的方式存储文件数据,因此既有提交历史 也有 文件历史,但无论如何如果没有提交历史,文件历史也没有用。)
为了能够理解 Git 的作用和原因,您需要了解足够的图论来驾车或骑车 public t运行 坐在城市周围。这并不是那么多——但如果你没有意识到 Git 有这些 one-way 铁轨/街道/桥梁,从 last 提交回来迈向第,很多事情就没有意义了。 Git 开始一个结束,然后倒退到开始。 b运行ch 名称让您进入图表,在 branch-tip 结束。其他一切都是提交图的函数。
TLDR:
Merge
, merges argument branches into checkout branch,rebase
, rebase puts checkout branch on top of argument branch (ie, ahead of, in the future, nearest to now)
合并会影响结帐分支标签的推进,顺序无关紧要
例如,提供给 git merge A B
的分支将合并到结帐分支中
(没什么大不了的,如果你写错了) 提示:git branch -f <oops-branch> <go-back-to-commit> # don't be on oops-branch
这样做
99% 的时间你想要做的是检查一些分支 git checkout A
然后将另一个分支合并到它 git merge B
✅ $ git merge B #I am on branch A, megre B into A
分支 A 标签被推进到合并提交,而 B 不是。
Rebase 顺序影响哪些提交被重写
(有点大不了,但你可以从错误中恢复) 提示:git branch -f <oops-branch> <go-back-to-commit> # don't be on oops-branch
这样做
99% 的时间你只想使用 rebase 将更改从一个分支拉到你的开发分支。此 rebase
语法与上面显示的惯用合并方式相反(即,检查分支“A”然后 merge
分支 'B' 进入 'A')
rebase
想象一下在一根棍子上烤棉花糖,最后一个棉花糖堆在前一个上面。这就是 rebase
语法的工作原理。
✅ $ git rebase main dev #I am on branch main but it doesn't matter what branch I am on bc I've explicitly told git the rebase order, rebase dev on top of main
不要这样做
你能看出这里的问题吗?
❌$ git rebase dev #I am on branch main, rebases main on top of dev