git revert-撤消git的更改(不重写历史记录)

我对脚本进行了更改并提交了。 然后,我进行了其他一些更改,并将其推送到远程存储库等。

然后我意识到我提到的第一个更改是愚蠢的,并且想要撤消它。我可以在不手动复制/粘贴差异的情况下“取消应用”该提交吗?

例如:我有两个文件a.pyb.py

Commit 1:
I delete a function in a.py

Commit 2:
I change a few lines in b.py

Commit 3:
I change the docstring in a.py

我可以撤消该功能的删除,并使其显示为“提交4”(而不是删除提交1)吗?

dbr asked 2020-02-02T08:59:30Z
4个解决方案
61 votes

是的,您可以为此使用git revert。 有关更多信息,请参见git手册部分。

要点是您可以说:

git revert 4f4k2a

其中4f4k2a是您要撤消的提交的ID,它将尝试撤消它。

Jesse Rusak answered 2020-02-02T08:59:49Z
33 votes

只是一个评论:

git revert aCommit

确实还原了所有提交(如“提交的所有文件部分”中所示):
它计算一个反向补丁,将其应用于HEAD并提交。

所以这里有两个问题(第一个很容易解决):

  • 它确实会始终提交,因此您可能要添加git merge-file选项:“ git merge-file”:当连续将多个提交的效果恢复到索引时,此选项很有用。
  • 它不适用于特定文件(如果a.py是提交的一部分,而您又不想还原1000次其他更改,那该怎么办?)
    为此,如果您要提取特定文件,就像它们在另一个提交中一样,您应该看到git merge-file,特别是git merge-file语法(不过,在这种情况下,这并不是您所需要的)

Easy Git(Elijah Newren)尝试使Git Mailing列表更加“完整还原”。 但没有成功:

人们偶尔会想要“还原更改”。

现在,可能是:

  • 在32到29个修订之间的更改,
  • 可能是自上次提交以来的所有更改,
  • 这可能是3年前提交以来的更改,或者
  • 它可能只是一个特定的提交。
  • 用户可能只想将这些还原子集化为特定文件,

git merge-file在此处记录,但我不确定它是否是例如eg的当前发行版的一部分)

但最终归结为“还原更改”。

eg revert --since HEAD~3  # Undo all changes since HEAD~3
eg revert --in HEAD~8     # much like git revert HEAD~8, but nocommit by default
eg revert --since HEAD foo.py  # Undo changes to foo.py since last commit
eg revert foo.py               # Same as above
eg revert --in trial~7 bar.c baz.  # Undo changes made in trial~7 to bar.[ch]

这些类型的“还原数据”是否真的如此不同,以至于需要使用不同的命令,或者简单的还原命令不支持其中某些操作?
当然,大多数用户大部分时间可能会使用“ git merge-file”   形式,但我看不到支持额外功能的危害。

还有...是否有任何基本因素可以阻止核心git采取这种行为?

以利亚

注意:默认情况下,提交对于通用的2795991040582878208命令没有意义,并且“ <other-file>”会因指令而出错(告诉用户添加--in标志)。


假设您已经提交了50个文件,其中有20个文件,您意识到旧的提交X引入了本不应该进行的更改。
一定要进行一些水暖。
您需要的是列出所有需要还原的特定文件的方法
(如“在保留所有后续更改的同时取消在提交X中所做的更改”),
然后,对于每个人:

git-merge-file -p a.py X X^

这里的问题是要恢复丢失的功能,而又不消除您可能想要保留的a.py中的所有后续更改。
该技术有时称为“负合并”。

由于git merge-file表示:
合并了从git merge-file<other-file>git merge-file的所有更改,您可以通过说要合并所有更改来恢复已删除的功能。)

  • 来自:X(已删除功能的位置)
  • 到:X ^(X之前的先前提交,该函数仍在此处)

注意:“ git merge-file”参数使您可以先查看更改,而无需在当前文件上执行任何操作。 如果确定,请删除该选项。

注意:git merge-file并不是那么简单:您不能像以前那样引用文件的早期版本。
(您将一遍又一遍的令人沮丧的消息:error: Could not stat X
你必须:

git cat-file blob a.py > tmp/ori # current file before any modification
git cat-file blob HEAD~2:a.py > tmp/X # file with the function deleted
git cat-file blob HEAD~3:a.py > tmp/F # file with the function which was still there

git merge-file a.py tmp/X tmp/F # basically a RCS-style merge
                                 # note the inversed commit order: X as based, then F
                                 # that is why is is a "negative merge"
diff -u a.py tmp/ori # eyeball the merge result
git add a.py 
git commit -m "function restored" # and any other changes made from X are preserved!

如果要在上一次提交中对大量文件执行此操作,则应按顺序执行一些脚本;)

VonC answered 2020-02-02T09:02:55Z
4 votes

如VonC所指出的,要将更改仅还原到一个提交中的一个文件,我将diff分支(主机或主干或其他),然后checkout我想要还原的文件版本并将其视为新的提交:

$ git checkout trunk
$ git checkout 4f4k2a^ a.py
$ git add a.py
$ git diff              #verify I'm only changing what I want; edit as needed
$ git commit -m 'recover function deleted from a.py in 4f4k2a'

可能有一个直接执行此操作的管道命令,但是如果知道的话,我就不会使用它。 这并不是说我不信任Git,但我也不信任自己-我不相信自己知道自己在提交中以及此后该文件中所做的更改之前所知道的内容。 而且一旦我看了,通过编辑diff来构建一个新的提交就更加容易了。也许那只是个人的工作风格。

Paul answered 2020-02-02T09:03:20Z
1 votes

看看这个git revert问题。如果不按较早的提交顺序(包括最近的提交),还原较早的提交似乎会出现问题。

Mohan Nayaka answered 2020-02-02T09:03:40Z
translate from https://stackoverflow.com:/questions/642264/undo-change-in-git-not-rewriting-history