如何修改连续提交,以便它们引用其他子模块提交?

How to amend successive commits such that they reference other submodule commits?

修改子模块中的一些提交消息后,我认为我还应该更新父存储库的提交以修复损坏的引用。

所以我在父存储库上做了一个交互式变基。我想修改父存储库中引用子模块中另外两个提交的两个提交,如下所示:

---A---B---C---D--- parent
   |   |
   v   v
---a---b--- sub

因此我 git rebase -i A^ 并选择编辑 A 和 B:

edit A ...
edit B ...
pick C ...
pick D ...

现在我在提交 A。为了恢复正确的子模块提交 ID,我首先检查相关的子模块提交,然后修改父存储库中的提交。

$ cd sub/
$ git checkout a
$ cd ..
$ git add sub
$ git commit --amend

感觉不错,继续下一篇:

$ git rebase --continue

现在它抱怨无法合并。这是我对本地化消息的翻译:

Error merging submodule sub (Commits do not follow any merge base)
automatic merge of sub
CONFLICT (submodule): Merge conflict in sub
error: Could not apply B (B's commit message)
Resolve all conflicts manually, mark them as resolved with
"git add/rm ", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply B (B's commit message)

很公平。由于第一个提交中的子模块 ID 已更改,第二个提交已失去与第一个提交的连接。 git status 表示 changed by both: sub。坚定不移,再次尝试修改:

$ cd sub/
$ git checkout b
$ cd ..
$ git add sub
$ git commit --amend

不幸的是,这不是我想要的。原因是错误的 git rebase --continue 以某种方式完全吃掉了提交 B。 B 的更改已放入暂存区,但提交已消失。因此第二个 git commit --amend 将修改 A 并将 B 的所有更改放入 A!现在我想我可以在那时创建一个新的提交,复制 B。但是要完全按照 B 进行复制会相当复杂。

如何正确修改子模块引用?为什么以及在什么情况下 rebase 会破坏这样的提交?

TL;DR:在没有 --amend 的情况下执行 git commit 使用 git rebase --continue,这将在没有 [的情况下执行 git commit =18=].

更长

让我们拿你的原始图表,减去与子模块的连接(因为它们很脆弱并且妨碍了:-)):

...--o--A--B--C--D   <-- branch

你 运行 git rebase -i A^ 并将 A 更改为 edit(依此类推)。变基 cherry-picks A 到新副本 A':

...--o--A--B--C--D   <-- branch
      \
       A'  <-- HEAD

您进行更新,git addgit commit --amend 进行更新 A",留下 A' 被遗弃:

       A"   <-- HEAD
      /
...--o--A--B--C--D   <-- branch
      \
       A'

现在,无论您为 B 的说明输入什么内容,Git 都会尝试 复制 B 但失败了。所以变基停止在:

       A"   <-- HEAD
      /
...--o--A--B--C--D   <-- branch
      \
       A'

在索引和 work-tree 中有一些未提交的更改。 还没有提交 B' 您现在可以做两件事。一种是自己做:

<fix the submodule>
git add sub
git commit

这将创建 B':

       A"-B'   <-- HEAD
      /
...--o--A--B--C--D   <-- branch
      \
       A'

现在您可以 git rebase --continue 让 Git 继续说明的下一部分(因此您最初不需要要求编辑 B,您可以现在继续将 C 复制到 C':如果 Git 现在停止让您编辑 B',您可以告诉它继续)。

另一个——因为git commit现在需要你输入一个提交消息——是设置一切,而不是git commit,运行 git rebase --continue制作 Git 制作 B':

<fix the submodule>
git add sub
git rebase --continue

--continue 步骤注意到所有冲突都已修复(如果没有,则抱怨并停止),然后执行 git commit 并继续,就像您所做的一样提交自己。

总结

你需要 edit 作为停止 rebase 的指令,让你 --amend 一个 cherry-pick 成功 。您 不需要 需要 edit 进行提交,其中 cherry-pick 将 失败 ,因为 Git 将没有首先提交就停止。

很难事先知道——在某些情况下,甚至不可能——知道哪些 cherry-picks 会成功,哪些会失败。因此,您最终不得不非常注意 git rebase 停止让您做某事之前出现的确切消息:它停止是因为 cherry-pick 失败了,还是因为你告诉它在 cherry-pick 成功后停止? 换句话说,是否有你现在应该 --amend 的提交,或者你应该(有 Git)现在进行 new 提交?

(我自己也被这个绊倒了,我觉得很烦人。)