git 将远程恢复到带有合并的特定提交不适用于 -m
git revert remote to a particular commit with a merge doesn't work with -m
我正在尝试将我们的远程回购恢复到之前的提交。树如下图:
我们的想法是,我们希望回到那个提交,而不需要任何从 master 分支中拉出来的人必须处理因重置回提交 2dda031
而产生的问题。所以我改用 git revert
。
我正在尝试使用 git revert --no-commit 2dda031..HEAD
来做到这一点
但是,我得到这个错误:
error: commit d064f7c3b04a2bda30c43a32afac822c6af633c0 is a merge but no -m option was given.
fatal: revert failed
这是预期的,因为 d064f7c
是合并(47d4161
也是)。所以按照建议 here 我这样做:
git revert --abort
git revert --no-commit -m 1 2dda031..HEAD
然后我收到错误消息:
error: mainline was specified but commit cb420e0 is not a merge.
fatal: revert failed
所以我只是觉得我在循环。有人可以告诉我恢复到该提交的正确方法(同时恢复历史记录)吗?
编辑(下面是原始答案):让我首先将您的图形转换为文本,(我希望)没有拼写错误或其他严重错误。这就是您现在所拥有的,正如 git log --graph --oneline
可能显示的那样(虽然 --graph --oneline
可能会选择稍微不同的提交顺序——图形查看器生成的蓝线和绿线可能按提交日期排序,而不考虑拓扑,而不是先按拓扑排序):
* cb420e0 (master, ...) evert "Update README.md"
* 7a16df4 Update README.md
* 7564754 Update README.md
* 214cd47 Update README.md
* d064f7c Merge pull request #6 from ...
|\
* | d936a24 Changing Run instructions
* | 2cbd7c2 Minor edits for Google Drive link
* | 1a3d871 Updated process documentation with google drive link
| * 0594132 (TrustM..., ...) Added some comments to various scripts.
| * 7e060c4 Updated the JSON dialogues and implemented the Trust mechanism
|/
* 4d7f49b Configured script inputs and enabled mouse during pause screen.
* 47d4161 Merge pull request #5 from ...
|\
| * e999b3d (origin/Trying...) Adjusted ray cast length to be more realistic.
| * 953e4c3 Fully functional dialogue system implemented.
* | 1f33079 updated wiki to reflect marking of prototype
| * 09e350b Added in most of the Yarn framework
| * 2dda031 fixed heirarchy of files
| * bf667cc Merge branch 'develop' of ...
| |\
| * | 79e068d Character placement
(我们看不到低于此点的任何内容,但显然必须有更多提交)。
我猜你想要返回的提交状态是 2dda031 fixed heirarchy of files
。
现在,最棘手的部分是这个状态 "lives on" what was apparently a side branch, under the "Merge pull request #5 from ..." 犯罪。如果在还原过程中的某个时刻,您要 运行 git revert -m <some-number> 47d4161
,您将告诉 Git 将 47d4161
与其第一个 parent、1ff3079
,或者反对它的第二个 parent,d999b3d
。这些差异中的第一个显示了自合并基础以来每次提交的效果——无论是什么提交:我们无法从图表的这个片段中看到它;我们需要更多图表来找到它,因为它位于此处 "screen" 的底部 - 这两个中的一个,另一个差异显示了自合并基础到另一个的每次提交的效果。所以用 -m 1
恢复基本上消除了以下效果:
* e999b3d (origin/Trying...) Adjusted ray cast length to be more realistic.
* 953e4c3 Fully functional dialogue system implemented.
* 09e350b Added in most of the Yarn framework
* 2dda031 fixed heirarchy of files
* bf667cc Merge branch 'develop' of ...
...
而使用 -m 2
基本上消除了以下效果:
* 1f33079 updated wiki to reflect marking of prototype
...
(在这两种情况下,可能会有更多我们在这里看不到的提交)。我很清楚你不想那样做,但我不确定。
但是请注意,如果您只是提取提交 2dda031
的内容,您 仍然 失去 1f33079
的效果以及任何其他提交可能低于它,因为你在 origin/Trying...
.
之前获得了几次提交的状态
关于提交 d064f7c
,事情更简单,因为它只是从合并基础 4d7f49b
合并 d936a24
和 0594132
。如果你想撤销提交 1a3d871
+2cbd7c2
+d936a24
的影响,你可以 git revert -m 1 d064f7c
。如果您想撤消提交 0594132
+7e060c4
的影响,您可以 git revert -m 2 d064f7c
。但是,由于您(大概)想要撤消其中 所有 的影响,因此更简单的方法是单独撤消它们,完全跳过合并。
由于您可能还想通过 214cd47
撤消 cb420e0
,您只需单独撤消这些。
如果您想保持 1f33079
和更早提交的效果,请不要还原它们。如果你想撤销它们的效果,你可以git revert -m 2 47d4161
,它会一次性全部撤销。我怀疑你想要那个,但和以前一样,这取决于你。
请注意,任何还原都可以是 运行 和 -n
(在索引和 work-tree 中还原而不提交),但是一旦你开始了一系列 -n
操作,您必须继续 -n
并最终提交,然后才能在没有 -n
.
的情况下开始新的还原
根据您想要的结果,最简单的方法可能是从提取提交 47d4161
的 内容 开始——树状态最早可追溯到你可以不做单独的 commit-backouts——然后在每个额外的提交上使用 git revert -n
来恢复。要提取这些内容,您可以使用 git checkout <commit> -- .
来避免删除索引和 work-tree 条目的轻微风险,因为那时是新的文件,或者使用 git read-tree --reset -u <commit>
来避免风险(见备注下面,也是原始答案)。我会选择后者,给出:
git read-tree --reset -u 47d4161
git revert -n e999b3d
git revert -n 953e4c3
git revert -n 09e350b
(假设你得到了最终的 work-tree 并且索引表明你当然想要拥有)。
(原始答案在下方。)
Git 的 revert
不会将 还原为 提交(这使得命令命名不当:它使用了错误的动词)。它所做的是退出(即"revert")一个特定的提交,或者可能是一组提交。1 你已经完成了 2dda031..HEAD
,因为这个范围语法实际上意味着 HEAD ^2dda031
,即从 HEAD
可以到达的所有提交的集合,不包括(减去, set-subtraction) 可从 2dda031
.
到达的所有提交集
现在,由于合并,这里有多个问题。首先是排除 2dda031
及其 parents 无法排除合并的另一部分,因此您将还原太多提交。第二个问题是,从某种意义上说,合并提交是一个提交,随着它的 single-commit 改变,"all of the changes being brought in by a side branch".2 第三个是在为了恢复合并提交,您必须指定要考虑的"side",但为了恢复non-merge,您不能 指定任何 "side".
其中一些问题的解决方案是完全避免还原合并,而其他问题的解决方案是 仅 还原合并(如果适用)。但还有另一种更简单的方法,具体取决于您的实际目标:如果真的要转rt 到 提交,Git 动词实际上是 git checkout
——但是有一些陷阱。请参阅 this answer 相关(甚至可能重复,具体取决于您的目标)问题。 git rm -r .
的原因是删除当前索引中不会被 git checkout <hash> -- .
步骤提取的所有文件。
有一个 short-cut 可以用来代替 git rm -r . && git checkout <hash> -- .
序列,它也不依赖于当前的工作目录:您可以 运行 git read-tree --reset -u <hash>
。这将丢弃索引的当前内容 (--reset
) 并将它们替换为指定提交的内容 (<hash>
参数),然后更新 work-tree 以匹配,删除任何文件从索引中删除并更新索引中更新的任何文件。
请注意,在所有情况下,最终结果都在索引和 work-tree 中,但尚未提交,因此您必须 运行 git commit
.
请注意,如果您的目标实际上不是将 还原为 特定提交,而是还原引入的一系列更改,则方法为git revert -n
是根据需要使用尽可能多的单独 git revert
命令:每个 change-set 一个要退出的命令。其中一些可能是 git revert
s of non-merges,有些可能是 git revert
s of merges。不过请参阅脚注 2,并记住无论您使用哪种方法,退出您想要保留的更改毕竟会成功(更改将消失),即使您想要保留它也是如此。
1因此有些VCS里的动词是"backout".
2这个描述在一个微妙但非常重要的方面是错误的:合并 combines 变化。合并的输入是两组更改:一组从合并基础提交到 --ours
提交,另一组从合并基础提交到 --theirs
提交。这两个 change-set 可能会重叠。如果他们这样做,并且重叠在任何时候都是 "sufficiently similar",则 Git 只需要 一个副本 的变化。如果 Git 复制了某个更改 Δ,其中 Δ 出现在两个 change-set 中,并且您恢复 --theirs
change-set,Git 退出 Δ 即使它也在 --ours
change-set 中。(如果您取消 --ours
增量,同样的推理也适用:Git不应该,但确实将其从作为 --theirs
引入的版本中删除。)
我正在尝试将我们的远程回购恢复到之前的提交。树如下图:
我们的想法是,我们希望回到那个提交,而不需要任何从 master 分支中拉出来的人必须处理因重置回提交 2dda031
而产生的问题。所以我改用 git revert
。
我正在尝试使用 git revert --no-commit 2dda031..HEAD
但是,我得到这个错误:
error: commit d064f7c3b04a2bda30c43a32afac822c6af633c0 is a merge but no -m option was given.
fatal: revert failed
这是预期的,因为 d064f7c
是合并(47d4161
也是)。所以按照建议 here 我这样做:
git revert --abort
git revert --no-commit -m 1 2dda031..HEAD
然后我收到错误消息:
error: mainline was specified but commit cb420e0 is not a merge.
fatal: revert failed
所以我只是觉得我在循环。有人可以告诉我恢复到该提交的正确方法(同时恢复历史记录)吗?
编辑(下面是原始答案):让我首先将您的图形转换为文本,(我希望)没有拼写错误或其他严重错误。这就是您现在所拥有的,正如 git log --graph --oneline
可能显示的那样(虽然 --graph --oneline
可能会选择稍微不同的提交顺序——图形查看器生成的蓝线和绿线可能按提交日期排序,而不考虑拓扑,而不是先按拓扑排序):
* cb420e0 (master, ...) evert "Update README.md"
* 7a16df4 Update README.md
* 7564754 Update README.md
* 214cd47 Update README.md
* d064f7c Merge pull request #6 from ...
|\
* | d936a24 Changing Run instructions
* | 2cbd7c2 Minor edits for Google Drive link
* | 1a3d871 Updated process documentation with google drive link
| * 0594132 (TrustM..., ...) Added some comments to various scripts.
| * 7e060c4 Updated the JSON dialogues and implemented the Trust mechanism
|/
* 4d7f49b Configured script inputs and enabled mouse during pause screen.
* 47d4161 Merge pull request #5 from ...
|\
| * e999b3d (origin/Trying...) Adjusted ray cast length to be more realistic.
| * 953e4c3 Fully functional dialogue system implemented.
* | 1f33079 updated wiki to reflect marking of prototype
| * 09e350b Added in most of the Yarn framework
| * 2dda031 fixed heirarchy of files
| * bf667cc Merge branch 'develop' of ...
| |\
| * | 79e068d Character placement
(我们看不到低于此点的任何内容,但显然必须有更多提交)。
我猜你想要返回的提交状态是 2dda031 fixed heirarchy of files
。
现在,最棘手的部分是这个状态 "lives on" what was apparently a side branch, under the "Merge pull request #5 from ..." 犯罪。如果在还原过程中的某个时刻,您要 运行 git revert -m <some-number> 47d4161
,您将告诉 Git 将 47d4161
与其第一个 parent、1ff3079
,或者反对它的第二个 parent,d999b3d
。这些差异中的第一个显示了自合并基础以来每次提交的效果——无论是什么提交:我们无法从图表的这个片段中看到它;我们需要更多图表来找到它,因为它位于此处 "screen" 的底部 - 这两个中的一个,另一个差异显示了自合并基础到另一个的每次提交的效果。所以用 -m 1
恢复基本上消除了以下效果:
* e999b3d (origin/Trying...) Adjusted ray cast length to be more realistic.
* 953e4c3 Fully functional dialogue system implemented.
* 09e350b Added in most of the Yarn framework
* 2dda031 fixed heirarchy of files
* bf667cc Merge branch 'develop' of ...
...
而使用 -m 2
基本上消除了以下效果:
* 1f33079 updated wiki to reflect marking of prototype
...
(在这两种情况下,可能会有更多我们在这里看不到的提交)。我很清楚你不想那样做,但我不确定。
但是请注意,如果您只是提取提交 2dda031
的内容,您 仍然 失去 1f33079
的效果以及任何其他提交可能低于它,因为你在 origin/Trying...
.
关于提交 d064f7c
,事情更简单,因为它只是从合并基础 4d7f49b
合并 d936a24
和 0594132
。如果你想撤销提交 1a3d871
+2cbd7c2
+d936a24
的影响,你可以 git revert -m 1 d064f7c
。如果您想撤消提交 0594132
+7e060c4
的影响,您可以 git revert -m 2 d064f7c
。但是,由于您(大概)想要撤消其中 所有 的影响,因此更简单的方法是单独撤消它们,完全跳过合并。
由于您可能还想通过 214cd47
撤消 cb420e0
,您只需单独撤消这些。
如果您想保持 1f33079
和更早提交的效果,请不要还原它们。如果你想撤销它们的效果,你可以git revert -m 2 47d4161
,它会一次性全部撤销。我怀疑你想要那个,但和以前一样,这取决于你。
请注意,任何还原都可以是 运行 和 -n
(在索引和 work-tree 中还原而不提交),但是一旦你开始了一系列 -n
操作,您必须继续 -n
并最终提交,然后才能在没有 -n
.
根据您想要的结果,最简单的方法可能是从提取提交 47d4161
的 内容 开始——树状态最早可追溯到你可以不做单独的 commit-backouts——然后在每个额外的提交上使用 git revert -n
来恢复。要提取这些内容,您可以使用 git checkout <commit> -- .
来避免删除索引和 work-tree 条目的轻微风险,因为那时是新的文件,或者使用 git read-tree --reset -u <commit>
来避免风险(见备注下面,也是原始答案)。我会选择后者,给出:
git read-tree --reset -u 47d4161
git revert -n e999b3d
git revert -n 953e4c3
git revert -n 09e350b
(假设你得到了最终的 work-tree 并且索引表明你当然想要拥有)。
(原始答案在下方。)
Git 的 revert
不会将 还原为 提交(这使得命令命名不当:它使用了错误的动词)。它所做的是退出(即"revert")一个特定的提交,或者可能是一组提交。1 你已经完成了 2dda031..HEAD
,因为这个范围语法实际上意味着 HEAD ^2dda031
,即从 HEAD
可以到达的所有提交的集合,不包括(减去, set-subtraction) 可从 2dda031
.
现在,由于合并,这里有多个问题。首先是排除 2dda031
及其 parents 无法排除合并的另一部分,因此您将还原太多提交。第二个问题是,从某种意义上说,合并提交是一个提交,随着它的 single-commit 改变,"all of the changes being brought in by a side branch".2 第三个是在为了恢复合并提交,您必须指定要考虑的"side",但为了恢复non-merge,您不能 指定任何 "side".
其中一些问题的解决方案是完全避免还原合并,而其他问题的解决方案是 仅 还原合并(如果适用)。但还有另一种更简单的方法,具体取决于您的实际目标:如果真的要转rt 到 提交,Git 动词实际上是 git checkout
——但是有一些陷阱。请参阅 this answer 相关(甚至可能重复,具体取决于您的目标)问题。 git rm -r .
的原因是删除当前索引中不会被 git checkout <hash> -- .
步骤提取的所有文件。
有一个 short-cut 可以用来代替 git rm -r . && git checkout <hash> -- .
序列,它也不依赖于当前的工作目录:您可以 运行 git read-tree --reset -u <hash>
。这将丢弃索引的当前内容 (--reset
) 并将它们替换为指定提交的内容 (<hash>
参数),然后更新 work-tree 以匹配,删除任何文件从索引中删除并更新索引中更新的任何文件。
请注意,在所有情况下,最终结果都在索引和 work-tree 中,但尚未提交,因此您必须 运行 git commit
.
请注意,如果您的目标实际上不是将 还原为 特定提交,而是还原引入的一系列更改,则方法为git revert -n
是根据需要使用尽可能多的单独 git revert
命令:每个 change-set 一个要退出的命令。其中一些可能是 git revert
s of non-merges,有些可能是 git revert
s of merges。不过请参阅脚注 2,并记住无论您使用哪种方法,退出您想要保留的更改毕竟会成功(更改将消失),即使您想要保留它也是如此。
1因此有些VCS里的动词是"backout".
2这个描述在一个微妙但非常重要的方面是错误的:合并 combines 变化。合并的输入是两组更改:一组从合并基础提交到 --ours
提交,另一组从合并基础提交到 --theirs
提交。这两个 change-set 可能会重叠。如果他们这样做,并且重叠在任何时候都是 "sufficiently similar",则 Git 只需要 一个副本 的变化。如果 Git 复制了某个更改 Δ,其中 Δ 出现在两个 change-set 中,并且您恢复 --theirs
change-set,Git 退出 Δ 即使它也在 --ours
change-set 中。(如果您取消 --ours
增量,同样的推理也适用:Git不应该,但确实将其从作为 --theirs
引入的版本中删除。)