假设我有以下历史:
--E <- branch y
/
A---B---C---D <- branch x
我要修改commit B
,例如通过添加提交 B2
并将其压缩成 B
使用 git rebase -i
.
历史应该是这样的:
--E' <- branch y
/
A---B'--C'--D' <- branch x
我的问题是:我该怎么做?
我尝试在 E
之后提交它或 D
和 rebase ,但这会导致:
--B'--C'--E' <- branch y
/
A---B---C---D <- branch x
一个解决方法是 rebase E
到 D
;然后我可以去E'
, 添加和压扁 B2
, 导致
-E' <- branch y
/
A---B'--C'--D'
\
--B---C---D <- branch x
我可以在哪里让分支 x 指向 D'
:
-E' <- branch y
/
A--B'--C'--D' <- branch x
这几乎与我想要实现的目标相似,但感觉有点hacky,因为我手动移动了分支指针。 (在我的特殊情况下, rebase 是可以接受的,但我想知道一般情况。) 如果没有针对主要问题的简单解决方案,我想知道是否可以在不手动移动分支指针的情况下使用此解决方法。
附加信息:尚未推送相应的提交。
最佳答案
一个简单的解决方案是首先在其中一个分支上执行交互式 rebase ,进行我们的更改,然后将另一个分支 rebase 到新的 C'
:
git checkout branch_x
git rebase -i A
# mark commit B as edit, modify it, and complete the rebase
# rebase branch_y to be based on the new C' instead of C
git rebase --onto C' C branch_y
因为我们告诉原来基于C
的branch_y
rebase 到新的C'
上,所以我们恢复了原来的分支结构关于修改后的提交的分支。
请注意,我们需要知道 C
和新的 C'
的提交哈希值。在执行第二个 rebase 命令之前,我们必须在第一个分支上的交互式 rebase 之后查找它们。
另一种避免必须知道提交哈希值的解决方案是在此处执行保留 merge 的交互式 rebase 。请注意,这需要您先 merge 这两个分支。但是我们这样做只是为了 Git 保持分支关系,所以之后,我们可以再次摆脱那个 merge 。
所以要做到这一点,我们从任何分支开始, merge 另一个分支。然后我们执行一个保留 merge 的交互式 rebase 来修改提交 B
(以我们想要的任何方式)。之后,Git 将正确重放这些分支(包括 merge ),所以我们以这段历史结束:
A -- B' -- C' -- D' ---- M' ← branch
\ /
\ /
E' ------
然后我们可以将分支指针移动到更新的提交 D'
和 E'
,我们就完成了。
git checkout branch_x
git merge branch_y
# merge preserving interactive rebase
git rebase -p -i A
# mark commit B as edit, modify it, and complete the rebase
# we’re now on M', so move branch pointers to the new commits
git update-ref refs/heads/branch_y HEAD^2
git reset --hard HEAD^
历史现在应该是这样的:
A -- B' -- C' -- D' ← branch_x
\
\
E' ← branch_y
不幸的是,我们必须在这里手动移动分支指针,因为我们一次只能 rebase 一个分支。所以因为我们已经为另一个分支重新设置了历史记录的基础(因为 merge ),我们仍然必须移动它的指针。所以我们只接受我们必须在这里手动重置分支(无论如何这并不是一件坏事)。
关于git - 如何更改共同历史中的提交?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38369257/