Mercurial:如何修改上一次提交?


211

我正在寻找git commit --amendMercurial 的对立部分,即一种修改工作副本链接到的提交的方法。我只对最后一次提交感兴趣,而不对先前的任意提交感兴趣。

此修订程序的要求是:

  • 如果可能的话,它不需要任何扩展。它不得要求非默认扩展名,即,与Mercurial官方安装无关的扩展名。

  • 如果修改的提交是我当前分支的负责人,则不应创建任何新负责人。如果提交不是头,则可以创建一个新的头。

  • 该过程应该是安全的,以确保无论出于何种原因修改都失败了,我都希望恢复与修改前相同的工作副本和存储库状态。换句话说,如果修改本身可能失败,那么应该有一个故障保护过程来恢复工作副本和存储库状态。我指的是“故障”,它属于修改程序的性质(例如冲突),而不是文件系统相关的问题(例如访问限制,无法锁定文件以进行写入等)。 )

更新(1):

  • 该过程必须是可自动化的,因此它可以由GUI客户端执行,而无需任何用户交互。

更新(2):

  • 不得触摸工作目录中的文件(某些修改后的文件可能有文件系统锁定)。这尤其意味着,一种可行的方法在任何时候都不需要干净的工作目录。

Answers:


289

Mercurial 2.2发行版中,您可以使用--amend选项with hg commit更新当前工作目录的最后一次提交。

命令行参考

--amend标志可用于通过新提交修改工作目录的父级,该提交包含除当前由hg状态报告的更改(如果有的话)之外的父级更改。旧的提交存储在.hg / strip-backup中的备份包中(有关如何还原它,请参阅hg帮助包和hg帮助解除捆绑)。

除非指定,否则消息,用户和日期均来自修订的提交。如果未在命令行上指定消息,则编辑器将打开并显示修改后的提交的消息。

很棒的事情是该机制是“安全的”,因为它依赖于相对较新的“阶段”功能来防止可能会更改历史记录的更新,而这些历史记录已在本地存储库之外提供。


2
好答案!实验性的Evolution扩展使您可以安全地修改非head提交。旧的提交将被标记为过时和隐藏。使用非发布服务器,您甚至可以在推送变更集之后安全地执行此操作。
Martin Geisler

5
只需在最后一次提交时更新消息:hg commit --amend -m“这是我的新消息”
Jay Sheth,

52

您可以使用3个选项来编辑Mercurial中的提交:

  1. hg strip --keep --rev -1撤消最后(1)个提交,因此您可以再次执行(有关更多信息,请参见此答案)。

  2. 使用Mercurial随附的MQ扩展

  3. 即使Mercurial没有随附,Histedit扩展程序也值得一提

您还可以查看编辑历史记录在Mercurial Wiki页面上。

总之,编辑历史真的很难和气馁。而且,如果您已经进行了更改,则几乎无能为力,除非您完全控制所有其他克隆。

我对git commit --amend命令并不十分熟悉,但是AFAIK和Histedit似乎是最接近的方法,但遗憾的是,Mercurial并未附带该命令。MQ的使用确实很复杂,但是您几乎可以用它做任何事情。


1
我不确定为什么错过了回滚,但它似乎(几乎)满足了我的要求。唯一的问题是,当已为我的原始提交删除了一个文件,并且为我的修订提交又将其复活了:回滚之前,它将被取消版本控制,回滚之后,将被安排删除(但是该文件仍然存在于工作目录)
mstrap

@Marc我不确定我是否理解您的问题,但是请看一下cancel命令,我认为这正是您要寻找的。
krtek

我认为“忘记”在这里不会有所帮助。这是更详细的问题:(1)我的修订版为2(2)删除“文件”并进行了其他一些更改(3)提交更改,导致版本为3(4)现在,我改变主意并决定不应从提交中删除“文件”,因此我想修订版本3。因此,我将重新添加现在未版本化的“文件”(5)现在执行回滚:它将重置目录状态并标记为“文件”中删除。(6)现在再次执行“ hg commit”时,“ file”将保持被删除的状态,尽管不应再使用了。对此的自动修复效果如何?
mstrap

1
对于自动化部分,我不知道,但是您可以hg revert myfile撤消删除操作。也许也可以重新添加hg add文件rollback
2011年

3
我同意应避免编辑已发布更改的历史记录,但是对本地历史记录的编辑是DVCS的亮点之一。具有qimport的MQ是纯历史编辑AFAICT。
mstrap

38

GUI等效于hg commit --amend

这也可以在TortoiseHG的GUI中使用(我使用的是v2.5):

夹到“提交”视图,或者在工作台视图中选择“工作目录”条目。“提交”按钮具有一个名为“修改当前修订版本”的选项(单击按钮的下拉箭头即可找到它)。

在此处输入图片说明

          ||
          ||
          \/

在此处输入图片说明

警告购买者

仅当Mercurial版本至少为2.2.0,并且当前版本不是公共版本,不是补丁程序且没有子代时,才启用此额外选项。[...]

单击该按钮将调用“提交-修改”来“修改”修订。

在THG开发者频道上有更多关于此的信息


非常有帮助,谢谢。THG非常聪明,可以将提交(修改)消息默认为来自先前提交的消息-正是我想要的。
UuDdLrLrSs

7

我正在调整krtek编写的内容。更具体地说,解决方案1:

假设:

  • 您已提交一个(!)变更集,但尚未推送
  • 您想要修改此变更集(例如,添加,删除或更改文件和/或提交消息)

解:

  • 用于hg rollback撤消上一次提交
  • 再次提交新的更改

回滚实际上撤消了上一个操作。它的工作方式非常简单:HG中的常规操作只会附加到文件中;这包括提交。Mercurial会跟踪上一个事务的文件长度,因此可以通过将文件截短到原来的长度来完全撤消一步。


1
感谢您的解决方案(1);回滚只剩下一个小问题,请在krtek的解决方案上查看我的评论。
mstrap

8
需要回滚的一件事要强调,因为它可以吸引人,这是回购中的最后一笔交易,而不是最后一次提交。因此,如果其他原因导致对存储库的写操作,则回滚将无济于事。要记住这是一个微妙但重要的事情。一旦关闭了回滚窗口,MQ和histedit就可以提供帮助,但是仍然只能达到一定程度。
Paul S

7

假设您尚未传播更改,则可以执行以下操作。

  • 添加到您的.hgrc:

    [extensions]
    mq =
    
  • 在您的存储库中:

    hg qimport -r0:tip
    hg qpop -a
    

    当然,您不必从零修订版开始或弹出所有补丁,对于最后一个pop(hg qpop)就足够了(请参阅下文)。

  • 删除.hg/patches/series文件中的最后一项,或者删除您不喜欢的补丁。也可以重新排序。

  • hg qpush -a; hg qfinish -a
  • 删除.diff仍位于.hg / patches 中的文件(未应用的补丁)(在您的情况下应该是一个)。

如果你不想收回所有的补丁,您可以通过使用编辑hg qimport -r0:tip(或类似),然后编辑的东西,并使用hg qrefresh合并变成你的筹码最顶端的补丁。阅读hg help qrefresh

通过编辑.hg/patches/series,您甚至可以删除几个补丁,或重新排序一些补丁。如果您的最新版本是99,则可以使用hg qimport -r98:tip; hg qpop; [edit series file]; hg qpush -a; hg qfinish -a

当然,强烈建议不要这样做,并且要冒险备份所有内容,然后再执行此操作!

附带一提,我在仅专用存储库上做了无数次。


我还考虑过使用mq-extension,但是它需要进行很多操作,其中某些操作可能会失败(例如,如果涉及二进制文件)。此外,必须接受.hg / patch / series的编辑,因为此过程应在GUI客户端中使用(我已经更新了上述要求)
mstrap

嗯,抱歉,这不适合您,在私有存储库上确实会打屁股(带有备份-我已经用胖手指破坏了代表^^)。在使用hg qfold,btw 推送局部更改之前,将补丁组合成一个很酷
hochl11

+1表示使用MQ,但是我认为您过分了。他只是问有关修改最后一次提交的问题。而且,导入将在合并后立即终止。'qimport -r提示;<edit stuff>; qrefresh -e; qfin -a'将完成工作(-e编辑提交消息)
Paul S

是的,合并是一个问题,我通常只弹出一个补丁并使用hg import -r<prev>:tip。可怜的是,以前的版本没有捷径,就像在Subversion中一样。
hochl

2

Mercurial的最新版本包括evolve提供hg amend命令的扩展。这允许修改提交而不会丢失版本控件中的修改前历史记录。

hg修改[选项] ... [文件] ...

别名:刷新

将变更集与更新结合起来,并用新的变更集替换

Commits a new changeset incorporating both the changes to the given files
and all the changes from the current parent changeset into the repository.

See 'hg commit' for details about committing changes.

If you don't specify -m, the parent's message will be reused.

Behind the scenes, Mercurial first commits the update as a regular child
of the current parent. Then it creates a new commit on the parent's
parents with the updated contents. Then it changes the working copy parent
to this new combined changeset. Finally, the old changeset and its update
are hidden from 'hg log' (unless you use --hidden with log).

有关扩展程序的完整说明,请参阅https://www.mercurial-scm.org/doc/evolution/user-guide.html#example-3-amend-a-changeset-with-evolveevolve


重用相同的提交消息是一个不错的功能!
mpen

0

可能无法解决原始问题中的所有问题,但是由于这似乎是关于如何修改汞含量以更改为先前提交的事实,因此,我将添加2美分的信息。

如果您像我一样,并且只希望在不添加任何文件的情况下修改以前的提交消息(修正错字等),则可以使用

hg commit -X 'glob:**' --amend

如果没有任何包含或排除模式,hg commit则默认情况下将包含工作目录中的所有文件。应用模式-X 'glob:**'将排除所有可能的文件,仅允许修改提交消息。

在功能上与git commit --amend在索引/阶段中没有文件时相同。


0

另一种解决方案是使用uncommit命令从当前提交中排除特定文件。

hg uncommit [file/directory]

当您要保留当前提交并从提交中取消选择某些文件时,这将非常有用(特别是对于files/directories已删除的文件)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.