51

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

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

例如:我有两个文件,a.py并且b.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)

4

4 回答 4

67

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

要点是你可以说:

git revert 4f4k2a

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

于 2009-03-13T11:40:17.003 回答
36

只是一个评论:

git revert aCommit

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

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

  • 它总是提交,因此您可能需要添加-no-commit选项:“ git revert --no-commit aCommit”:这在将多个提交的效果连续恢复到您的索引时很有用。
  • 它不适用于特定文件(如果您的 a.py 是提交的一部分,并且您可能不想恢复 1000 个其他更改)?
    为此,如果您想像在另一个提交中一样提取特定文件,您应该看到git-checkout,特别是git checkout <commit> <filename>语法(尽管在这种情况下,这并不是您所需要的)

Easy Git (Elijah Newren) 试图为Git 邮件列表带来更“完整的还原” ;但没有多大成功:

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

现在,这可能是:

  • 32 和 29 版本之前的变化,
  • 可能是自上次提交以来的所有更改,
  • 可能是自 3 次提交以来的更改,或者
  • 它可能只是一个特定的提交。
  • 用户可能希望将此类还原子集化为特定文件,

eg revert此处记录,但我不确定它是否是当前发行版的一部分,尽管如此)

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

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]

这些类型的“恢复数据”是否真的如此不同以至于需要不同的命令,或者简单的恢复命令不应该支持其中一些操作?
当然,大多数用户大部分时间可能会使用“ eg revert FILE1 FILE2...”形式,但我没有看到支持额外功能的危害。

另外……有什么基本的东西可以阻止核心 git 采用这种行为吗?

以利亚

revert注意:默认情况下,提交对通用命令没有意义,并且“ git revert REVISION”会错误地显示指令(告诉用户添加 --in 标志)。


假设您有 50 个提交的文件,有 20 个文件您意识到旧的提交 X 引入了不应该发生的更改。
一个小管道是为了。
您需要的是一种列出您需要恢复
的所有特定文件的方法 (如“取消提交 X 中所做的更改,同时保留所有后续更改”),
然后,对于每个文件:

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

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

由于表示:包含从to导致的所有更改,因此您可以通过说要合并所有更改来恢复已删除的功能。)git merge-file <current-file> <base-file> <other-file>
<base-file><other-file><current-file>

  • 来自:X(函数已被删除的地方)
  • to: X^(X 之前的上一次提交,该函数仍然存在)

注意:' -p'参数允许您在不对当前文件执行任何操作的情况下首先查看更改。确定后,删除该选项。

注意:并不是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!

如果要对先前提交中的大量文件执行此操作...一些脚本是有序的;)

于 2009-03-13T13:51:47.717 回答
4

正如VonC指出的那样,要在提交中仅恢复对一个文件的更改,我将checkout分支(主干或主干或其他),然后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. 也许这只是个人的工作方式。

于 2009-03-14T16:01:08.860 回答
1

看看这个 git revert 问题。如果不是在包括最近提交的连续序列中,恢复旧提交似乎存在问题。

于 2012-04-15T13:27:25.020 回答