Mercurial - 回退到旧版本并从那里继续

254

我正在一个项目中本地使用Mercurial(它是唯一的仓库,没有从其他地方推送/拉取)。

到目前为止,它有一个线性历史记录。然而,我现在意识到我正在处理的当前事物是一个可怕的方法,我想回到开始之前的版本,并用不同的方式实现它。

我对Mercurial中的branch / revert / update -C命令有些困惑。基本上,我想还原到第38个版本(当前在第45个版本),并让我的下一个提交以38作为父提交,然后从那里继续。我不介意版本39-45永久丢失或进入它们自己的死胡同分支中。

我需要哪个命令/命令集?


6
如果有人感兴趣,这个相关侧栏弹出了一个很好的解释“revert”和“update”的区别的链接:https://dev59.com/SnE95IYBdhLWcg3wAo9U。 - Paolo
7个回答

408
以下是这些命令的速查表:
  • hg update 更改您的工作副本父级修订版本,还更改文件内容以匹配此新父级修订版本。这意味着新提交将从您更新到的修订版本继续进行。

  • hg revert 仅更改文件内容,并保留工作副本父级修订版本不变。通常在您决定不想在工作副本中保留未提交的更改时使用hg revert

  • hg branch 开始一个新的命名分支。将命名分支视为您分配给变更集的标签。因此,如果您执行hg branch red,那么以下变更集将被标记为属于“red”分支。这可以是组织变更集的一种好方法,特别是当不同的人在不同的分支上工作并且您后来想要查看更改集的来源时。但你不想在你的情况下使用它。

如果您使用hg update --rev 38,则变更集39-45将成为死胡同 - 我们称之为悬空头。由于这些悬空头暗示某人需要执行合并,因此在推送时会收到警告。但在您的情况下,您可以继续hg push --force ,因为您确实希望让它挂起。

如果您还没有将版本39-45推送到其他地方,那么您可以将其保留为私有。非常简单:通过使用hg clone --rev 38 foo foo-38,您将获得一个新的本地克隆,该克隆仅包含至版本38。 您可以继续在foo-38中工作,并推送您创建的新(好的)变更集。您仍将拥有旧的(坏的)修订版在您的foo克隆中。(您可以自由地根据需要更改克隆名称,例如将 foo更名为foo-bad并将foo-38更名为foo。)
最后,您还可以使用hg revert --all --rev 38,然后提交。这将创建一个与修订版38完全相同的修订版46。您随后将从修订版46开始工作。这将不会像hg update一样以明确的方式在历史记录中创建分支,但另一方面,您不会收到关于拥有多个heads的投诉。如果我正在与已经基于修订版45创建了他们自己的工作的其他人进行合作,则会使用hg revert. 否则,hg update更加明确。

2
真是太棒了的答案。我使用了hg revert --all --rev ##,它救了我的命 :D - Van Thoai Nguyen
1
关闭悬空头的分支是否更好?这将防止存储库未来发出警告。请参见https://dev59.com/MXA65IYBdhLWcg3wrgsa#3688320 - Zoltán
注意:hg revert --all --rev xxx将修改本地文件,以便从本地存储库中恢复。因此,在执行还原操作之前,您需要更新到要还原的位置。 - Vincent
为了从早期版本分支出来,我首先必须执行还原操作,然后再进行更新。话虽如此,这比大多数解释都要简单明了。 - CodeLurker
有点不好意思问,但我该如何找出所需提交/修订的版本号? - domsson

152
hg update [-r REV]
如果您稍后提交,那么您将会有效地创建一个新的分支。然后,您可以继续仅在此分支上工作,或最终将现有分支合并到该分支中。

6
下一次提交将创建一个新的分支。如果不确定,请先备份您的存储库(包括工作副本),尝试一下,如果不喜欢结果,则可以免费从头开始。 - van
这是一个可疑的答案,因为它会将您当前的更改与旧版本合并,这可能不是您想要做的。正确的答案应该是hg revert。 - Trevor de Koekkoek
答案很好,只是关于合并的部分不太对(我认为问答者不想要合并)。 - ctrl-alt-delor
3
@NeonWarge 中的 "REV" 只是修订版本的占位符,它可以是版本号、哈希值、书签等。Trevor:这并不可疑,因为它不会合并任何内容。也没有必要这样做。 - DanMan

32

我刚遇到了一个需要将单个文件回滚到之前版本的情况,就在我提交和推送之后。其他答案没有涵盖指定这些版本的速记语法,所以这是命令的方式。

hg revert path/to/file -r-2

-2将恢复到上一个提交之前的版本,使用-1仅会撤销当前未提交的更改。


2
我发现这非常有用。当然,对于-r选项,您可以简单地提供修订号。 - Alex
1
您还可以选择特定的版本。例如:hg revert path/to/file -r478 - hookenz

8

在我看来,hg strip -r 39 更适合这种情况。

它需要启用mq扩展,并且与Martin Geisler推荐的“克隆存储库方法”具有相同的限制: 如果更改集已被某种方式发布,它将(可能)在某个时间点返回到您的存储库,因为您只更改了本地存储库。


不知道这个。比删除和重新克隆Repo更容易和清洁。谢谢。 - Reinstate Monica -- notmaynard

6
使用 hg update -r REV 后,如何提交更改并推送不太明确。如果你在更新后尝试提交,Mercurial 不会认为有任何更改。因此,您需要先对任何文件进行更改(例如 README),这样 Mercurial 才能识别到您已经做出了新的更改,然后才可以提交。这将创建两个分支。在推送之前,您需要消除另一个分支,然后按照 无操作合并 步骤解决该问题。然后您就可以推送了。

你可以在旧分支上执行 commit --close-branch 命令来关闭它。你也可以使用 push -f 命令来推送新的提交,但这可能会导致当前分支不明确。 - ctrl-alt-delor

5
上面的答案非常有用,我学到了很多。然而,对于我的需求,简洁的答案是:
hg revert --all --rev ${1}

hg commit -m "Restoring branch ${1} as default"

其中${1}是修订版号或分支名称的数字。这两行实际上是bash脚本的一部分,但如果您想手动执行它们,它们也可以正常工作。

如果您需要向发布分支添加热修复程序,但需要从默认版本构建(直到我们的CI工具正确并能够从分支构建并且随后也不再需要发布分支),则此操作非常有用。


1
我会安装Tortoise Hg(Mercurial的免费GUI),并使用它。然后,您只需右键单击可能要返回的修订版本-所有提交消息都在您眼前-并“还原所有文件”。这使得在文件集的不同版本之间向后和向前滚动变得直观和容易,如果您想确定问题何时首次出现,这非常有用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接