如何在Mercurial中编辑错误的提交信息?

338

我目前正在使用TortoiseHg(Mercurial),不小心提交了错误的提交消息。我该如何在代码库中编辑此提交消息?


hg metaedit - Thomas Ahle
12个回答

255

更新: Mercurial 添加了--amend,现在应该是首选的选项


你可以使用 hg rollback 撤销最近一次提交(只能是最后一次),然后重新提交它。

重要提示: 这个操作永久删除了最新的提交(或拉取)。因此,如果你已经使用 hg update 更新过工作目录,那么这个提交就再也没有了。所以要先备份一下。

除此之外,你不能更改仓库的历史记录(包括提交消息),因为其中的所有内容都是经过校验和计算的。唯一能做的事情是在给定的变更集之后修剪历史记录,然后相应地重新创建它。

如果你已经发布了你的更改(除非你能够获得所有副本),那么以上任何方法都不会起作用。你也无法"重写历史",包括GPG签名的提交(由其他人完成)。


107
我刚看到一个人因遵循这个建议而被提交毁掉了。当建议别人使用“rollback”命令时,请务必包含一个警告,指出它会永久删除最新的提交(或拉取)。因此,如果你已经执行了类似于“hg update”的操作,并且该提交不再存在于你的工作目录中,那么它将永远消失无踪。 - Ry4an Brase
40
避免回滚/翻转灾难的最简单方法是进行一个简单的更改(添加或删除间隔),并在下一个提交信息中解释您的错误。 - rxgx
3
@rxgx你应该将这个作为单独的回答发布,因为它可能是这里最好的答案。 - Sled
我很惊讶花了两年才加上这个警告。说实话,如果在添加警告之前我需要知道如何做到这一点,我会遵循这个答案中的建议并因此失去工作。 - Clonkex

92

嗯,我过去是这样做的:

想象一下,你有500个提交,而你错误的提交消息在r.498中。

hg qimport -r 498:tip
hg qpop -a
joe .hg/patches/498.diff
(change the comment, after the mercurial header)
hg qpush -a
hg qdelete -r qbase:qtip

5
在使用 hg qpop 到达正确的补丁后,您可以使用 hg qrefresh -e 编辑提交消息。 - Martin Geisler
4
当然,你可以使用任何其他编辑器代替“joe”。 - Kees de Kooter
1
+1 这是我在无法使用简单回滚时使用的方法。Windows 用户应该注意,记事本对 diff 文件中的行尾并不友好。 - Mizipzor
4
我虽然对MQ还不熟悉,但我认为你应该使用hg qfinish -a而不是hg qdelete -r ...。因为在qdelete的帮助文档中写道:“补丁不能被应用”,而在这个例子中,补丁是已经被应用的(而且hgbook也指出“qbase和qtip标识了最底层和最顶层的应用补丁”)。 - maxschlepzig
在这种情况下应该怎么办..? hg qimport -r 301:tip中止:修订版本301是多个分支的根源 - OZZIE
显示剩余3条评论

70
好消息:hg 2.2刚刚添加了类似于git的--amend选项。 此外,在tortoiseHg中,您可以通过选择提交按钮右侧的黑色箭头来使用“修改当前修订版”。

a


5
如果文件内容没有改变,它会阻止你提交更改。即使什么都没改也是如此。 - Luciano

49

非常好的扩展,感谢您的建议! - unexist
2
我来到这个页面是因为histedit在合并提交时无法工作。只是一个警告,你不能使用它来重命名合并。 - Benbob
3
扩展程序的当前版本甚至支持“message”命令,专门用于编辑提交信息。 - Sergii Volchkov
点赞。一旦你学会了如何使用histedit,它就是最简单的方法。 - Ken Mason
1
如果你遇到了 abort: can't rebase immutable changeset 43ab8134e7af 的错误,你必须先将提交翻转为草稿状态:hg phase -f -d 45:c3a3a271d11c - 更多信息请参见Mecurial Phases - Daniel Sokolowski

20

最后一次操作是指当前提交

当最后一次操作是提交时,您可以使用以下命令更改最后一次提交的提交消息:

$ hg rollback

要撤销最近的提交并以新消息重新提交:

$ hg ci -m 'new message'

但要小心,因为回滚命令也会回滚以下操作:

  • 导入
    • 拉取
    • 推送(以此存储库为目标)
    • 取消捆绑

(参见hg help rollback

因此,如果您不确定最后一个Mercurial命令是否为hg ci,请勿使用hg rollback

更改任何其他提交消息

您可以使用分支管理扩展程序mq extension来更改任何提交的消息。该扩展程序随Mercurial一起分发。

只有在公共克隆库中不存在包含您想要重命名的变更集时,这种方法才有用,因为这样会更改该变更集及其后继变更集的哈希值。

这意味着您必须能够删除所有现有的克隆,其中包括要重命名的变更集,否则它们之间的推送/拉取将无法正常工作。

要使用mq扩展程序,您必须显式启用它,例如在UNIX下检查您的~/.hgrc文件,该文件应包含以下行:

[extensions]
mq=

假设你想要更改修订版本X,首先使用qimport导入版本X及其后续版本。现在它们被注册为应用补丁的堆栈。弹出堆栈中除X以外的所有补丁(使用qpop)使得可以通过qrefresh更改X。当提交消息更改后,需要再次推送所有补丁(使用qpop)来重新应用它们,即重新创建后续修订版本。不再需要补丁堆栈,因此可以通过qfinish将其删除。

下面的演示脚本展示了所有操作的实际效果。在这个例子中,第三个变更集的提交消息被重命名。

# test.sh
cd $(dirname $0)
set -x -e -u
echo INFO: Delete old stuff
rm -rf .hg `seq 5`
echo INFO: Setup repository with 5 revisions
hg init
echo '[ui]' > .hg/hgrc
echo 'username=Joe User <juser@example.org>' >> .hg/hgrc
echo 'style = compact' >> .hg/hgrc
echo '[extensions]' >> .hg/hgrc
echo 'mq=' >> .hg/hgrc
for i in `seq 5`; do
  touch $i && hg add $i && hg ci -m "changeset message $i" $i
done
hg log 
echo INFO: Need to rename the commit message on the 3rd revision
echo INFO: Displays all patches
hg qseries
echo INFO: Import all revisions including the 3rd to the last one as patches
hg qimport -r $(hg identify -n -r 'children(2)'):tip
hg qseries
echo INFO: Pop patches
hg qpop -a
hg qseries
hg log 
hg parent
hg commit --amend -m 'CHANGED MESSAGE'
hg log 
echo INFO: Push all remaining patches
hg qpush -a
hg log 
hg qseries
echo INFO: Remove all patches
hg qfinish -a
hg qseries && hg log && hg parent

将它复制到一个空目录中并通过以下方式执行:

$ bash test.sh 2>&1 | tee log
输出应包括原始变更集消息:
+ hg log
[..]
2   53bc13f21b04   2011-08-31 17:26 +0200   juser
  changeset message 3

重命名操作更改了消息:

+ hg log
[..]
2   3ff8a832d057   2011-08-31 17:26 +0200   juser
  CHANGED MESSAGE

(已在Mercurial 4.5.2版本中测试)


19
在TortoiseHg中,右键单击要修改的修订版本。选择“修改历史记录”->“导入MQ”。这将把从Mercurial变更集到所选修订版本的所有修订版本转换为Mercurial队列补丁。选择要修改消息的补丁,它应该自动将屏幕切换到MQ编辑器。编辑屏幕中间的消息,然后单击“QRefresh”。最后,右键单击补丁,选择“修改历史记录”->“完成补丁”,这将将其从补丁转换回更改集。
哦,这假设MQ是此存储库上TortoiseHG的一个活动扩展程序。如果没有,则应该能够单击“文件”->“设置”,单击“扩展”,然后单击mq复选框。它应该警告您在扩展程序激活之前必须关闭TortoiseHg,因此请关闭并重新打开。

这是我总是做的 - 这是最简单的方式! - Rune Andersen
1
点赞。这很棒,因为它允许您对多个草稿更改进行此操作——例如,如果您在所有提交中都放错了票号!:D - user677526

12

编辑:正如其他用户指出的那样,不要使用 MQ,而是使用 commit --amend。现在,这个答案基本上只有历史兴趣了。

正如其他人提到的,MQ 扩展更适合这个任务,而且你不会有破坏你工作的风险。要做到这一点:

  1. 通过在你的 hgrc 中添加类似以下内容来启用 MQ 扩展:

    [extensions]
    mq =
    
  2. 更新到你想要编辑的变更集,通常是 tip:

    hg up $rev
    
  3. 将当前的变更集导入队列:

  4. hg qimport -r .
    
  5. 刷新补丁,并编辑提交信息:

  6. hg qrefresh -e
    
  7. 完成所有应用的补丁(在本例中为一个补丁),并将它们存储为常规的变更集:

  8. hg qfinish -a
    
    我不熟悉TortoiseHg,但命令应该与上面的命令类似。我还认为值得一提的是编辑历史是有风险的;只有当您确信更改集尚未被推送到任何其他地方或从任何其他地方拉取时,才应进行编辑。

3
我用Mercurial 1.7.5测试了一下,你的方法不起作用。qimport会打印“abort: revision <rev> has unmanaged children”。可行的方法是不要调用hg up,从<rev>到tip包括所有内容进行导入,弹出所有内容,然后调用hg qrefresh -e并推送所有内容 - 就像Antonio回答中所描述的那样。 - maxschlepzig
1
“pop everything” 是什么意思? - Milos
他的意思是(将修订版重命名为“rev”),类似于答案,但要从mq堆栈中弹出所有后代。类似这样:hg up``hg qimport -r rev::. hg qpop --all hg qpush hg qrefresh -e(在编辑器中编辑提交消息)hg qpush --all``hg qfinish --all - Joshua Goldberg

6

回滚和重新应用是一个非常简单的解决方案,但它只能帮助最后一次提交。Mercurial Queues则是更加强大的工具(请注意,您需要启用Mercurial Queues扩展才能使用“hg q*”命令)。


1
如果我想编辑的版本不是太旧,我会使用一个技巧:
假设你现在在第500个版本,而你想要编辑第497个版本。
hg export -o rev497 497
hg export -o rev498 498
hg export -o rev499 499
hg export -o rev500 500

编辑rev497文件并更改消息。(在以"#"为前缀的第一行之后)

hg import rev497
hg import rev498
hg import rev499
hg import rev500

1

我是这样做的。首先,不要推送你的更改,否则就没戏了。下载并安装collapse扩展。提交另一个虚拟更改集。然后使用collapse将前两个更改集合并为一个。它会提示你输入新的提交消息,并以你已有的消息作为起点。你已经成功地修改了原始的提交消息。


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