我正在做一个很大的交互式rebase,我正在编辑8个提交。这是通过git commit --amend
完成的。我的问题是,有一次我遇到了合并冲突,我没有注意到,所以我继续天真地修改和git rebase --continue
- ing。显然我现在已经将多个提交修改为一个,并且在完成rebase之后大约有4个提交已经消失了。这些更改已修改为其他提交。
有什么方法可以撤消这些修改,或者重新申请已经失效的提交?
当然;一个解决方案就是回去再做一次rebase,但是我在rebase中做了很多编辑,所以我很想不必重新完成我的所有工作。我是如何陷入这种困境的另一个故事。
Git树示例:
在rebase之前:A-B-C-D-E-F
在rebase之后:A-B-C-F
(C现在修改了D和E)
答案 0 :(得分:3)
是的,你可以。
通常情况下,我会马上回去重做所有内容,但我能理解这个问题 - 听起来你已经投入了大量的时间进入rebase,所以似乎没有邀请再做一遍。< / p>
我假设您示例中F
的内容正是您希望最终结果的内容,您只是错过了D
和E
提交。
你可以做的是:
git checkout C # "git status" should be empty right now
git checkout F .
git reset .
git add only-changes-from-D ; git commit -m D
git add only-changes-from-E ; git commit -m E
git add -A ; git commit -m F
git checkout F . ; git reset .
使得您的工作目录包含F
,但您的HEAD仍指向C
,索引中没有任何内容。 git status
现在会显示C
和F
之间的完全差异。
现在,您可以使用自己喜欢的添加/提交工具(我喜欢git gui
)并选择最初属于D
的所有更改,并提交。重复E
。之后,只有来自F
的更改;你可以一次添加和提交它们。当然,如果E
和F
之间有更多,则必须冲洗并重复。
这样做的好处是您实际上不需要更改任何内容。最终结果将是F
,但您将根据需要获得一些中间提交。
答案 1 :(得分:3)
您所做的每一次提交,修改与否,仍然“在那里”,并且它们都可以通过reflog找到。这是因为git commit --amend
实际上 原样。
提交你没有制作(即,如果索引中存在冲突的状态以便git commit
拒绝提交)当然不会保存。< / p>
使用git reflog
(或git reflog HEAD
)查找每次提交。您可能希望将原始哈希ID保存在文件中以进行剪切和粘贴,因为命名它们的简单方法HEAD@{3}
等等都是相对的,并且会不断变换。 (即,每次调整HEAD
时,HEAD@{3}
现在是HEAD@{4}
,HEAD@{5}
,很快HEAD@{7}
,最后是HEAD@{198}
,augh !:-))
您还可以使用名称ORIG_HEAD
立即恢复原始链(如果您没有运行任何其他命令)。也就是说,当您运行git rebase -i
然后执行所有编辑,修改提交等等,最后完成时,会发生的事情是git rebase
将原始分支提示保存在名称{{ 1}}。您可以将新分支或标记名称指向该原始提交,然后使用ORIG_HEAD
,name
,name~1
等来引用原始(预先变更)承诺:
name~2
现在git tag oops ORIG_HEAD
提交oops
,F
提交oops~1
,依此类推。
您可以E
任何提交,git show
从中获取文件,git checkout <commit-id> -- <path>
将该提交应用为您当前位置的增量,依此类推。
答案 2 :(得分:2)
在重新定位/修改提交后,原始提交仍在此处。虽然如果它无法通过分支到达,但它不会出现在git log
。
我认为在git reflog
的帮助下,你可以设法做你想做的事。
git reflog //identify the hash of the commits you want, look for your commit --amend that you want to undo
git checkout B
git cherry-pick hash-of-commit-C-as-resolved-during-rebase-but-before-amending
git cherry-pick hash-of-commit-C-after-amending-with-D
git cherry-pick hash-of-commit-C-after-amending-with-E
git cherry-pick F