Git 来自旧提交的分支

Git branch from old commits

我已经在 SO 和其他文档中对此进行了研究。我试过变基、合并、挑选樱桃和分离头。

经过 6 个小时的尝试,现在是时候提出问题了!

这是我的开头:

A-B-C-D-E-F-G master

这是我想将其更改为:

A-B      F-G  master
   \    / 
    C-D-E dev

我最接近的是:

A-B      C-D-E-F-G-H Main
   \    / 
    C-D-E dev
        \
         F-G master

我必须添加另一个分支名称和一个虚拟提交才能让分支正常工作。

但这比没有改变更糟糕。

请帮忙!

回复后更新

感谢您的回复。

是的,我的"what I want"不是很清楚。希望这可以澄清它:

A-B   -  F-G  master
   \    / 
    C-D-E dev

也就是说F处的"master"是B加上分支"dev"合并进去的结果

仍然无法正常工作

感谢@frasertweedale 尝试回答。

我已仔细按照您的说明进行操作,结果如下:

A-B   -  "merge branch 'dev'"-G  master
   \    / 
    C-D-E dev
        \ 
         F-G-"merge branch 'dev'"-F-G

我很高兴这很难:现在我花了 7 个小时在这上面,我感觉没那么糟糕了!

最终结果 正如@frasertweedale 所说,这正是我想要的,除了悬空的提交。

所以,我只需要摆脱悬垂物。

为清楚起见,我在下面重绘了:

A-B   -  "merge branch 'dev'"-G2  master
   \    / 
    C-D-E dev
        \ 
         F1-G1-"merge branch 'dev'"-F2-G2

此命令进行清理:

git rebase -p --onto F1^ F1

结果:

A-B   -  "merge branch 'dev'"-G2  master
   \    / 
    C-D-E dev

"merge branch 'dev'" 包含原始的 F 提交,当然可以这样重新注释。

假设您将 AB 等扩展到它们相应的提交哈希中,并且 masterG,第一步是分支 devE:

git branch dev E

然后将 master 重置为 B

git reset --hard B

接下来,将 dev 合并到 master,明确要求合并提交(否则它将执行 快进,因为 dev没有偏离 master):

git merge --no-ff dev

master 现在包含最多 E 的提交。现在你可以 cherry-pick 原来的 FG 提交。

git cherry-pick F
git cherry-pick G

现在你已经得到了非常接近你想要的东西;唯一的区别是添加了合并提交 (B+E):

A-B   -  (B+E)-F-G  master
   \    / 
    C-D-E dev

如果您现在想在合并提交 (B+E) 中包含 F 的内容,您可以执行 interactive rebase 并压缩两个提交一起。 --preserve-merges(别名 -p)选项必不可少。

git rebase --interactive --preserve-merges B

这将调用一个编辑器,其内容类似于以下内容(提交哈希和摘要会有所不同):

pick d4057bd c
pick 9419ef8 d
pick ad9e208 e
pick 120a90a Merge branch 'dev'
pick 61552ad f     
pick c947153 g

F提交行开头的pick指令替换为squash指令(在上面的例子中:squash 61552ad f),然后保存并退出.系统将提示您从合并提交和 F 的提交消息中形成一个新的提交消息,然后 rebase 操作将在没有进一步交互的情况下完成。变基后,您将完全您要求的存储库历史记录(在您更新的问题中)。

缩写脚本

以下脚本创建一个具有线性历史记录的新存储库,然后使用(大部分)与上述相同的步骤自动编辑历史记录。避免了交互式变基,因此不需要用户干预。

mkdir foo ; cd foo
git init
for C in A B C D E F G; do
    echo $C > $C
    git add $C
    git commit -m $C
    git tag $C
done
git branch dev E
git reset --hard B --
git merge --no-ff dev
git cherry-pick F
git reset --soft HEAD~
git commit --amend -m F
git cherry-pick G
for C in A B C D E F G; do
    git tag -d $C
done