如何重写到覆盖历史的分支?

问题描述 投票:1回答:1

说我有分支1与提交A

1: A

从1开始,我创建了另一个分支2

2: A

2上,我添加了一个提交。

2: A->B

然后在1,我做了一些改变和git commit --amend,覆盖A

1: C

2,我想要在1上进行这些新的更改,并希望将我的更改从B应用到C。但是,从我的理解,git将看到分支2有新提交AB,并尝试在C上应用这两个提交。因此,当我完成变基,2将会是这样的

2: C->A->B

当我真正想要的是C->B

处理这种情况的正确方法是什么?到目前为止,我一直在处理这个问题的方法是从1创建一个新分支,然后从B挑选2。但是,当2不仅仅有一个新的提交时,这看起来有点像hacky,并不是那么简单。

git version-control rebase
1个回答
2
投票

让我们更传统地说明这一点,看看发生了什么。

如果A是第一次提交事情变得复杂,那么我将添加一个祖先Z.

假设我有提交A的分支1。

Z - A [1]

从1开始,我创建另一个分支,2。

Z - A [1][2]

在2,我添加一个提交。

Z - A [1]
     \
      B [2]

然后在1,我做了一些更改和git commit --amend,覆盖A.

事情变得如此糟糕。

  C [1]
 /
Z - A
     \
      B [2]

Git从不“覆盖”提交。它不能。提交ID是提交内容及其所有祖先的校验和。 commit --amend(以及rebase)所做的是创建新的提交并假装它一直都是这样。

但旧的承诺仍然存在。如果有任何东西作为祖先,就像这里的分支2一样,它将是可见的。

在2,我希望在1上进行这些新的更改,并希望将我的更改从B应用到C.但是,根据我的理解,git将看到分支2具有新的提交A和B,并尝试应用这两个提交在C语言之上。所以当我完成变基础时,2将看起来像2:C-> A-> B当我真正想要的是C-> B.

这里的问题是因为commit --amend分支1和分支2不再有A作为共同的祖先。它现在是Z.如果你试图将2变为1,它会将A和B都放在C之上。

    A1 - B1 [2]
   /
  C [1]
 /
Z - A
     \
      B

虽然这可能有效,但也可能导致混乱的冲突。你必须使用更精确的rebase命令让Git知道你真正想要的是什么。由于C实际上是一个重写的A,你真正想要的是A之后的所有内容。

git rebase --onto 1 A..2

结果将是你想要的。

    B1 [2]
   /
  C [1]
 /
Z - A
     \
      B

(A和B将不可见,它们最终将被垃圾收集。)


如果你认为这很复杂并且充满危险,那就是!

这就是为什么最好不要修改或修改你的“稳定”分支,通常是master。相反,只需使用普通提交或功能分支进行更大的更改。然后应用更新分支的正常过程。

© www.soinside.com 2019 - 2024. All rights reserved.