当现有的提交哈希值发生变化时,重新设置基础(Rebasing)是什么?

5

我正在尝试了解我们团队最近遇到的一个git问题。我们有几层分支:

-> Master
   |-> Feature Branch
        |-> Individual developer branches

小组开发者会从一个功能分支开始工作,同时我们会有几个不同的功能分支。当一个功能分支与主分支合并时,功能分支的拥有者将会进行 “变基” 操作。但是经常会出现合并冲突,因为有些工作已经被合并到了功能分支中。
在解决合并冲突时,变基操作通常会更改提交哈希值。
当一个独立的开发者想把功能分支合并到他们自己的开发分支中时,实际上有两个提交哈希值,这样就会导致同一项内容有两个不同的提交哈希值:
1. 旧的提交哈希值 (在变基和合并冲突之前) 2. 新的提交哈希值 (在变基之后)
当这个开发者试图将其分支与功能分支进行比较时,旧的提交哈希会被认为是新的工作并且会“弄脏”拉取请求。
我可以通过让他们从最新的功能分支创建一个新的分支,并选择他们自己的工作来轻松地解决这个问题。这样就可以丢弃旧的提交哈希,但这不是很高效。
是否有任何更改我们的做法或以不同的方式进行变基的方法,以便我们可以在开发者分支中排除“更改”的提交哈希值呢?

你提到了一个拉取请求,你是用Github吗?你能详细解释一下“污染拉取请求”的含义吗? - Schwern
我们正在使用GitHub企业版,但这与问题无关。比较开发者分支和特性分支将显示要合并的提交列表已经存在 - 只是Git不再识别提交哈希值。 - helion3
1个回答

5
TL;DR版本:让每个人使用git pull --rebase
如果我理解正确,您的情况是这样的。
A - B - C [m]
     \
      D - E - F [f]
           \
            G - H - I [d]

m表示主分支,f表示特性分支,d表示���发分支。你想要能够将f分支rebase到m分支上,也希望能够将d分支rebase到新的f分支上。

                     G1 - H1 - I1 [d]
                     /
          D1 - E1 - F1 [f]
         /
A - B - C [m]
     \
      D - E - F
           \
            G - H - I

答案是让每个人运行git pull --rebase,这相当于运行git fetchgit rebase。下面是它的工作原理。在主分支(commit C)有新工作推送后,仓库将如下所示。
origin
A - B - C [m]
     \
      D - E - F [f]
           \
            G - H - I [d]

feature branch maintainer
A - B [m][o/m]
     \
      D - E - F [f][o/f]
           \
            G - H - I [o/d]

dev branch maintainer
A - B [m][o/m]
     \
      D - E - F [o/f]
           \
            G - H - I [d][o/d]

特性分支的维护者决定更新,因此他们执行 git pull --rebase origin master 命令。这会执行 git fetch origingit rebase origin/master 命令,结果如下。

feature branch maintainer
             D1 - E1 - F1 [f]
            /
A - B [m]- C [o/m]
     \
      D - E - F [o/f]
           \
            G - H - I [o/d]

然后他们会执行git push origin命令(我相信他们需要强制执行),这是结果。
origin
             D1 - E1 - F1 [f]
            /
A - B - C [m]
     \
      D - E
           \
            G - H - I [d]

feature branch maintainer
             D1 - E1 - F1 [f][o/f]
            /
A - B [m]- C [o/m]
     \
      D - E
           \
            G - H - I [o/d]

dev branch maintainer
A - B [m][o/m]
     \
      D - E - F [o/f]
           \
            G - H - I [d][o/d]

现在,dev分支的维护者想要更新,却毫不知情feature分支发生了什么。他们使用git pull --rebase命令,它等同于git fetch origingit rebase origin/feature命令。在执行fetch命令后,结果如下所示。

dev branch maintainer
             D1 - E1 - F1 [o/f]
            /
A - B [m]- C[o/m]
     \
      D - E
           \
            G - H - I [d][o/d]

然后执行git rebase origin/feature
dev branch maintainer
                         G1 - H1 - I1 [d]
                        /
             D1 - E1 - F1 [o/f]
            /
A - B [m]- C[o/m]
     \
      D - E
           \
            G - H - I [o/d]

他们可以使用--force参数来强制推送。

你会注意到dev分支现在是在F1上,而不是原来的E1。如果你想保持原样,你需要特别地将其变基到E1上。


如果Git无法确定D和E实际上不属于dev分支,你可能会遇到这种情况。

dev branch maintainer
                         D2 - E2 - G1 - H1 - I1 [d]
                        /
             D1 - E1 - F1 [o/f]
            /
A - B [m]- C[o/m]
     \
      D - E
           \
            G - H - I [o/d]

Git应该能够使用“补丁ID”来解决这个问题,它类似于提交ID,但只检查内容而不涵盖其他信息。如果无法解决,请尝试更新Git并查看是否有所帮助。如果仍然无法解决,则属于git-rebase文档所称的“困难情况”。您需要使用--onto明确告诉Git要将哪些提交作为基础进行变基。幸运的是,引用日志包含了功能分支的先前位置f@ {1},可以用作参考。
git rebase --onto f f@{1}

这里说的是将当前分支(d)变基到f,但只从d到f@{1}(也就是f之前的位置)进行变基。


我将git pull --rebase别名为git repull。我几乎总是这样做,它相当安全,通常都是正确的做法。您可以使用git config --global pull.rebase true将其配置为默认值。

更多信息,请参见git-rebase文档中有关从上游变基的恢复说明


我不确定这是否解决了核心问题。我们已经在使用 git fetch [remote]get rebase [remote/branchname]。当 git 进行变基时,它需要确定哪些提交是“新工作”,并且不在您正在从中拉取更改的“上游”分支上已经存在。由于提交哈希已更改为真正已经存在于两个分支上的提交,git 认为它是一个新提交,并尝试“重新应用”这些更改。显然,合并冲突很多。 - helion3
@helion3 Git应该能够使用补丁ID来完成此操作,补丁ID类似于提交ID,但仅与内容更改相关。我所描述的是git-rebase文档中的“简单情况”。您正在描述“困难情况”。您使用的Git版本是什么?请参阅《Pro Git》的Rebasing部分中的“The Perils Of Rebasing”和“Rebase When You Rebase”。 - Schwern
@helion3,我已经更新了答案,解释了如何处理“特殊情况”。 - Schwern
@helion3 如果没有看到您存储库的详细信息,我无法提供更多帮助。如果您想咨询,我可以在codementor.io和HackHands上提供服务。 - Schwern
好的,所以我从“坏”分支创建了两个分支。使用git fetch upstream/git rebase upstream/the-feature-branch命令时,它会抛出合并冲突,因为它认为旧的哈希提交是新工作。但是使用git pull --rebase upstream the-feature-branch命令,它会正确更新基础并应用实际最近的提交。这两个命令之间有一些不同,其中一个不仅仅是另一个的别名。它可以工作,但我想找出原因。 - helion3
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接