【问题标题】:Git revert does not work as expectedGit 还原无法按预期工作
【发布时间】:2013-09-17 16:22:37
【问题描述】:

我在使用 git revert 命令时遇到问题。我使用 Ubuntu 12.04 Linux 和 Git 版本 1.7.9.5。

  1. 我在本地 PC 上创建了一个全新的 b_test_repo,并通过远程 origin b_test_repo 对其进行跟踪。
  2. 我在本地创建了一个包含两行文本的单个文件 (commit A),并且仅在本地 master 分支中成功提交。

为了尝试git revert,我又生成了 3 个提交,每个提交都添加了一行文本。所以我的master 提交历史看起来像:

A - B - C - D

在哪里

  • A - 第 1 行和第 2 行的新文件
  • B - 添加了一行
  • C - 添加了一行
  • D - 添加了一行

在所有这些提交之后,文件包含 5 行:

line1
line2
line3
line4
line5

然后,我想恢复提交B,这将呈现没有line3的文件,这是由提交B添加的:

git status
# On branch master
nothing to commit (working directory clean)

我输入:

git revert -n master~2

在不提交更改的情况下恢复提交B 的效果,但得到以下内容:

error: could not revert 1a13ad6... Adding one line
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'

我很困惑为什么会发生冲突,即为什么 Git 在确定文件中需要更改的内容时遇到问题。

我在这里缺少什么?请赐教!

【问题讨论】:

    标签: git revert


    【解决方案1】:

    删除该行将与以后的版本产生冲突,这会改变 same 行。

    所以正如“What should I do when git revert aborts with an error message?”中提到的,你需要解决合并、添加和提交。

    一种更简单的恢复提交的方法是交互式变基:

    git rebase -i <SHA1 commit a>
    

    然后你放弃提交b
    但这仅在您尚未将分支推送到 upstream repo 时才有效,因为它确实会重写提交历史。

    如果你已经推送了,那么git revert 是正确的方法,以便生成一个取消b 的新提交(并将该新提交推送到上游仓库)。


    详细说明:您的示例会产生以下合并冲突:

    C:\Users\VonC\prog\git\tests\18779372\r1>git lg
    
    * 10b9953  - (HEAD)
    * 07fff99  - c
    * 3d888c4  - b
    * 8c7155f  - a
    

    git lgalias for a fancy git log

    如果有冲突,我更喜欢在合并或还原之前同时查看源(他们的)、目标(我们的)原始部分:

    git config merge.conflictstyle diff3
    

    然后还原:

    git revert -n master~2
    

    那会给出:

    line1
    line2
    <<<<<<< HEAD
    line3
    line4
    line5
    ||||||| 3d888c4... b
    line3
    =======
    >>>>>>> parent of 3d888c4... b
    

    这样,您会看到 git revert 做了什么:合并

    • 提交b的父级(显然不包含b修改)
    • HEAD

    合并无法决定从第三行开始的部分做什么:

    • a 中不存在该部分(=== &gt;&gt;&gt;&gt; 部分:“他们的”部分)
    • b中进行了修改(||||====之间的原始部分,和之前revert一样,只有line3
    • 并且它HEAD 中进行了修改(&lt;&lt;&lt;&lt; |||| 部分,添加了line4line5,尽管line3 看起来没有变化)

    如果以提交a 开头,合并冲突会更加清晰:

    line1
    line2
    line3
    line4
    line5
    

    最后以提交 d 为:

    line1
    line2
    line3b
    line4c
    line5d
    

    (commit b add 'd' to line3, commit c add 'c' to line 4, commit d add 'd' to line 5)

    然后回复会给你:

    git config merge.conflictstyle diff3
    git revert -n master~2
    
    cat afile.txt
    
    line1
    line2
    <<<<<<< HEAD
    line3b
    line4c
    line5d
    ||||||| 4ddccc1... b
    line3b
    line4
    line5
    =======
    line3
    line4
    line5
    >>>>>>> parent of 4ddccc1... b
    

    这里是从第 3 行开始的部分:

    • 等于“他们的”=== &gt;&gt;&gt; 中的 line3 -line4 -line5,它是 b 的父级,或提交 a)
    • 在提交b 中等于line3b-line4 -line5(原始部分||| ===,在合并/还原之前)
    • 等于line3b-line4c-line5d in HEAD '我们的' &lt;&lt;&lt; |||

    三种不同的内容,没有办法让merge知道该怎么做。

    【讨论】:

    • Re: line1 line2 >>>>>> parent of 3d888c4... b 这样,您就会看到 git revert 做了什么:合并:提交 b 的父级(显然没有'不包含 b 修改)和 HEAD ----------- 嗯,在我看来,合并确实是恢复提交 b 的合理策略?!
    • @BudM 但是...答案的其余部分应清楚地说明合并无法如何自动解决。你能指出我的回答中不清楚的部分吗?
    • 对不起,我的意思是说通过合并提交 b 的父级和 HEAD 来恢复提交 b 的策略似乎不合逻辑,至少对我来说不是。是的,我看到无法自动解决合并尝试的对象。
    • @BudM 好的。恢复遵循的逻辑策略是什么?
    • 从我读过的关于 revert git 命令的内容来看,考虑到 revert b 应该撤消提交 b 引入的更改,同时保留所有其他更改,即提交 c 和提交 d,应用提交 e ,这会撤消提交 b 的更改,因此此分支历史记录看起来像 abcde,逻辑策略将是 (1) 回滚提交 d、c 和 b 并 (2) 再次应用提交 c 和 d。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-26
    • 2013-12-23
    • 2014-12-09
    • 2016-01-13
    • 2020-09-21
    • 2011-08-17
    • 2012-04-29
    相关资源
    最近更新 更多