我经常想分解一个大的提交:
git commit -a -m "Monolith"
我知道如何拆分提交(git gui
是我的朋友),但有时我实际上想手工重做…
git branch temp # Keep a reference to all my hard work
git reset --hard HEAD~ # Rewind 'my-topic' branch
# hack hack
git commit -a -m "Refactor 1"
# hack hack
git commit -a -m "Refactor 2"
要完成它,然后我想应用另一个提交,使代码完全回到存储在分支temp
中的状态,通常包括原始提交消息。
是否有一个简单的方法来做到这一点?
我想象cherry-pick
上的合并策略可能会完成这项工作,但是唉,这些都没有完成:
git cherry-pick --strategy=theirs temp # I am told about conflicts
git status # ... But here I find no changes to commit!
git cherry-pick --strategy=ours temp # Worth a try. Nope, empty commit.
git cherry-pick --strategy=recursive --strategy-option=ours temp # Partial result, bits are missing
我知道有一种方法可以做到这一点:
git log -1 temp # note the SHA
git checkout temp
git reset --soft my-topic
git commit -C <SHA-from-above> # branch 'temp' now contains the desired commit
git checkout HEAD -B my-topic
git br -d temp
然而,这似乎是一种非常容易出错的方法。任何小错误和我想保留的提交可能不在任何分支(git reflog
来拯救…)。我想找一些更有逻辑、更容易记住/做的事情。
要在temp
上重新创建树,(至少)有两种相当简单的方法:
git checkout temp -- .
,另一个
git diff temp | git apply --index
之后,使用
创建具有相同提交消息的提交git commit -C temp
这两个选项各有利弊。checkout
路由不会删除不再存在于temp
中的文件。apply
路由不支持二进制文件。
旁注:在现代的Git中,你可以使用git restore
而不是git checkout
,但我是一个老家伙,还没有学会使用它。
j6t的答案有一些合理的选项,但我更喜欢您自己建议的过程的简化版本。(我不知道你害怕犯什么错误,但我怀疑它们是由于你采取了不必要的步骤而产生的。)
git checkout temp
git reset --soft my_topic
git checkout my_topic
git commit -C temp
git branch -D temp
这似乎是一个奇怪的偏好,因为git checkout -- .
(他们的建议之一)看起来像一行;但请注意我对他们的回答的评论。还有其他一些微妙的陷阱,比如如果你忘记了你不在工作树的根节点上怎么办?当然,你可以绕过所有这些…
所以你可以养成先做git rm
的习惯,或者"知道";当你需要的时候(犯错的机会)。作为习惯,您可以使用:/:
而不是.
(并习惯向与您一起工作的每个人解释它),或者总是反复检查您是否在根中(另一个犯错的机会)。然后是
git rm -- :/:
git checkout temp -- :/:
git commit -C temp
git branch -D temp
只有一个简单的命令"less">
直接导入另一个提交的快照的直接路径是执行该操作的核心命令:
git read-tree -u temp
紧随其后git commit -C temp
用temp
的commit消息提交。
git read-tree
是几乎所有从现有的repo内容更新索引和工作树的命令的基础。git reset
是围绕git update-ref HEAD
和git read-tree
的选择逻辑;git checkout
也围绕git update-ref HEAD
和git read-tree
的一些选择逻辑;git merge
是对git read-tree
结果的一些相当繁重的清理工作…是的。顺便说一下,git commit
是围绕git update-ref HEAD
、git write-tree
和git commit-tree
的一些选择逻辑(后者向对象db添加了一个小对象)。
忘掉你的临时分支吧。不是硬复位,而是混合复位。
结果是索引被重置,但工作树没有。现在你可以添加和提交任何你喜欢的组合,然后只需添加其他所有内容并提交完成。
请参阅我的https://stackoverflow.com/a/59675191/341994了解更多。