【问题标题】:Git revert command errorGit还原命令错误
【发布时间】:2014-05-08 08:57:07
【问题描述】:

当我在 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

谁能解释一下为什么会出现这个错误?

-谢谢 克里希纳

【问题讨论】:

    标签: git git-revert


    【解决方案1】:

    阅读罚款manpage :-):

    通常您无法还原合并,因为您不知道哪一边 的合并应该被认为是主线。此选项指定父编号 (从 1 开始)的主线,并允许 revert 反转相对于 指定的父级。

    [...]

    还原合并提交声明您永远不会想要树 合并带来的变化。结果,以后的合并只会 引入由非祖先的提交引入的树更改 先前还原的合并。这可能是也可能不是您想要的。

    问题是合并提交比常规提交更复杂 - 它不仅更改文件,还将两个分支链接在一起。还原它时,您必须决定(并告诉 git)您是只想回滚它引入的文件更改,还是回滚分支的链接。

    • 如果您想回滚更改,但保留分支的链接,请按照手册页中的说明使用选项 -mgit merge
    • 如果您想完全撤消合并,您必须重写历史记录(使用git rebasegit resetgit cherry-pick 的组合),以及所有the complications that can bring

    您需要什么取决于您恢复提交的原因。

    【讨论】:

      【解决方案2】:

      git revert 要“退出”更改,需要弄清楚更改是什么。

      在大多数普通提交的情况下,更改很容易计算。例如考虑这个 git commit graph 片段:

      ... - G - H ...    <-- HEAD=master
      

      在这里,您位于分支 master,其中包含提交 GH,然后还有更多。

      如果您要求 git 恢复提交 H,它只需要查看“修订版 G 中的所有内容”和“修订版 H 中的所有内容”之间的变化。通过比较GH,Git 可以像你一样做到这一点:

      $ git diff <sha1-of-G> <sha1-of-H>
      

      如果这表明在提交 H 中,您向文件 readme.txt 添加了一行并完全删除了文件 x.h,那么 git 可以通过从 readme.txt 中删除该行并恢复文件 x.h 来撤消此操作来自提交G

      不过,合并提交更复杂。让我们再填写一些提交图:

                    I - J
                  /       \
      ... - G - H           M - N - O  <-- HEAD=master
                  \       /
                    K - L
      

      如果你要求 git 恢复合并提交 M,它应该撤回哪些更改?

      JM 有一组变化:

      $ git diff <sha1-of-J> <sha1-of-M>
      

      (实际上,这些更改是通过提交L 带来的更改,与提交H 相比,这将是提交KL 组合的更改。

      LM 还有另一组可能完全不同的更改:

      $ git diff <sha1-of-L> <sha1-of-M>
      

      (这些变化实际上是IJ中的变化,逻辑相似)。

      您必须告诉 git 要撤消哪些组更改,以及要保留哪些更改。 Git 让你通过指定“主线”来做到这一点。这还依赖于存储在合并提交中的父 ID按特定顺序这一事实。

      假设您在进行合并时正在提交 J,即 master

      $ git checkout master   # i.e., commit J
      $ git merge branch      # i.e., commit L
      

      现在你正在提交O,它仍然是master。分支名称branch 可能不再存在(或可能指向除L 之外的某个提交),但您想丢弃KL 中的更改——即,那些在分支@ 上的更改987654361@ 进行合并时。

      M第一个 父级是 J,因为您将 branch 合并到 master 中,其中 git 通过将 J 设为第一个父级并将 L 设为第二个父级来记录父母。因此,要丢弃来自提交 KL 的更改,您现在可以使用:

      $ git revert -m 1 HEAD~2
      

      (这里HEAD~2 备份两个提交,从ON,然后到M)。然后,Git 可以区分 M^1 (J) 和 M,它发现通过合并分支 branch 引入的更改,如上所述;然后撤消这些更改会导致撤消合并引入的更改。

      请注意,这会生成一个新的提交,生成的图形如下所示:

                    I - J
                  /       \
      ... - G - H           M - N - O - P   <-- HEAD=master
                  \       /
                    K - L
      

      比较提交OP 产生与比较MJ 基本相同的结果(按此顺序,即从JM 的“正常”比较相反)。但是,就 git 中的后续操作而言,您最好通过手动编辑 O 的树并进行新的提交 P 来完成此操作:它不记录(提交消息文本除外) P 本质上是 KL 的还原。


      顺便提一下,在这种特殊情况下,您可以简单地先恢复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
      

      不过,在大合并的情况下,还原每个单独的更改是一项繁重的工作;恢复合并提交本身要容易得多(如果有适当的文档,则可以做到,并在以后理解)。 (此外,上面的“可能”是因为合并处理了在分支的“两侧”所做的相同更改,并且恢复合并避免撤消 KL 中的更改 不是带入M,因为它们出现在I 和/或J。然而,这有点罕见,尤其是在像这样的微小分支结构中。)

      【讨论】:

        猜你喜欢
        • 2015-11-23
        • 2012-01-07
        • 2014-09-01
        • 2021-08-12
        • 1970-01-01
        • 2015-06-12
        • 2017-01-13
        • 1970-01-01
        • 2020-05-16
        相关资源
        最近更新 更多