gpt4 book ai didi

git - 如何在父级 merge 后处理主题分支的 merge

转载 作者:行者123 更新时间:2023-12-02 21:02:51 24 4
gpt4 key购买 nike

假设我有以下场景:

A -- B -- C -- D -- H master
\ /
E -- F -- G topicA
\
I -- J -- K topicB
topicA并入 master使用 --squash 开关,这意味着 master不知道历史 topicA .

如果我现在 merge master进入 topicB然后做一个 diff master...topicB差异搞砸了,包含许多不应该存在的更改或撤消。

在那种情况下,我通常会 merge master进入 topicA然后 topicA进入 topicB在做上一段所说的事情之前。但是,有时这是不可能的(例如,分支被删除)并且我以很多冲突结束。

在这种情况下我应该如何处理?我有什么误解吗?

rebase --onto master topicA topicB正确的解决方案?

最佳答案

DavidN said in a comment ,你的计划看起来很合理。

(剩下的内容太长太乱了;它是在其他任务之间/期间写的。)

题外话和细节

Hgit merge --squash 创建,画错了。它应该是:

A -- B -- C -- D -- H master
\
E -- F -- G topicA
\
I -- J -- K topicB

关键区别在于提交 HE--F--G无关序列,至少不是在任何 Git 检测到的意义上。提交 H的内容受 E--F--G 中发生的任何事情的影响序列(当然,根据 C--D 序列中发生的任何事情)但据 Git 现在所知,有人来写 H连看都不看 E--F--G .

我现在将在这里有一个相当大的题外话。

If I now merge master into topicB



如果您进行了真正的 merge

好的,让我们将其绘制为提交图,以确保这意味着您的意图。我将使用我通常的形式(稍微紧凑一点,分支名称的箭头向右移动一点):
A--B--C---D----H       <-- master (still points to H)
\ \
E--F--G \ <-- topicA (still points to G)
\ \
I--J--K--L <-- topicB (points to new L)

请注意,我画了一个真正的 merge ,而不是一个假的、根本不是 merge 的“ Squash merge ”。正如我们将看到的,这确实很重要。

当 Git 进行这个新的提交时 L ,它必须 merge 提交 HK .为此,它必须找到它们的 merge 基础(在某些情况下可能有多个 merge 基础,但这里只有一个)。

任何两个提交的 merge 基础是/是最低公共(public)祖先:也就是说,最接近两个起始提交( HK )的提交,这些起始提交都可以访问。

让我们从 H 开始和 K自己先。 H可从 H 到达(当然)但不是来自 K . K可从 K 到达(当然)但不是来自 H .现在我们可以查看 D对比 HK : D可从 H 到达但不是来自 K .现在我们可以查看 J ,但无法从 H 访问.现在我们考虑 CI , 和 F , 和 E ,但直到我们一路回到提交 B我们发现可以从 H 访问提交和 K .提交 A也可以,但它离 H 都远了和 K ,所以提交 B是 merge 基础。

然后 merge 以两个差异开始:
git diff B H


git diff B K

第一个差异显示了我们从 B 开始的更改至 H .当然, H有我们在 C 中更改的内容和 D ,加上我们在 E 中所做的任何更改, F , 和 G .第二个差异显示了我们从 B 开始的更改至 K .当然, K有我们在 E 中更改的内容,加上我们在 I--J--K 中所做的任何更改.

这有我们在 E 中所做的更改两次,但 Git 通常——不总是,但通常——能很好地注意到这一点,并且只接收一次更改。所以提交 L可能拥有之前每次提交的所有内容,只完成一次。

and then do a diff master...topicB



请注意,这是使用三点 ...语法,而不是两点 ..句法。我不确定你在这里打算做什么,但三点语法本质上意味着“找到(或一个) merge 基础”。那么让我们再次进行这个练习: master仍然指向提交 HtopicB现在指向新的 merge 提交 L ,我们找到了 H 的 merge 基和 L ,现在我们有一个真正的 merge (对我们来说没有这种愚蠢的“ Squash merge ”假 merge 东西,不可能!)。

所以让我们从 H 开始和 L自己先。 L可从 L 到达(当然)但不是来自 H . H可从 H 到达(当然)也来自 L .这意味着 H 的 merge 基础和 LH : master的 merge 基础和 topicB是主人。

... diff master...topicB



master位于三点的左侧,它被替换为 merge 基础,即提交 H .三点的右侧被解析为其提交,即提交 L .然后差异会向您显示 H 之间的任何不同。和 L .

在这种情况下,效果与 git diff master..topicB 相同, 与 git diff master topicB 意思相同: 比较提交 HL , 以该顺序。

这应该是一个非常合理的差异,尽管我们最初是为了制作 H 而做了可怕的假 Squash merge 。 .真正的 merge 修复了这个问题,至少对于 H对比 L .

如果你做了一个虚假的、非 merge 的“ Squash merge ”

让我们再次绘制这个东西,但这次使用假的 not-a-merge git merge --squash技术。我们新提交的内容 L将与我们进行了真正的 merge 相同,但图形会有所不同:
A--B--C---D----H       <-- master (still points to H)
\
E--F--G <-- topicA (still points to G)
\
I--J--K--L <-- topicB (points to new L)

现在我们回到:

diff master...topicB



再一次,我们需要找到 H 之间的 merge 基数。和 L ,但现在 L不指向两者 KH ,但仅限于 K .都没有 H也不是 L是 merge 基础。都没有 D也不是 J要么工作:我们不能倒退到 D来自 L ,我们不能倒退到 J来自 H .实际上, merge 基础提交再次提交 B ,所以这意味着同样的事情:
git diff B L

这个差异会大不相同。

我不知道你对你的差异有什么期望,所以我无法解决这一部分:

the diff is messed up and contains a lot of changes or undoings which shouldn't be there.



回到 merge 、 rebase 等。

现在让我们回到问题:

In that case, I usually merge master into topicA and then topicA into topicB before doing what was said in the previous paragraph. However, sometimes that it's not possible (e.g. the branch was deleted) and I end with a lot of conflicts.



请注意,删除分支名称对其提交没有立即影响。它所做的是停止保护这些提交。也就是说,因为每个分支名称都使提交可访问,所以这些提交对于 Grim Collector 来说是安全的……呃……Grim Reaper Garbage Collector。我们做了几次可达性的事情来寻找 merge 基础;然而,在 GC 期间,Git 更频繁地查找要保留的提交和要丢弃的提交; promise 转让,期间 pushfetch ;等等。如果提交受到其他方式的保护——通过真正的 merge 的可达性,或者来自另一个分支或标签名称的可达性,或者其他什么——它们会留下来。如果您可以通过哈希 ID 找到它们,则可以将它们带回来。

更重要的是您的 rebase案例,如果您可以通过 git log 找到它们,你可以剪掉它们。稍后我们将看到这一点。

Squash “merge ”的一般考虑

因为 Squash “merge ”实际上根本不是 merge ,因此它们不会保护其他提交链,并且— 这通常是 future merge 冲突的关键 —它们不提供具有更新 merge 基础的 future merge 。这意味着那些 future 的 merge 必须检查巨大的差异,而不是小的差异,然后 Git 的自动“冗余更改”检测失败。

这在实践中意味着什么取决于您如何使用这些 Squash 非 merge “merge ”。当您使用它们进行一条开发线并将其减少为单个提交时,完全停止使用另一条开发线可能是个好主意。您可以保存它(使用分支或标签名称,甚至是分支和标签 namespace 之外的其他一些引用,以便您通常不会看到它,从而防止提交链被 GC 处理)或只是让它得到收获了,但无论哪种方式,您都可能不应该继续处理它,这包括您从某些提交中分出的任何其他分支。

使用 git rebase

Is rebase --onto master topicA topicB the right solution?



使用 git rebase ,您可以复制这些其他链—您的 topicB ,在这种情况下 - 指向新链,然后将标签 ( topicB ) 指向复制链的尖端。你想要复制的提交是那些没有被压缩的提交:这里是 I--J--K链。使用 topicA<upstream>论据 git rebase将选择正确的提交集。请注意 topicA达到提交 G , F , E , B , 和 A , 而 topicB到达 K , J , I , F , E , 等等;所以使用 topicA<upstream>F 砍掉所有东西在后面,但随后需要显式 --onto你提供的。

如果标签 topicA被删除了,你仍然可以做这个 rebase,它只是变得更棘手。您需要做的是指定任一提交 GF通过它们的散列 ID,以便切断提交 F和更早。 G的哈希ID从难以找到(GC 没有删除它,但无法从任何实时引用访问)到不存在(GC 已删除它)。 F 的 ID然而,就在 topicB 中链条: K的 parent 是 J , J的 parent 是 I , 和 I的 parent 是 F .问题是 没有简单的方法可以确定提交 F位于早先 git merge --squash 的链中的一组提交中处理。

(这与我之前加粗的评论有关,但并不完全相同。)

关于git - 如何在父级 merge 后处理主题分支的 merge ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38644232/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com