首页 > 解决方案 > 混帐 | 将旧提交移至另一个分支的过去

问题描述

我过去错误地分支,一个提交留在了另一个分支的开头:

* 03431cb (HEAD -> bar) a2
| * d332e4d (foo) b2
| * 9b29ae3 b1
| * 4656a98 a1
|/  
* 6ebca20 (master) root

我怎样才能搬出a1进入foobar这样的bar历史是不是在?是否可以通过一个 git commit 来完成? 这不是推送的,因此无需担心破坏其他人的本地存储库。root -> a1 -> a2a1foo

我首先考虑做一个樱桃挑选a1然后更正和之间的a2顺序a1。问题是这两个提交在我的真实案例场景中发生冲突,我必须在进行樱桃挑选和切换顺序时纠正冲突。


bash中的mwe:

#!/bin/bash
set -e

rm -rf .git

git init -b master
echo content > my-file
git add my-file
git commit -m root

git checkout -B foo
echo asd >> my-file
git add my-file
git commit -m a1
echo qwe >> my-file
git add my-file
git commit -m b1
echo zxc >> my-file
git add my-file
git commit -m b2

git checkout master
git checkout -B bar
echo jkl >> my-file
git add my-file
git commit -m a2

标签: gitgit-rebase

解决方案


我是语法的忠实粉丝git rebase --onto x y z,这意味着:

从 z 开始,通过父链向后看,直到你即将到达 y 并停止。现在将这些提交,即从 y 到并包括 z 的所有内容重新设置为 x。

换句话说,使用这种语法,你可以清楚地说明在哪里剪断链。另外,您不必在变基之前切换分支。语法需要一些时间来适应,但一旦你熟练掌握它,你就会发现自己一直在使用它。

所以:

  1. 在 a1 创建一个临时分支只是为了给它一个名字:git branch temp 4656a98
  2. 现在将 b1 和 b2 重新设置为根:git rebase --onto master temp foo
  3. 最后将 a2 变基到 a1 上:git rebase --onto temp master bar
  4. 现在,您可以根据需要删除 temp :git branch -D temp

当然,我们可以节省两个步骤,只使用 SHA 编号 4656a98 而不是名称 temp 执行 2 和 3,但名称更好。


证明。

起始位置:

* 9a97622 (HEAD -> bar) a2
| * 83638ec (foo) b2
| * 7e7cbd0 b1
| * 931632a a1
|/  
* 6976e30 (master) root

现在:

% git branch temp 931632a
% git rebase --onto master temp foo
% git rebase --onto temp master bar
% git branch -D temp

结果:

* 3a87b61 (HEAD -> bar) a2
* 931632a a1
| * bbb83d0 (foo) b2
| * 5fa70af b1
|/  
* 6976e30 (master) root

我相信这就是你所说的你想要的。


推荐阅读