如何在不冲突的情况下挑选来自不同开发人员的最新补丁

时间:2018-08-28 13:29:22

标签: git cherry-pick git-merge-conflict

我从其他开发者那里挑选了一份承诺来做一些工作。

几个小时后,一名开发人员更新了他的补丁。

如果我选择新补丁,则存在冲突。

  1. 添加的两个文件:-如果新文件存在于同一文件中  补丁
  2. 均已修改:-旧补丁和新补丁中的文件相同。

有什么办法可以丢弃以前的补丁,还是必须手动解决冲突?

1 个答案:

答案 0 :(得分:2)

您有两个直接且显而易见的选择:

  • 添加第二个提交,以撤消第一个选择。 (现在,您有了一个源快照,看起来好像您从未进行过第一次采摘。)

  • 删除第一个选择,即更改提交历史记录。

使用哪种方法取决于很多事情,包括您是否说过“永远不要重写任何历史”(在这种情况下,您必须使用第一种方法),或者您是否拥有除承诺之外的其他承诺。按图顺序选择一个。

请记住,每个Git提交均由其哈希ID唯一标识。如果我们使用大写字母表示这些提交(而不是原始哈希ID),则可以更清楚地了解正在发生的事情。例如,假设我们从以下一系列提交开始:

... <-F  <-G  <-H   <--yourbranch (HEAD)
       \
        I  <-J   <--origin/theirbranch

然后,无论出于何种原因,您都决定喜欢他们的提交J,因此您运行git cherry-pick <hash-of-J>git cherry-pick theirbranch复制提交J的效果,进行新的提交。我们可以将此提交称为K,但让我们使用J'来表示它是J的副本:

...--F--G--H--J'  <-- yourbranch (HEAD)
      \
       I--J   <-- origin/theirbranch

在将来的某个时刻,无论他们是谁,他们都放弃了他们的提交J,而选择了新的和改进的提交K,因此在运行git fetch之后,您可以有:

...--F--G--H--J'  <-- yourbranch (HEAD)
      \
       I--K   <-- origin/theirbranch

(提交J已完全消失:新提交K直接指向I。这是人们谈论的“历史重写”。)

此时,您可以使用git reset --hard重写自己的历史记录。当然,这会丢弃您正在做的任何工作,但是让我们假设您没有做任何新工作,这样就可以了:

             J'  [abandoned]
            /
...--F--G--H   <-- yourbranch (HEAD)
      \
       I--K   <-- origin/theirbranch

您现在可以更轻松地选择他们的提交K,因为它与您的原始J'的副本J不冲突。这样您将拥有:

             J'  [abandoned]
            /
...--F--G--H--K'  <-- yourbranch (HEAD)
      \
       I--K   <-- origin/theirbranch

但是,另一方面,假设您要做的工作取决于您的J'的{​​{1}}副本。例如,假设您从挑选他们的J到完成J之后又做了六次提交?然后,您现在有了 this

J'

现在要摆脱...--F--G--H--J'-L--M--N--O--P--Q <-- yourbranch (HEAD) \ I--K <-- origin/theirbranch 更加困难:它已嵌入到您的 历史中,该历史从J'一直延伸到{{1} }。

您可以使用交互式变基(Q)通过将提交F复制到很多新的提交git rebase -i中来尝试将J'从历史记录中删除>喜欢原稿,但跳过L-M-N-O-P-Q

L'-M'-N'-O'-P'-Q'

(请注意,这看上去很像是反复摘樱桃。那是因为J' 就是反复摘樱桃!)但是,如果这样做太痛苦或令人反感,出于其他原因,您现在可以进行新的提交 J'-L--M--N--O--P--Q [abandoned] / ...--F--G--H--L'-M'-N'-O'-P'-Q' <-- yourbranch (HEAD) \ I--K <-- origin/theirbranch ,使它们的副本git rebase与其原始R的副本J'的效果 ,并将其添加到您的分支中:

J

通过运行以下命令,新提交...--F--G--H--J'-L--M--N--O--P--Q--R <-- yourbranch (HEAD) \ I--K <-- origin/theirbranch 可能很容易(也可能不容易)

R

git revert <hash-of-J> 命令告诉Git:找出给定提交中的更改,并进行新的提交,以撤消这些更改。对于我添加到某个文件的每一行,请从该文件中删除该行。对于我从文件中删除的每一行,请将该行放回去。对于我批量删除的每个文件,请将该文件重新带回;对于我从头开始创建的每个文件,请完全删除该文件。

此过程完成后,提交git revert中有一个快照,看起来好像从未发生提交R。 (如果您的提交J'L中的更改与此撤消Q的尝试冲突,则通常会在还原过程中看到合并冲突。请注意 if 就是这种情况,如果在复制J'J'时使用交互式变基丢弃提交L,通常会看到 same 冲突。到新的提交。)