Git 用 rebase 改写历史

Git rewriting history with rebase

我目前在一个看起来像这样的分支上工作

--A------B (master)
        / \
----C--D   E--F (feature_branch, HEAD)

我一直在尽力修复它,但没有成功:( git-rebase <A_SHA1> 似乎根本不起作用。目前只有两个分支:masterfeature_branch.

有没有办法让它看起来像这样?

--A------B (master)
   \    / \
    C--D   E--F (feature_branch, HEAD)

请注意,无法更改现有提交,因此给出:

...--α--A------B   <-- master
              / \
 ....--γ--C--D   E--F   <-- feature_branch (HEAD)

你将不可避免地从 rebase 中得到的是:

            C'-D'  E'-F'  <-- feature_branch (HEAD)
           /    \ /
          /___---B'
         //
...--α--A------B   <-- master
              / \
 ....--γ--C--D   E--F   [abandoned]

然后您可以强行移动 master 以指向 B' 而不是 B 以便您拥有:

            C'-D'  E'-F'  <-- feature_branch (HEAD)
           /    \ /
          /___---B'  <-- master
         //
...--α--A------B
              / \
 ....--γ--C--D   E--F   [abandoned]

现在可以完全忽略 BγC 等的存在,并假装 C'C,例如。请注意,提交 γ 已变得无法访问,除非 αγ 确实是相同的提交。

要实现此 使用 git rebase,您需要 somewhat-newfangled -r--rebase-merges 选项:

git checkout feature_branch   # if needed - you've drawn a detached HEAD
git rebase -i -r --onto master <hash-of-γ>

之后,您需要从要进行 pick 编辑的提交列表中删除 αA 等提交,因为这些提交目前都在 feature_branch 以及 master,通过合并提交 B。 (请注意 -r 是 Git 2.18 中的新内容。-r 选项使用交互式机制指示 Git 到 re-perform合并,这就是我们下面要做的。)

总体而言,使用单独的 git cherry-pickgit merge 命令可能更容易实现此目的:

git checkout --detach <hash-of-A>    # note: master~1 probably finds commit A
git cherry-pick <hash-of-C>          # make C'
git cherry-pick <hash-of-D>          # make D'
git merge --no-ff <hash-of-A>        # make new merge B'
git branch -f master HEAD            # forcibly update master now
git cherry-pick feature_branch~2     # make E'
git cherry-pick feature_branch~1     # make F'
git checkout -B feature_branch       # forcibly move feature_branch and re-attach HEAD

如果 master~1 确实标识了提交 A,您可以在此处使用它来代替每个文字散列,在这种情况下,master^2^ 将标识提交 C并且 master^2 将标识提交 D,因此您可以使用它来代替这两个文字哈希 ID。