9

据我所知,当您想在 Git 中撤消某些操作时,您必须明确地找到命令来撤消您所做的任何事情并发出它。例如,撤消提交并重做的众多方法之一是遵循此处的示例,

$ git commit ...
$ git reset --soft HEAD^
$ edit
$ git add ....
$ git commit -c ORIG_HEAD 

或者要撤消拉动,您可以按照此处的说明进行操作,

$ git reset --hard

但这些命令不一定可以互换使用。Git不允许简单的撤消和重做命令有什么原因吗?与它背后的哲学有关吗?另外,我对其他版本控制系统没有太多经验,但是它们中的任何一个都提供简单的撤消和重做命令吗?

4

5 回答 5

8

这样的概念有几个问题:

  • 并非所有操作都是可逆的。有时这是因为 Git 没有记录足够的信息来推断先前的状态——这通常会非常昂贵。有时像git reset --hardor之类的东西git clean会破坏未跟踪的更改。为了撤消它们,它必须不断地自动备份。有时这是因为撤消的概念是模棱两可的 - 正如您自己指出的那样,有很多方法可以撤消提交。

  • 如果一个操作是可逆的,并且它涉及某种历史,撤消/重做是否也应该在历史中,还是应该让它消失?是否应该通过重置或还原(创建另一个提交来取消它)来撤消提交?

  • 如果不记录你所做的每一件事,你怎么知道最近的操作是什么?假设您向索引添加了一个文件,并创建了一个分支。没有记录显示哪个是第一个。

即使所有内容都已明确定义,实施起来也将是荒谬的工作量。你如何决定什么构成一个单一的动作?一个 Git 命令可能会做很多事情。它应该撤消一步,整个事情吗?如果您已经运行了无数个命令,每个命令都执行了一小步,并且您想撤消这一切怎么办?而且它必须是完美的,完全完美的,因为这种功能会被没有经验的用户使用,他们不知道如何从任何错误中恢复。

因此,正如 Git 为您提供了做事的工具一样,它也为您提供了查看已完成工作的工具,并在需要时自行撤消操作。

此外,关于“重做”,正如您在问题中定义的那样,它是重复一个命令,而不是再次执行原始操作。当您重新提交时,它是一个不同的提交。重新运行之前的命令是命令行 shell 的设计目的。Git 不需要重新发明它。

于 2011-12-02T03:51:55.407 回答
4

实际上,您的第一个示例可以通过以下方式执行:

$ git commit ...
$ edit
$ git add ...
$ git commit --amend

你的第二个例子应该更像git reset --hard <hash>

你的问题的答案是它可能是可能的,但是是的,它更多的是驱动 git 的哲学,这意味着它还没有完成。从理论上讲,没有办法判断您是通过创建提交还是删除另一个提交,但是使用 reflog 可能是可能的......以前没有真正考虑过这种方式。

我不认为'撤消'和'重做'在源代码管理中是很常见的事情,但如果我错了,请纠正我。

编辑:您可能会安装一个脚本,在使用 reflog 后可以执行您正在做的事情 - 不确定那里是否有足够的信息,但值得一试。

于 2011-12-01T18:56:08.880 回答
1

git实际上是作用于存储库、索引和工作目录的多个小工具,因此它没有任何“撤消”的“核心”部分。

也就是说,它确实有各种日志,例如reflog让您回顾所做的事情。

最后,按照惯例,许多 git 操作通常被认为是“只有一种方式”,也就是说,你不希望任何人公开看到它,所以 git 试图“让你绕过街区”上市。如果您仍在本地存储库中,则可以使用各种命令进行备份,但全局撤消不是合适的命令产品。

于 2011-12-02T00:24:22.960 回答
0

连同其他评论,我会查看git stash。很多时候我隐藏了一些工作,修复了其他东西,然后解开并继续。或者对于 web 应用程序,存储我完成和未提交的工作,刷新浏览器,取消存储,打开一个新选项卡,然后来回比较两者以确保与 UI 相关的错误修复没有破坏其他任何东西。

于 2013-02-21T23:32:14.740 回答
0

我有时会将整个活动源代码树快照到一个压缩文件(在 Mac 上单击一次),然后再做一些让我害怕的事情,比如一个大的变基。

因为我将使用的 git 命令只是在本地目录树上执行,所以如果事情变得非常糟糕,这很容易放弃操作并恢复到我之前的状态(包括未签入或修改的文件) .

我不需要经常这样做,但是这个手动“撤消”已经不止一次救了我的屁股。

于 2021-01-22T18:59:04.513 回答