Git 重新定基是否是修复错误樱桃采摘的唯一方法?

Git 重新定基是否是修复错误樱桃采摘的唯一方法?,git,git-merge,git-rebase,git-cherry-pick,Git,Git Merge,Git Rebase,Git Cherry Pick,分支#1包含错误修复C1。分行2首先樱桃采摘对C1进行了修复,然后分行2的所有者意识到C1中所做的工作实际上是错误的,因此他实施了正确的修复C2 在C2中,他基本上删除了C1中的更改,并替换为正确的更改。当分行1所有者想要“获取”修复时,合并将无法工作。因为使用merge时,结果C3将包含C1和C2中引入的正确修复,即C1将由merge保留 Because the branch #2 now does NOT contain C1 codes at all so merge won't work

分支#1包含错误修复C1。分行2首先樱桃采摘对C1进行了修复,然后分行2的所有者意识到C1中所做的工作实际上是错误的,因此他实施了正确的修复C2

在C2中,他基本上删除了C1中的更改,并替换为正确的更改。当分行1所有者想要“获取”修复时,合并将无法工作。因为使用merge时,结果C3将包含C1和C2中引入的正确修复,即C1将由merge保留

Because the branch #2 now does NOT contain C1 codes at all so merge won't work.

base -- C1'-- C2'(remove C1' change) -- C2''(add the correct fix) <--branch #2


     /---- C1---------------C3 (merge won't do b/c C1 will be kept)  <-- branch #1
base                       /
     \---- C1' ---- C2----/  <--branch #2
因为分支#2现在根本不包含C1代码,所以合并无法工作。
基本--C1'--C2'(删除C1'更改)--C2''(添加正确的修复)
所以问题是,如果我知道有人会选择我的提交,我最好重新设置他的分支的基础,而不是合并

是的,因为正如我前面所说的,一个cherry pick在分支之间复制了一个commit。由于重基跳过重复提交,这是一个很好的解决方法。
有关具体说明,请参见“”

有没有其他方法可以避免(或解决)我在这里提到的问题

如果您打算最终合并两个分支,那么在这两个分支之间就不应该有樱桃采摘。仅合并或重设基础

只有在分支不应该合并的情况下,Cherry选择错误修复是个好主意

所以问题是,如果我知道有人会选择我的提交,我最好重新设置他的分支的基础,而不是合并

是的,因为正如我前面所说的,一个cherry pick在分支之间复制了一个commit。由于重基跳过重复提交,这是一个很好的解决方法。
有关具体说明,请参见“”

有没有其他方法可以避免(或解决)我在这里提到的问题

如果您打算最终合并两个分支,那么在这两个分支之间就不应该有樱桃采摘。仅合并或重设基础


只有在分支不应该合并的情况下,Cherry选择错误修复是个好主意。

您基本上是正确的。然而,重新设定基准并不是解决问题的万灵丹

让我们画一个稍微复杂一点的情况。我们将从一个类似的提交图开始:

...--o--o
这里的最后一个
o
节点是某个分支的tip commit,而之前的一些commit
o
也不是很明显。我们不会为分支标签费心,因为它们只是为了帮助人类,我们关注的是Git做了什么,而不是人类做了什么。:-)

出现了一个人,他进行了一次新的提交,您的提交
C1
(不过我将其称为
C
),其中有一个bug:

          C
         /
...--o--o
与此同时,在这份回购协议中,或者在它的其他复制品中,出现了一个不同的人,他做出了一个不相关的承诺
F

          C
         /
...--o--*
         \
          F
提交
C
F
可能位于不同的(命名的)分支上,但重要的是它们有一个公共基
*
(这过去只是标记为
o
,但现在我们需要记住,它是公共基,尽管从图纸上看很明显)

在您的特定场景中,第二个用户通过樱桃采摘
C
生成了
F
。假设在我们的例子中,第二个用户相当独立地制作了
F
。现在,第二个用户决定现在是挑选
C
的时候了,所以他们得到了它的一个副本,但它并没有完全应用,所以他们会稍微更改它,手动编辑它,使其应用。现在他们有:

          C
         /
...--o--*
         \
          F--G
请再次注意,commit
G
主要是
C
的一个副本,但并非完全如此,正如我们所指出的,它将被视为有缺陷的

因此,您的第一个人将
C
还原为实际上将其从其分支中移除,然后添加
D
(更正的修复):

您的第二个人继续添加更多提交:

          C--R--D       <-- branch1
         /
...--o--*
         \
          F--G--H--I    <-- branch2
因此,虽然
git merge
肯定会失败,
git rebase
有时也会失败(特别是当必须修改提交以适应时)。在这种情况下,发生这种情况是因为
F
C
之间存在冲突,但是有很多方法可以解决这个问题

有没有其他方法可以避免(或解决)我在这里提到的问题

理想的情况是,无论谁在
branch2
上工作,都不必一开始就选择
C
,而只需要在
C
上重新设置基址,然后在需要时(或者直接在
D
上重新设置基址),或者在所述重新设置基址后合并。让我们看看如果第二个人在
branch2
工作,将他的
F
commit重设为
C
,而不是樱桃采摘,那么这个图会是什么样子。让我们在重设基础之前绘制:

          C    <-- branch1
         /
...--o--*
         \
          F    <-- branch2
现在,让我们将
F
复制到
F'
顶部
C
并移动分支标签:

...--o--*---C      <-- branch1
         \   \
          \   F'   <-- branch2
           \
            F      [abandoned]
如果我们现在使用
git merge
将commit
I
合并到commit
D
上,我们不会通过
G
重新引入错误的commit
C
,因为现在没有
G

当然,如果有多人使用
branch2
——如果发布了旧的
F
commit,那么每次我们重新设置基址时,这意味着他们都必须切换到使用新的副本

测试 有没有其他方法可以避免(或解决)我在这里提到的问题

理想情况下,当有人发现bug时,在编写commit
C
之前,他们会编写一个测试用例。测试用例显示commit
C
是必需的,commit
C
修复了这个bug,这就是commit
C
首先被提交的原因

当发现
C
有故障时,应该改进它的测试用例,或者编写一个额外的测试用例,以证明提交
C
并不完全正确。这也是为什么revert
R
进入,以及后续更好的修复
D
的原因。(也许
D
本质上是
R
的挤压和替换修复?
          C--R--D               <-- branch1
         /       \
...--o--*         F'-G'-H'-I'   <-- branch2
         \
          F--G--H--I            [abandoned]
          C    <-- branch1
         /
...--o--*
         \
          F    <-- branch2
...--o--*---C   <-- branch1
         \
          F     <-- branch2
...--o--*---C      <-- branch1
         \   \
          \   F'   <-- branch2
           \
            F      [abandoned]
...--o--o---C--R--D     <-- branch1
             \
              F'-H--I   <-- branch2