Dun*_*nes 6 git git-merge squash git-squash
I use an optimistic work-flow in Gitlab, which assumes the majority of my merge requests will be accepted without change. The flow looks like this:
cool-feature-Acool-feature-A, called cool-feature-B. Begin developing on this branch.cool-feature-A.cool-feature-B反对master(这是无痛的)并继续开发。如果同事在第 3 步进行壁球合并,就会出现问题。这会重写cool-feature-B. 当我到达第 4 步时,我面前是一个合并痛苦的世界。
我怎样才能避免这种情况发生?
tor*_*rek 17
本质上,您必须告诉 Git: 我想cool-feature-B针对进行变基master,但我想复制与您通常在此处计算的提交不同的一组提交。 最简单的方法是使用--onto. 也就是说,通常你会跑,正如你所说:
git checkout cool-feature-B
git rebase master
Run Code Online (Sandbox Code Playgroud)
但你需要做:
git rebase --onto master cool-feature-A
Run Code Online (Sandbox Code Playgroud)
在删除自己的 branch-name / label 之前cool-feature-A。
即使他们使用普通合并,您也可以随时执行此操作。 这样做不会有什么坏处,除了您必须键入更多内容并记住(无论您喜欢什么),稍后您将需要 this --onto,它需要正确的名称或哈希 ID。
(如果您可以获得当前cool-feature-A指向 的 reflog的提交的哈希 ID cool-feature-B,您可以使用该--fork-point功能让 Git 稍后自动为您计算,前提是相关的 reflog 条目尚未过期。但总的来说,这可能比手动执行此操作更难。另外,它具有整个“提供”部分。)
让我们像往常一样从图形开始。最初,您在自己的存储库中有此设置:
...--A <-- master, origin/master
\
B--C <-- cool-feature-A
\
D <-- cool-feature-B
Run Code Online (Sandbox Code Playgroud)
运行后git push origin cool-feature-A cool-feature-B,您将拥有:
...--A <-- master, origin/master
\
B--C <-- cool-feature-A, origin/cool-feature-A
\
D <-- cool-feature-B, origin/cool-feature-B
Run Code Online (Sandbox Code Playgroud)
请注意,我们在这里所做的只是添加了两个origin/名称(两个远程跟踪名称):在他们的存储库中,在 at 上origin,他们获取了 commits B, C, Dand 他们将它们的 cool-feature-A和cool-feature-B名称分别设置为记住提交C和D,因此您自己的 Git 添加了您的 origin/变体这两个名字中。
如果他们(无论“他们”是谁——控制存储库的人origin)进行快进合并,他们就会将他们的master 向上滑动以指向 commit C。(请注意,GitHub Web 界面没有进行快进合并的按钮。 我没有使用过 GitLab 的 Web 界面;它可能以各种方式不同。)如果他们强制进行真正的合并——这就是 GitHub 网页“立即合并”clicky 按钮默认执行;再说一次,我不知道 GitLab 在这里做了什么——他们会做一个新的合并提交E:
...--A------E
\ /
B--C
\
D
Run Code Online (Sandbox Code Playgroud)
(这里我故意去掉了所有的名字,因为他们的名字和你的不太匹配)。他们大概会删除(甚至可能从未真正创建)他们的cool-feature-A名字。无论哪种方式,您都可以使用自己的 Git 快进您的 master名称,同时更新您的origin/*名称:
...--A------E <-- master, origin/master
\ /
B--C <-- cool-feature-A [, origin/cool-feature-A if it exists]
\
D <-- cool-feature-B, origin/cool-feature-B
Run Code Online (Sandbox Code Playgroud)
或者:
...--A
\
B--C <-- cool-feature-A, master, origin/master [, origin/cool-feature-A]
\
D <-- cool-feature-B, origin/cool-feature-B
Run Code Online (Sandbox Code Playgroud)
无论你cool-feature-A现在是否删除你的名字——为了方便以后的绘图,假设你删除了——如果你运行:
git checkout cool-feature-B
git rebase master
Run Code Online (Sandbox Code Playgroud)
Git 现在将枚举从D- D、 then C、 thenB等可访问的提交列表,并减去可从master以下内容访问的提交列表:(E如果存在),则A(如果E存在)和C(无论是否E存在),然后B, 等等。减法的结果就是 commit D。
你的 Git 现在复制这个列表中的提交,以便新的副本出现在 : 的提示之后,master即在E他们进行真正的合并之后,或者在C他们进行快进合并之后。所以 Git 要么复制D到一个新的提交D',在E:
D' <-- cool-feature-B
/
...--A------E <-- master, origin/master
\ /
B--C
\
D <-- origin/cool-feature-B
Run Code Online (Sandbox Code Playgroud)
或者它D独自离开,因为它已经出现了C(所以没有什么新东西可以画)。
当他们使用 GitLab 的任何等效项是 GitHub 的“挤压和合并”或“变基和合并”点击按钮时,就会出现棘手的部分。我将跳过“rebase 和合并”案例(这通常不会导致问题,因为 Git 的 rebase 也会检查补丁 ID)并直接进入硬案例,即“挤压和合并”。正如您正确指出的那样,这会产生一个新的、不同的、单一的提交。当您将新提交带入您自己的存储库时 - 例如,之后git fetch- 您拥有:
...--A--X <-- master, origin/master
\
B--C <-- cool-feature-A [, origin/cool-feature-A]
\
D <-- cool-feature-B, origin/cool-feature-B
Run Code Online (Sandbox Code Playgroud)
whereX是进行新提交的结果,其快照将匹配 merge E(如果他们要进行 merge E),但其(单个)父项是现有 commit A。所以历史——通过向后工作枚举的提交列表——来自X只是X, then A, then 任何提交到之前A。
如果您git rebase master在 on 上定期运行cool-feature-B,Git:
D以下位置访问的提交:D, C, B, A, ...;X: X, A, ...;访问的提交D, C, B;X.请注意,第 2 步和第 3 步都使用该词master来查找提交:对于第 2 步,要复制的提交是那些无法从master. 对于步骤 3,放置副本的位置在的尖端之后master。
但是如果你运行:
git rebase --onto master cool-feature-A
Run Code Online (Sandbox Code Playgroud)
你让 Git在步骤 2 和 3 中使用不同的项目:
cool-feature-A..cool-feature-B:subtract C-B-A-...from D-C-B-A-...。那只剩下 commit 了D。--onto master: put them after X。所以现在 Git 只复制D到D',然后git rebase将名称拉到cool-feature-B指向D':
D' <-- cool-feature-B
/
...--A--X <-- master, origin/master
\
B--C <-- cool-feature-A [, origin/cool-feature-A]
\
D <-- origin/cool-feature-B
Run Code Online (Sandbox Code Playgroud)
这就是你想要的。
如果他们——控制 GitLab 存储库的人——使用了真正的合并或快进而不是真正的合并,这一切仍然有效:你会让你的 GitD向后枚举,但是C从列表中删除-on-backwards,只留下D复制;然后 Git 会复制,D以便在E(真正的合并情况)或C(快进情况)之后出现。在快进的情况下,“复制 D 使其到达它所在的位置”,它会巧妙地根本不费心去复制,而将所有内容留在原处。
| 归档时间: |
|
| 查看次数: |
4228 次 |
| 最近记录: |