所以我正在和其他人一起做一个项目,有多个github分叉正在进行中。有人刚刚修复了一个问题,我就和他的叉子合并了,但后来我意识到我可以找到更好的解决方案。我想要恢复我刚刚做的提交。我尝试用git revert HEAD这样做,但它给了我这个错误:

fatal: Commit <SHA1> is a merge but no -m option was given.

这是什么意思?当我合并和提交,我确实使用-m选项说“合并与<用户名>”。

我哪里做错了?


默认情况下,git revert拒绝恢复合并提交,因为这实际上意味着模棱两可。我假设你的HEAD实际上是一个合并提交。

如果你想要恢复合并提交,你必须指定哪个合并的父节点你想要考虑作为主干线,也就是说你想要恢复到哪个节点。

通常情况下,这将是第一个父节点,例如,如果你在master上,git合并了不想要的,然后决定恢复不想要的合并。第一个父分支将是合并前的主分支,第二个父分支将是不需要的尖端。

在这种情况下,你可以这样做:

git revert -m 1 HEAD

git cat-file -p [MERGE_COMMIT_ID]将按顺序显示父分支。第一个是- m1,第二个是- m2。


假设另一个人在foo上面创建了bar,但你同时创建了baz,然后合并,给出了历史

$ git lola
*   2582152 (HEAD, master) Merge branch 'otherguy'
|\  
| * c7256de (otherguy) bar
* | b7e7176 baz
|/  
* 9968f79 foo

注意:git lola是一个非标准但有用的别名。

没有骰子与git恢复:

$ git revert HEAD
fatal: Commit 2582152... is a merge but no -m option was given.

查尔斯·贝利像往常一样作了精彩的回答。使用git还原

$ git revert --no-edit -m 1 HEAD
[master e900aad] Revert "Merge branch 'otherguy'"
 0 files changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 bar

有效地删除栏并生成的历史记录

$ git lola
* e900aad (HEAD, master) Revert "Merge branch 'otherguy'"
*   2582152 Merge branch 'otherguy'
|\  
| * c7256de (otherguy) bar
* | b7e7176 baz
|/  
* 9968f79 foo

但我怀疑你想要扔掉合并提交:

$ git reset --hard HEAD^
HEAD is now at b7e7176 baz

$ git lola
* b7e7176 (HEAD, master) baz
| * c7256de (otherguy) bar
|/  
* 9968f79 foo

正如git rev-parse手册中所记录的那样

<rev>^,例如HEAD^, v1.5.1^0 对修订形参加上后缀^表示该提交对象的第一个父对象。^<n>表示第n个父结点(即<rev>^等同于<rev>^1)。作为一个特殊规则,<rev>^0表示提交本身,当<rev>是引用提交对象的标记对象的对象名时使用。

所以在调用git重置之前,HEAD^(或HEAD^1)是b7e7176, HEAD^2是c7256de,即分别是合并提交的第一个和第二个父节点。

小心git重置——很难,因为它会破坏工作。


我有这个问题,解决方案是查看提交图(使用gitk),并看到我有以下:

*   commit I want to cherry-pick (x)
|\  
| * branch I want to cherry-pick to (y)
* | 
|/  
* common parent (x)

我现在明白我想做什么了

git cherry-pick -m 2 mycommitsha

这是因为- m1会基于公共父结点进行合并而- m2则基于分支y进行合并,这就是我要选择的。


在最初的问题中,git错误的“-m选项”可能错误地表示提交消息。正如在其他答案中解释的那样,使用'-m n'指定merge的第n个父节点,以选择您认为是主干线的父节点。