【问题标题】:how to cherry-pick latest patch from the different developer without conflicts如何从不同的开发人员那里挑选最新的补丁而不会发生冲突
【发布时间】:2018-08-28 13:29:21
【问题描述】:

我已经从其他开发人员那里挑选了一个提交来完成一些工作。

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

如果我选择新补丁,那么就会有冲突。

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

有什么方法可以丢弃之前的补丁或者我必须手动解决冲突?

【问题讨论】:

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


    【解决方案1】:

    您有两个直接而明显的选择:

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

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

    使用哪一个取决于很多事情,包括您是否属于说“永远不要重写任何历史”的学校(在这种情况下,您必须使用第一种方法),或者您是否有额外的提交- 选择一个,按图表顺序。

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

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

    然后你决定无论出于何种原因,你喜欢他们的提交J,所以你运行git cherry-pick &lt;hash-of-J&gt;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' 他们的J 的副本。例如,假设自从您挑选了他们的J 来制作您的J' 之后,您又进行了六次提交?那么你现在就有这个了:

    ...--F--G--H--J'-L--M--N--O--P--Q   <-- yourbranch (HEAD)
          \
           I--K   <-- origin/theirbranch
    

    现在你要摆脱你的J' 变得更加困难:它嵌入在你的历史中,从Q 一直延伸到F

    您可以使用交互式 rebase (git rebase -i) 尝试通过将提交 L-M-N-O-P-Q 复制到与原件非常相似的新提交 L'-M'-N'-O'-P'-Q' 来将 J' 从历史记录中剔除。 , 但跳过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 revert 命令告诉 Git:找出给定提交中发生了什么变化,并进行一个新的提交,该提交具有撤消这些更改的效果。对于我添加到某个文件的每一行,从该文件中删除该行。对于我从某个文件中删除的每一行,将该行放回原处。对于我批发删​​除的每个文件,把那个文件带回来;对于我从头开始创建的每个文件,完全删除该文件。

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

    【讨论】:

    • torek,上面的解释对于新补丁也是如此,即如果其他开发人员确实提交了 --amend 到 J 而不是提交新的 K。
    • git commit --amend 可能是其他开发人员如何创建 K-instead-of-J。 --amend 真正所做的只是使 new 提交点回到 当前提交的父级,有效地将当前提交推到行尾。您实际上无法更改提交,git commit --amend 不会尝试这样做:它只是使 不同 提交成为分支上的最后一个。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-16
    • 1970-01-01
    • 1970-01-01
    • 2022-10-08
    • 2014-02-02
    相关资源
    最近更新 更多