重新更改合并提交的父级

Tra*_*own 8 git git-rebase

假设我有以下历史记录,其中顶行是主分支,较低的一个是在一个点与主服务器合并的功能分支,D只是恢复C(这意味着工作目录在B和中是相同的D).

A---B---C---D           master
 \   \
  E---F---G             feature
Run Code Online (Sandbox Code Playgroud)

我想在合并之前添加C并恢复D历史记录F,如下所示:

A---B---C---D           master
 \           \
  E-----------F'--G'    feature
Run Code Online (Sandbox Code Playgroud)

我不想改变E(这实际上是一系列提交).

git rebase --onto D B(如此处所示)导致合并冲突(有或没有--preserve-merges).

有没有办法实现我想要的?

tor*_*rek 11

大多数方法都会有些痛苦.有一个适度无痛的版本使用git filter-branch,除了过滤器分支本身是痛苦的.:-)(您将过滤提交FG编写一个提交过滤器,替换您想要的新父项F',并让filter-branch操作替换该父项G.)

我认为不采用低级命令的最简单方法只是进行新的合并,然后重新绑定G到新的合并.新合并可能有冲突,但我们不在乎,我们只想采用旧的合并树,我们可以这样做:

$ git checkout <sha1>  # Use D or E's sha-1 here.
                       # Note: whichever you use will
                       # be the first parent of our new
                       # merge; choose based on that.
$ git merge --no-commit <sha1>  # use the remaining sha-1 here
[ignore resulting stuff]
$ git rm -rf .         # Note: assumes you're in top dir of work tree
$ git checkout <sha1-of-F> -- .
$ git commit           # Create merge commit F'
Run Code Online (Sandbox Code Playgroud)

第一个checkout使用一个SHA-1 merge --no-commit启动分离的HEAD,启动与另一个SHA-1 的合并过程,git rm -rf .抛弃合并的树和任何冲突,以及git checkout <id> -- .上一个合并中的索引和工作树中的填充.最终git commit创建F'与合并相同的树合并F,但使用不同的父项.

此时(仍然使用分离的HEAD)您可以重新设置(或者挑选)提交G(或许多提交G),然后强制您的分支指向新图的提示.我建议使用,git rebase ... --onto HEAD但我没有用一个独立的HEAD测试它,并且至少有一种方法可能出错(解析HEADID太晚了).

低级git commit-tree命令实际上可能更简单. Andrew C在评论中写了正确的命令,尽管你必须拼出分支名称git update-ref.[编辑:也许不太正确,你希望两个父母DE,不DB.再次,把你想要的那个作为第一个父母的第一个.]

使用更熟悉的命令的优点(?)是,它们更熟悉.