你能否在不产生冲突的情况下还原最后一次提交?

问题描述 投票:3回答:2

注意:stackoverflow的机器人认为问题是主观的,但这是非常事实的 - 我不是在这里征求意见!

假设我只有一个分支,我的提交历史是:A - B - C - D.

如果我在GUI中点击C(如GitKraken或Git for Windows)并执行“还原提交”,则会收到文件冲突消息。

两个问题:

  1. 这是因为恢复“撤消”在C中所做的更改,而GIT现在停留在B和D中,它们以不同的,不兼容的方式修改文件?那是什么原因?
  2. 如果是,这是否意味着您只能恢复最后一次提交?你能否在不产生冲突的情况下还原最后一次提交?

更新:在@RomainValeri的非常有用的说明之后编辑问题。我认为我在还原和重置之间制造了太多混淆。在他的下面的例子中,做

git revert B

导致分支转移

A-B-C-D

A-B-C-D-E

如果B是唯一更改了file2.txt的提交,并且B没有对其他文件进行任何其他更改,则在revert之后创建的新提交E将保留在C和D中进行的所有更改,但不保留在B中进行的更改。 它是否正确?

这是因为,从技术上讲,还原意味着取消,撤消提交的任何更改 - 这是正确的吗?

另外:假设我的工作目录中只有一个文件。如果B是唯一一个更改我的文件中的函数fun1()的提交,而所有其他提交都改变了同一文件中的其他函数,那么恢复B很可能会导致冲突,因为git根据文件中的行来思考,而不是文件中的功能。它是否正确?

所以我们假设B改变了fun1(),C改变了fun2(),D改变了fun3()。然后我意识到在fun1()中B处所做的更改是错误的,我需要撤消它们。如果所有这些函数都在同一个文件中,是否有办法撤消B中的更改,同时保留C和D中的更改?

相反,如果这3个函数中的每一个都在一个单独的文件中,那么撤消一个提交的更改而不影响其他提交则更简单,对吧?

我想这当然是为什么单个文件永远不会太大也不包含太多函数执行不同的事情的众多原因之一,对吧?

git git-revert
2个回答
6
投票

简短的回答:你可以很好地恢复给定的提交(即使是旧的提交)并且没有冲突。


为什么会这样?

git revert在树的当前提示之上创建一个新提交,它不会删除给定的提交,也不会以任何方式修改它。

当您使用revert和merge-base创建的提交之间的HEAD中存在不同之处时,您会发生冲突。


用这个来试试吧

琐碎的例子

鉴于回购树,

Folder1
  file1.txt
  file2.txt
Folder2
  file3.txt

并遵循历史,

A---B---C---D << HEAD

哪里

A使用其内容创建所有文件。 B修改file2.txt C修改file1.txtfile3.txt D进一步修改了file1.txt

那么命令

git revert B

不会产生任何冲突,只是一个新的提交Efile2.txt的新变化。

A---B---C---D---E << HEAD

git revert创建的新提交的内容(在评论后添加)

E的变化是B引入的确切反向变化。

B这样:

$ git show B
commit f3ba29d98c0998297126d686d03d33794cbc0f73
Author: Pythonista <[email protected]>
Date:   Sun Mar 24 20:41:49 2019 +0100

    Some change

diff --git a/javascript/functions.js b/javascript/functions.js
index 543c9cb..5f166d3 100644
--- a/javascript/functions.js
+++ b/javascript/functions.js
@@ -3710,5 +3710,6 @@ function dumpLists(isMixted) {
 // end of process

 createTrigger(window, 'load', START_EVERYTHING);
+doStuff(param);

你会有一个E提交包含:

$ git show E
commit 2ff723970e81d64f3776c081a1f96242589774b6 (HEAD -> master)
Author: Pythonista <[email protected]>
Date:   Sun Mar 24 20:42:33 2019 +0100

    Revert "Some change"

    This reverts commit f3ba29d98c0998297126d686d03d33794cbc0f73.

diff --git a/javascript/functions.js b/javascript/functions.js
index 5f166d3..543c9cb 100644
--- a/javascript/functions.js
+++ b/javascript/functions.js
@@ -3710,6 +3710,5 @@ function dumpLists(isMixted) {
 // end of process

 createTrigger(window, 'load', START_EVERYTHING);
-doStuff(param);

注意在最后一个差异线前面的+-,意思是“加法”(+)和“删除”( - )。


1
投票

除了Git中的直接提交之外,几乎所有的历史制作操作最终都涉及合并。 Rebase,cherry-pick,revert,stash pop,合并当然,它们都合并,只需根据需要选择合并基础。在结账时甚至还有一个合并选项,它使用您当前的结账作为基础进行合并,将新提交作为提示进行合并,将工作树/索引作为另一个提示进行合并,并合并到新的工作树/索引中,这可能非常方便。

对于一个回复,比如A---B... * ... M master和你git revert B,git看看从BA的变化以及从BM的变化,这是你的合并。如果在两组变化中触及了相邻或重叠的线条,那么一些人需要修复文本冲突的可能性,因此Git拒绝默默地执行此操作。无论如何,琐碎的案件需要几秒钟。

© www.soinside.com 2019 - 2024. All rights reserved.