Mar*_*ger 10
在查看了 torek 的答案,然后重新阅读了问题之后,我正在更新以澄清几点......
- 合并到分支与重新建立分支时的冲突数量有什么区别吗?这是为什么?
可能是的,出于多种原因。最简单的是,合并过程仅查看三个提交 - “我们的”、“他们的”和合并基础。所有中间状态都被忽略。相比之下,在变基中,每次提交都会转换为补丁并单独应用,一次一个。因此,如果第三次提交创建了冲突,但第四次提交撤消了冲突,则 rebase 将看到冲突,而 merge 则不会。
另一个区别是提交是否被精心挑选或以其他方式在合并的两侧重复。在这种情况下,rebase通常会跳过它们,而它们可能会导致合并中的冲突。
还有其他原因;最终,它们只是不同的过程,尽管它们通常会产生相同的组合内容。
- 进行合并时,合并更改存储在合并提交本身(具有两个父级的提交)中。但是当进行变基时,合并存储在哪里?
合并的结果存储在 rebase 创建的新提交中。默认情况下,rebase 会为每个被 rebase 的提交写入一个新的提交。
正如托雷克在他的回答中解释的那样,这个问题可能表明对合并中存储的内容存在误解。可以解读该问题来断言导致合并结果的更改集(“补丁”)显式存储在合并中;他们不是。与任何提交一样,合并是内容的快照。使用其父指针,您可以找出已应用的补丁。在变基的情况下,git 不会显式保留有关原始分支点、哪些提交位于哪个分支或它们重新集成的位置的任何信息;因此,每个提交的更改都保留在该提交与其父级的关系中,但是在变基之后没有通用方法可以重建与相应合并关联的两个补丁,除非您拥有存储在存储库中之外的其他知识。
例如,假设您有
O -- A -- B -- C <--(master)
\
D -- ~D -- E -- B' -- F <--(feature)
Run Code Online (Sandbox Code Playgroud)
其中D与 的变化发生冲突master,~D恢复D,并且是对进行B'挑选的结果。Bfeature
现在,如果您合并feature到master,则合并仅查看 (1) 与 有何F不同O,以及 (2) 与 有何C不同O。它不会“看到”来自 的冲突D,因为~D反转了冲突的更改。它将看到B和B'都改变了相同的行;它可能能够自动解决这个问题,因为双方都进行了相同的更改,但根据其他提交中发生的情况,这里可能会发生冲突。
但一旦任何冲突得到解决,你最终会得到
O -- A -- B -- C -------- M <--(master)
\ /
D -- ~D -- E -- B' -- F <--(feature)
Run Code Online (Sandbox Code Playgroud)
并且,正如您所指出的,M包含合并的结果。
回到原来的画面……
O -- A -- B -- C <--(master)
\
D -- ~D -- E -- B' -- F <--(feature)
Run Code Online (Sandbox Code Playgroud)
...如果您改为 rebasefeature到master,这几乎就像一次逐步将每个feature提交与一个提交合并。master你可以粗略地想象你一开始是这样说的
git checkout master
git merge feature~4
Run Code Online (Sandbox Code Playgroud)
这会产生冲突。你解决了这个问题,然后得到
O -- A -- B -- C -- M <--(master)
\ /
-------------- D -- ~D -- E -- B' -- F <--(feature)
Run Code Online (Sandbox Code Playgroud)
然后您可以继续进行下一次提交
git merge feature~3
Run Code Online (Sandbox Code Playgroud)
这可能会或可能不会冲突,但是当你完成后你会得到
O -- A -- B -- C -- M -- M2 <--(master)
\ / /
-------------- D -- ~D -- E -- B' -- F <--(feature)
Run Code Online (Sandbox Code Playgroud)
并且,如果您正确解决了任何冲突,M2则应具有与 相同的内容C。那你就做吧E。
git merge feature~2
Run Code Online (Sandbox Code Playgroud)
B'有点不同,因为 rebase 会跳过它;所以你可以做
git merge -s ours feature~1
Run Code Online (Sandbox Code Playgroud)
最后
git merge feature
Run Code Online (Sandbox Code Playgroud)
你最终会得到
O -- A -- B -- C -- M -- M2 -- M3 -- M4 - M5<--(master)
\ / / / / /
-------------- D -- ~D -- E -- B' -- F <--(feature)
Run Code Online (Sandbox Code Playgroud)
(其中M4是“我们的”合并,因此M4与 具有相同的内容M3)。
所以变基很像,除了它不跟踪将新提交链接回分支的“第二父”指针feature,并且它完全跳过B'. (而且它以不同的方式移动树枝。)所以我们画
D' -- ~D' -- E' -- F' <--(feature)
/
O -- A -- B -- C <--(master)
\
D -- ~D -- E -- B' -- F
Run Code Online (Sandbox Code Playgroud)
因此我们可以直观地表明D'“来自” D,即使它不是带有显示其与 的关系的父指针的合并提交D。尽管如此,这仍然是存储合并这些更改的结果的地方;并最终F'存储两个历史的完整整合。
如上所述,存储库的最终状态(变基后)中没有任何内容可以清楚地表明哪些补丁将与(大致等效)合并相关联。您可以git diff O C查看其中之一,并git diff C F'查看另一个,但您需要 git 不保留的信息才能知道O、C、 和F'是相关提交。
请注意F,在这张图片中,这是无法访问的。它仍然存在,您可以在转发日志中找到它,但除非有其他东西指向它,否则gc最终可能会毁掉它。
另请注意,变基feature到master不会提前master。你可以
git checkout master
git merge feature
Run Code Online (Sandbox Code Playgroud)
to ff masteronfeature完成分支的整合。
变基(大部分)只是一系列精选。樱桃选择和合并都使用相同的逻辑 \xe2\x80\x94 我称之为“合并逻辑”,文档通常称之为“3路合并” \xe2\x80\x94 来创建新的提交。
\n该逻辑是,给定提交 X 和 Y:
\n从较早的提交开始。这称为合并基础。
\n区分早期提交和 X。
\n区分早期提交和 Y。
\n将两个差异应用于较早的提交,并且:
\nA。如果你能做到这一点,请进行一个新的提交来表达结果。
\nb. 如果你做不到,就抱怨你们之间有冲突。
\n在这方面,合并和cherry-pick(因此合并和变基)几乎是是相同的事情,但也有一些区别。一个极其重要的区别是“3路合并”逻辑中的“3”是谁。特别是,他们对于第一步(合并基础)中的“早期提交”是谁有不同的想法。
\n让我们首先看一个退化的例子,其中合并和樱桃选择几乎相同:
\nA -- B -- C <-- master\n \\\n F <-- feature\nRun Code Online (Sandbox Code Playgroud)\n如果将功能合并到主控中,Git 会查找功能和主控最近分歧的提交。那是 B。它是我们的合并逻辑 \xe2\x80\x94 合并基础中的“早期提交”。因此,Git 将 C 与 B 进行比较,将 F 与 B 进行比较,并将这两个差异应用于 B 以形成新的提交。它给出了该提交的两个父项,C 和 F,并移动master指针:
A -- B - C - Z <-- master\n \\ /\n \\ / \n F <-- feature\nRun Code Online (Sandbox Code Playgroud)\n如果您将功能挑选到 master 上,Git 会查找功能的父级,即 F 的父级。这又是 B!(那是因为我故意选择了这种退化的情况。)这就是我们的合并逻辑中的“早期提交”。因此,Git 再次将 C 与 B 进行比较,将 F 与 B 进行比较,并将这两个差异应用于 B 以形成新的提交。现在它给该提交一个父级 C,并移动master指针:
A -- B - C - F' <-- master\n \\ \n F <-- feature\nRun Code Online (Sandbox Code Playgroud)\n如果将功能变基到 master,git 会对功能上的每个提交进行挑选并移动feature指针。在我们的退化案例中,只有一项功能提交:
A -- B - C <-- master\n \\ \\\n \\ F' <-- feature\n F\nRun Code Online (Sandbox Code Playgroud)\n现在,在这些图中,充当合并基础的“早期提交”在每种情况下都是相同的:B。因此,在每个图中,合并逻辑是相同的,因此发生冲突的可能性是相同的。
\n但如果我在功能上引入更多提交,事情就会发生变化:
\nA -- B -- C <-- master\n \\\n F -- G <-- feature\nRun Code Online (Sandbox Code Playgroud)\n现在,将功能变基到主版本意味着将 F 挑选到 C 上(给出 F'),然后将 G 挑选到 C 上(给出 G')。对于第二个选择,Git 使用 F 作为“早期提交”(合并基础),因为它是 G 的父级。这引入了我们之前没有考虑过的情况。特别是,合并逻辑将涉及从 F 到 F' 的差异,以及从 F 到 G 的差异。
\n因此,当我们变基时,我们沿着变基分支迭代地挑选每个提交,并且在每次迭代中,在合并逻辑中比较的三个提交都是不同的。很明显,我们引入了合并冲突的新可能性,因为实际上,我们正在进行更多不同的合并。
\n| 归档时间: |
|
| 查看次数: |
4758 次 |
| 最近记录: |