我尝试将提交移至另一个分支的顶部,而忽略目标分支中所做的所有更改。
当前情况是:
master
↓
--A--B--C
\
D--E
我想将提交E移到C前面
master
↓
--A--B--C--E'
\
D--E
E'与E相同,只是下等额现在是C而不是D(这意味着E和E'的树应该相同)。
要更加精确:
"git cat-file -p E" shows e.g.
tree b98c9a9f9501ddcfcbe02a9de52964ed7dd76d5a
parent D
"git cat-file -p E'" should show
tree b98c9a9f9501ddcfcbe02a9de52964ed7dd76d5a
parent C
我尝试使用不同的参数以及Cherry-pick重新设置基准,但是所有这些最终都尝试将C中所做的所有更改合并到新的E'commit中:(
到目前为止,我发现的唯一阻止大规模合并的解决方案是
check out C
copy over all stuff from E to C
commit and get E'
现在树是相同的,父树是不同的,但是必须有一种更简单,更快的方法,因为要做的就是用现有的树对象创建一个简单的提交对象。
答案 0 :(得分:2)
是的,您的图表是准确的!
A,Git中没有明显的工具可以达到您想要的结果。这里的问题是,rebase只是自动化的自动选择,而自动选择是关于将提交及其快照转换为变更集,并将这些变更与其他提交合并以进行新的提交,这是不希望的想要:您想要保留原始快照。
幸运的是,有几种简单易行的方法可以做到这一点。不幸的是,其中一些使用至少一个 plumbing命令,即对用户不友好,不发光的瓷器,内部Git命令。
首先,让我们注意您自己的解决方案是正确的:
到目前为止,我发现的唯一阻止大规模合并的解决方案是
check out C copy over all stuff from E to C commit and get E'
在实际的Git命令中,例如:
$ git checkout -b new-branch master
$ git rm -r . # in case there are files in C that aren't in E at all
$ git checkout <hash-of-E> -- . # overwrite using E
$ git commit
这实际上还不错,但是它会导致对工作树的大量更新,如果您的下一个make
花费一个小时或其他时间,可能会很烦人。
第一种更简单的方法是:
$ git checkout -b new-branch master
$ git read-tree -u <hash-of-E>
$ git commit
read-tree
操作将您的 index 内容替换为提交E中的内容。-u
标志告诉Git:在执行此索引更新时,请更新工作树也是如此:如果将文件从索引中完全删除,也将其从工作树中删除,或者如果文件在索引中被替换,也将其在工作树中也替换。并不是真正需要的,因为git commit
将使用索引中的内容,但这是个好主意。
第二种更简单的方法是:
$ git commit-tree -p master -m "<message>" <hash-of-E>^{tree}
此打印出新提交的哈希ID;然后,我们需要设置一些内容以指向 这个新的哈希ID:
$ git update-ref refs/heads/new-branch <hash-ID>
或者,一行:
$ git update-ref refs/heads/new-branch $(git commit-tree -p master -m "<message>" <hash-of-E>^{tree})
请注意,-m "<message>"
可以替换为-F <file>
以从文件中读取消息,甚至可以替换为-F -
以从stdin中读取消息。然后,您可以使用E
从提交git log --no-walk --format=%B <hash-of-E>
复制提交消息,并将其通过管道传递到单行命令的其余部分。
请确保new-branch
确实是一个新的分支名称,否则请确保它是您要重置的分支,而不是当前分支,因为git update-ref
不会进行错误检查默认情况下。
您还可以执行以下操作:
$ git checkout -b new-branch <hash-of-E> # now at E, with E in index and work-tree
$ git reset --soft master # make new-branch identify C, without
# touching index or work-tree
$ git commit -c <hash-of-E> # make new commit using E's message
最后一种方法的工作树搅动最少,因此这三种方法中最好的。但是,方法2创建新提交时不会碰到任何东西,因此,如果您实际上不希望想要进入新分支,方法2可能是最好的。