使用合并提交将提交移动到新分支

Move commits into new branch with merge commits

我有这样的线性历史

----a--b--c--d--e--f----    main

我想将一系列提交移动到一个新分支中,并在旧分支中创建一个合并提交,创建一个像这样的非线性历史

----a-------x--d'--e'--f'-- main
      \    /
       b--c

其中 x 是新的合并提交。

我该怎么做?

请注意,移动的提交不是最新的(请参阅 here)。

你可以很容易地做到这一点,但你将重写 main 的历史记录,这是不推荐的,可能必须强制推送到远程。

无论如何,这是你的初始情况,或多或少(我使用 master 而不是 main,我只达到了 e):

$ git log --oneline --graph --all
* d5de97b (HEAD -> master) e
* 97f47d1 d
* 7c33da9 c
* 295b3c7 b
* 18622aa a

好的,我建议将 bc 变成分支 feature 上的提交,该分支将在 d 之前合并到 master 中。准备好? (其中一些步骤,例如某些 checkout 动作,可能是不必要的,但我没有停下来担心这个。)

$ git branch holdmyplace        # prevent losing any commits
$ git branch feature 7c33da9    # call `c` by a branch name `feature`
$ git reset --hard 18622        # slide `master` all the way back to `a`...
$ git merge --no-ff feature     # ...and merge `feature` with a merge commit!
$ git checkout holdmyplace      # okay, now return to the placeholder branch...
$ git rebase --onto master feature holdmyplace 
                                # ...and append it to `master`
$ git checkout master           # finally, return to master...
$ git reset --hard holdmyplace  # ...and slide it back up to the end!
$ git branch -d holdmyplace     # we no longer need the placeholder branch

现在我们有:

$ git log --oneline --graph --all
* 0d58dd1 (HEAD -> master) e
* 7831073 d
*   2bd7688 Merge branch 'feature'
|\  
| * 7c33da9 (feature) c
| * 295b3c7 b
|/  
* 18622aa a

你说的就是你想要的。

让我们从创建一些指针开始,让事情变得更简单。

git branch base <a>
git branch feat <c>

图表看起来像这样。

----a--b--c--d--e--f----    main
    ^     ^
  base  feat

现在我们将 feat 合并到 base,创建合并提交。

git switch base
git merge --no-ff feat

图表现在看起来像这样。

----a------x          base
     \    /
      b--c--d--e--f-- main

现在我们将 main 变基到 base,将其移动到新的合并提交上。

git switch main
git rebase --onto base feat

最后,我们可以清理不再需要的指针。

git branch -d base
git branch -d feat

我们最终得到如下图。

----a------x--d'--e'--f'-- main
     \    /
      b--c

这就是我要做的:

git checkout a
git merge --no-ff c
git cherry-pick c..main
# at this point you are on a revision that has a history like what you asked for
# now it's time to move main
git branch -f main
git checkout main

如果您将该分支推送到其他存储库,则必须强制推送新分支,因为您重写了它的历史记录。 (你重写历史还有其他考虑,以防万一)。