当我恢复git存储库中的特定提交时,它会出现以下错误:
Command for reverting is **git revert <commit-hash>**
error: Commit <commit-hash> is a merge but no -m option was given.
fatal: revert failed
任何人都可以解释为什么会出现这个错误吗?
-Thanks 克里希纳
答案 0 :(得分:4)
只需阅读罚款manpage: - ):
通常您无法恢复合并,因为您不知道哪一方 合并应该被视为主线。此选项指定父编号 (从1开始)主线并允许恢复相反的变化 指定的父级。
[...]
恢复合并提交声明您永远不会想要树 合并带来的变化。因此,以后的合并只会 引入不是祖先的提交所引入的树更改 先前恢复的合并。这可能是也可能不是你想要的。
问题在于合并提交比常规提交更复杂 - 它不仅更改文件,还将两个分支链接在一起。还原它时,您必须决定(并告诉git)您是否只想回滚它引入的文件更改,或者还要链接分支。
-m
至git merge
,如联机帮助页中所述。git rebase
,git reset
和git cherry-pick
的组合)。您需要什么取决于您恢复提交的原因。
答案 1 :(得分:3)
git revert
至&#34;退出&#34;一个变化,它需要弄清楚变化是什么。
在大多数普通提交的情况下,更改很容易计算。考虑一下这个git commit graph fragment:
... - G - H ... <-- HEAD=master
此处您已经提交了master
,G
,然后还有更多提交的分支H
。
如果你要求git恢复提交H
,它只需要查看修订版G
&#34;中的所有内容之间发生了什么变化。和#34;修订版H
&#34;中的所有内容。通过比较G
和H
:
$ git diff <sha1-of-G> <sha1-of-H>
如果这表示在提交H
中,您向文件readme.txt
添加了一行并完全删除了文件x.h
,那么git可以通过从{{1从提交readme.txt
恢复文件x.h
。
但是,合并提交更复杂。让我们填写一些提交图:
G
如果你要求git恢复合并提交 I - J
/ \
... - G - H M - N - O <-- HEAD=master
\ /
K - L
,应该退出哪些更改?
从M
到J
的一系列变化:
M
(事实上,与提交$ git diff <sha1-of-J> <sha1-of-M>
相比,这些更改通过提交L
带来的更改,这将是提交H
和K
的更改组合)。
从L
到L
还有另一种可能完全不同的变化:
M
(这些更改实际上是$ git diff <sha1-of-L> <sha1-of-M>
和I
中的更改,类似的逻辑)。
你必须告诉git 哪些更改要撤消,要保留哪些。 Git通过指定&#34;主线&#34;来完成此操作。这还依赖于以下事实:合并提交中存储的父ID是按特定顺序 。
当您进行合并时,我们假设您处于提交J
,即J
:
master
现在您处于提交$ git checkout master # i.e., commit J
$ git merge branch # i.e., commit L
,仍然是O
。分支名称master
可能不再存在(或者可能指向branch
以外的某些提交),但您要放弃L
和K
中的更改 - 即,当您进行合并时,在分支L
上的那些。
branch
的第一个父级是M
,因为您已将J
合并到branch
中,通过制作master
来进行git记录第一个父级和J
第二个父级。因此,要放弃提交L
和K
的更改,您现在可以使用:
L
(此处$ git revert -m 1 HEAD~2
备份两次提交,从HEAD~2
到O
再到N
)。然后,Git可以M
(M^1
)对J
进行区分,M
找到通过合并分支branch
引入的更改,如上所述;然后撤消这些更改会导致退出合并引入的更改。
请注意,这会进行新的提交,从而产生如下图:
I - J
/ \
... - G - H M - N - O - P <-- HEAD=master
\ /
K - L
比较提交O
和P
产生与比较M
和J
基本相同的事情(按顺序,即&#34;正常&#34;从J
到M
进行比较。然而,就git的后续操作而言,您可能通过手工编辑O
的树并进行新的提交P
来完成此操作:它不会记录(除了提交消息文本)P
基本上是对K
和L
的回复。
顺便提一下,值得注意的是,在这种特殊情况下,您可以先简单地还原L
,然后还原K
,以(可能)获得相同的效果(另外两个额外的效果)提交):
$ L=$(git rev-parse HEAD~2^2) # get sha-1 ID of commit L
$ git revert $L # make new commit P that reverts L
$ git revert $L^ # make new commit Q that reverts L^ = K
然而,通过大合并,恢复每个人的改变是很多工作;恢复合并提交本身要容易得多(要做到这一点,以及稍后理解,如果记录得当)。 (另外,&#34;可能&#34;上面是因为合并处理在&#34;分支的两侧&#34;上进行的相同更改,并且还原合并避免撤消K
和{中的更改{em> not 的{1}}被带到L
,因为他们也发生在M
和/或I
。但是,这有点罕见,特别是在像这样的小分支结构中。)