变基以更改合并提交的父级
Rebasing to change parent of a merge commit
假设我有以下历史记录,其中最上面一行是 master 分支,下面一行是与 master 在某一点合并的功能分支,D
只是恢复 C
(这意味着 B
和 D
中的工作目录相同)。
A---B---C---D master
\ \
E---F---G feature
我想在 F
合并之前将 C
及其还原 D
添加到历史记录中,如下所示:
A---B---C---D master
\ \
E-----------F'--G' feature
我不想更改 E
(实际上是一长串提交)。
git rebase --onto D B
(建议 here)导致合并冲突(有或没有 --preserve-merges
)。
有没有办法实现我想要的?
大多数方法都会有些痛苦。有一个使用 git filter-branch
的适度无痛版本,除了 filter-branch 本身是痛苦的。 :-)(您将过滤提交 F
和 G
并编写一个 commit-filter 替换您想要的 F'
的新 parents,然后让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> -- .
填充上一个合并的索引和 work-tree。最后的 git commit
使用与合并 F
相同的树创建合并 F'
,但 parents.
此时(仍然使用分离的 HEAD)您可以变基(或 cherry-pick)提交 G
(或许多提交 G
),然后强制您的分支指向新图表的顶端。我建议使用 git rebase ... --onto HEAD
但我没有用分离的 HEAD 测试过它,并且至少有一种方法可能会出错(将 HEAD
解析为 ID 为时已晚)。
低级git commit-tree
命令实际上可能更简单。 ,虽然你必须用 git update-ref
拼出分支名称。 [编辑:可能不太正确,你想要的两个 parents 是 D
和 E
,而不是 D
和 B
。同样,将您想要的 first-parent 放在第一位。]
使用更熟悉的命令的优点 (?) 是它们更熟悉。
假设我有以下历史记录,其中最上面一行是 master 分支,下面一行是与 master 在某一点合并的功能分支,D
只是恢复 C
(这意味着 B
和 D
中的工作目录相同)。
A---B---C---D master
\ \
E---F---G feature
我想在 F
合并之前将 C
及其还原 D
添加到历史记录中,如下所示:
A---B---C---D master
\ \
E-----------F'--G' feature
我不想更改 E
(实际上是一长串提交)。
git rebase --onto D B
(建议 here)导致合并冲突(有或没有 --preserve-merges
)。
有没有办法实现我想要的?
大多数方法都会有些痛苦。有一个使用 git filter-branch
的适度无痛版本,除了 filter-branch 本身是痛苦的。 :-)(您将过滤提交 F
和 G
并编写一个 commit-filter 替换您想要的 F'
的新 parents,然后让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> -- .
填充上一个合并的索引和 work-tree。最后的 git commit
使用与合并 F
相同的树创建合并 F'
,但 parents.
此时(仍然使用分离的 HEAD)您可以变基(或 cherry-pick)提交 G
(或许多提交 G
),然后强制您的分支指向新图表的顶端。我建议使用 git rebase ... --onto HEAD
但我没有用分离的 HEAD 测试过它,并且至少有一种方法可能会出错(将 HEAD
解析为 ID 为时已晚)。
低级git commit-tree
命令实际上可能更简单。 git update-ref
拼出分支名称。 [编辑:可能不太正确,你想要的两个 parents 是 D
和 E
,而不是 D
和 B
。同样,将您想要的 first-parent 放在第一位。]
使用更熟悉的命令的优点 (?) 是它们更熟悉。