Git:如何编辑带有多个后代分支的旧提交?

3

我的Git仓库历史记录长这样:

* (topic2) commit_11
* (topic1) commit_10
* commit_9
* commit_8
* (HEAD, master) commit_7
* commit_6
* commit_5
* commit_4 <- I wanted to edit this commit.
* commit_3

所以我就这样做了。
git rebase -i commit_3

对于编辑器中的 commit_4,将 pick 替换为 edit。 我纠正了一些变量名字中的拼写错误,然后

git add .
git commit --amend
(rename commit)
git rebase --continue

现在的历史看起来像这样:


* (HEAD, master) commit_7.1
* commit_6.1
* commit_5.1
* commit_4.1 <- Edited commit.
| * (topic2) commit_11
| * (topic1) commit_10
| * commit_9
| * commit_8
| * commit_7
| * commit_6
| * commit_5
| * commit_4 <- Original commit.
|/
* commit_3

我希望我的历史记录和以前一样干净利落。我尝试使用之前成功多次的方法。
git checkout topic1
git rebase master

在应用第一个补丁时,它最终会出现冲突。我手动解决了这些冲突。但是当我尝试git rebase --continue时,它告诉我“没有要提交的内容”。

如何处理这个问题以及为什么会出现这种情况?


我认为你有点滥用版本控制。如果在 commit_4 中犯了错误,请在新的 commit 中进行修复,如果需要在不同的分支中使用该修复,请将其 cherry-pick 到其他分支中。 - Marian Theisen
2
如果没有推送这些内容中的任何一个,那么这样做是合理的。 - Jason Malinowski
在此rebase期间的当前分支是哪一个?我猜想如果您在主分支上进行了重新编辑,然后将topic* rebase到主分支,历史记录将会是线性的。 - Netch
拥抱非线性版本历史,你的问题将神奇地消失。Git不是SVN。 - Max
@Max 问题不在于“非线性历史记录”。问题在于,在变基期间进行的编辑只会出现在执行变基的分支上。其他分支将具有未经编辑的版本。也就是说,OP表示他们在旧提交中修正了一些错别字。现在,修正后的版本仅会出现在“master”分支上(因为这是执行变基的分支),但它不会出现在其他分支上,如“topic1”,“topic2”等。它应该在其他分支上出现。 - Utku
显示剩余2条评论
1个回答

1
我稍作修改你的图表,以表示当你变基时,所有提交都会改变,即使内容没有变化。你的新提交集将具有与原始提交不同的 shas。(SHA是Git中用于标识提交的唯一标识符)
最简单的解决方案是使用 --onto。请查看此链接,从文本“以下是如何移植主题分支”开始:git rebase 所以在你的情况下,应该是这样的:
git rebase --onto commit_7.1 commit_7 topic1

换句话说,将从commit_7之后(包括commit_7)到topic1的提交移植到commit_7.1上。但是,您可能仍然会遇到需要手动修复的合并冲突。
我建议在执行此操作时,在topic1提交上创建一个额外的分支。将其命名为topic1old或其他名称。这样,如果rebase不成功,就可以轻松返回到该提交并通过硬重置将topic1还原回去。
编辑:为什么简单的git rebase master没有起作用?
如果您没有告诉它其他内容,git rebase会认为您正在对其上游分支进行rebase。
但正如我修改图表的方式所示,topic1和master现在已经没有太多共同点了。如果您只是简单地将其rebase到master上,那么topic1将尝试将所有提交都rebase到master上的所有提交上。这意味着您会得到类似以下的结果:
  • (主题1) commit_10
  • commit_9
  • commit_8
  • commit_7
  • commit_6
  • commit_5
  • commit_4
  • (HEAD, 主分支) commit_7.1
  • commit_6.1
  • commit_5.1
  • commit_4.1 <- 编辑过的提交。
  • commit_3

现在 Git 智能地避免重复提交。显然,如果您进行了更改 X、Y 和 Z,然后稍后的提交再次进行了这些更改,Git 就会省略后面的提交,因为这些更改已经存在。

但是改变提交 4 的结果就会引发问题。这导致所有在此之后的提交都是基于不同的代码集合进行的。这将可能需要进行大量的合并。

使用 --onto 可以解决这个问题,因为它允许你使用不同的基础。你要说的是:"我不在乎 commit_4(因为我已经改变了它)也不在乎 commit_5、_6 和 _7(因为我已经合并了它们,并且它们与我的主题分支中的基本相同)。所以从 commit_8 开始,在已经处理过的东西之上重新应用这些更改。"


Kyralessa,你的解决方案很好。但是有人能解释一下为什么这次简单的 git rebase master 不起作用吗? - LVitya
Kyralessa,感谢您的澄清。我猜git rebase master的成功取决于对commit_4所做的更改。 - LVitya

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