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

时间:2009-03-13 11:32:39

标签: git git-revert

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

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

例如:我有两个文件,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)

4 个答案:

答案 0 :(得分:60)

是的,您可以使用 git revert 。有关详细信息,请参阅git manual section on this

要点是你可以说:

git revert 4f4k2a

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

答案 1 :(得分:33)

只是评论:

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 Mailing list带来更“完全恢复”;但没有太大的成功:

  

人们偶尔想要“恢复变化”。

     

现在,这可能是:

     
      
  • 之前32到29次修订之间的变化,
  •   
  • 可能是自上次提交以来的所有更改,
  •   
  • 可能是自3次提交以来的更改,或
  •   
  • 它可能只是一个特定的提交。
  •   
  • 用户可能希望将此类转换仅限于特定文件
  •   

eg revertdocumented here,但我不确定它是当前分布的一部分,例如虽然)

  

但最终归结为“恢复变化”。

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标志)。 / p>


让我们假设你有50个已提交的20个文件,你知道旧的提交X引入了不应该发生的更改。
有点管道是有序的 您需要的是列出还原所需的所有特定文件的方法 (如“取消在提交X中所做的更改,同时保留所有后续更改”),
然后,对于他们每个人:

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

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

git merge-file <current-file> <base-file> <other-file> means
将从<base-file><other-file> 的所有更改合并到<current-file>中,您可以恢复已删除的功能纳入所有变化。)

  • from:X(功能已被删除)
  • to:X ^(X之前的提交,函数仍在那里)

注意:'-p'参数允许您首先查看更改,而不对当前文件执行任何操作。如果您确定,请删除该选项。

注意 git merge-file not that simple:您无法像这样引用文件的先前版本。
(你会反复听到令人沮丧的消息: 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!

如果要在之前的提交中对大量文件执行此操作...某些脚本按顺序排列;)

答案 2 :(得分: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来构建新提交会更容易。也许这只是个人的工作方式。

答案 3 :(得分:1)

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