重新更改合并提交的父级

时间:2015-02-17 23:11:12

标签: git git-rebase

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

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

我想在C合并之前将D及其版本F添加到历史记录中,如下所示:

A---B---C---D           master
 \           \
  E-----------F'--G'    feature

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

git rebase --onto D B(按照建议here)会导致合并冲突(有或没有--preserve-merges)。

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

1 个答案:

答案 0 :(得分:10)

大多数方法都会有些痛苦。使用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'

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

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

低级git commit-tree命令实际上可能更简单。 Andrew C wrote the correct command in a comment,但您必须使用git update-ref拼出分支名称。 [编辑:可能不太正确,您想要的两位家长是DE,而不是DB。再次,把你想要的那个作为第一父母的第一个。]

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