Mercurial将更改移动到新分支

125

我有一些修改已经提交到了我的本地代码库,但是还没有推送到远程仓库。由于某个功能的开发时间比预期要长,我想在推送之前将这些修改切换到一个命名分支上。我该如何操作呢?


2
可能是重复的问题:如何在Mercurial中将某些变更集移动到新分支 - Peter O.
4个回答

155

正如Mark所建议的那样,MqExtension是解决您问题的一种方法。在我看来,使用rebase扩展可以更简单。假设您有以下历史记录:

@  changeset:   2:81b92083cb1d
|  tag:         tip
|  summary:     my new feature: edit file a
|
o  changeset:   1:8bdc4508ac7b
|  summary:     my new feature: add file b
|
o  changeset:   0:d554afd54164
   summary:     initial

这意味着,版本0是您开始开发功能的基础。现在您想在一个命名分支上拥有版本1-2,比如说my-feature。更新到版本0并创建该分支:

$ hg up 0
$ hg branch my-feature
$ hg ci -m "start new branch my-feature"

现在的历史记录如下:

@  changeset:   3:b5939750b911
|  branch:      my-feature
|  tag:         tip
|  parent:      0:d554afd54164
|  summary:     start new branch my-feature
|
| o  changeset:   2:81b92083cb1d
| |  summary:     my new feature: edit file a
| |
| o  changeset:   1:8bdc4508ac7b
|/   summary:     my new feature: add file b
|
o  changeset:   0:d554afd54164
   summary:     initial

使用rebase命令将修订版本1-2移动到修订版本3上:

$ hg rebase -s 1 -d 3

这将导致以下图表:

@  changeset:   3:88a90f9bbde7
|  branch:      my-feature
|  tag:         tip
|  summary:     my new feature: edit file a
|
o  changeset:   2:38f5adf2cf4b
|  branch:      my-feature
|  summary:     my new feature: add file b
|
o  changeset:   1:b5939750b911
|  branch:      my-feature
|  summary:     start new branch my-feature
|
o  changeset:   0:d554afd54164
   summary:     initial

就这样了...如Mark的回答中所提到的评论,移动已经推送的变更集通常是一个坏主意,除非你在一个小团队中工作,在那里你能够交流并执行你的历史操作。


4
我认为这种解决方案的缺点在于它引入了一个“开始新分支my-feature”的虚拟提交(即不更改任何文件的提交)。 - sschuberth
9
我认为在这里明确表达是一件好事。如果额外的变更集对你来说是一个问题,可以将其与后续变更集合并(例如,通过使用现在内置的histedit扩展中的fold命令)。 - Oben Sonne
6
@AmirRachum说:“hg log -G”(GraphlogExtension)。我手动去掉了一些行,但也可以使用自定义日志样式完全自动地呈现。 - Oben Sonne
2
启用 rebase 扩展:http://mercurial.selenic.com/wiki/RebaseExtension#Configuration - 56ka
1
@sschuberth 我同意。我的解决方法是使用 --keepbranches 标志将非虚拟提交重新基于虚拟提交的父提交,然后再用 hg strip 命令删除虚拟提交。这样做虽然需要花费较多时间,但有时Mercurial确实是那么愚蠢。 - weberc2
显示剩余2条评论

30

你可以使用MqExtension。假设要移动的变更集为版本1-3:

hg qimport -r 1:3    # convert revisions to patches
hg qpop -a           # remove all them from history
hg branch new        # start a new branch
hg qpush -a          # push them all back into history
hg qfin -a           # finalize the patches

我想导入63:64和66:68。但是出现了“修订版65不是64的父级”的错误提示。 - Casebash
你想对65做什么?Mq只能从一个head转换连续的changesets,它会将通常不可变的changesets转换为可编辑的可变补丁。这样会改变哈希值(影响所有子元素),所以你不能跳过操作。 - Mark Tolonen
1
请勿编辑已推送的更改集。Mq 更改哈希值,因此它们将成为实际上的新更改集。只编辑尚未推送的历史记录。 - Mark Tolonen
如果您已经推送了65,则绝对不应该移动63和64,而只需移动66:68(仅当您尚未推送它们时)。 - Matt
我还会添加 hg qq -c rebranch 以避免干扰可能在队列中的其他补丁。 - anatoly techtonik
显示剩余5条评论

9
我更喜欢Mark Tolonen在这里描述的补丁解决方案。
我所拥有的:
hg log -G

#default branch
@  changeset:   3:cb292fcdbde1
|
o  changeset:   2:e746dceba503
|
o  changeset:   1:2d50c7ab6b8f
|
o  changeset:   0:c22be856358b

我想要什么:

  @  changeset:   3:0e85ae268e35
  |  branch:      feature/my_feature
  |
  o  changeset:   2:1450cb9ec349
  |  branch:      feature/my_feature
  |
  o  changeset:   1:7b9836f25f28
  |  branch:      feature/my_feature
  |
 /
|
o  changeset:   0:c22be856358b

Mercurial 命令:

hg export -o feature.diff 1 2 3
hg update 0
hg branch feature/my_feature
hg import feature.diff

这是我本地存储库的状态。
@  changeset:   6:0e85ae268e35
|  branch:      feature/my_feature
|
o  changeset:   5:1450cb9ec349
|  branch:      feature/my_feature
|
o  changeset:   4:7b9836f25f28
|  branch:      feature/my_feature
|
| o  changeset:   3:cb292fcdbde1
| |
| o  changeset:   2:e746dceba503
| |
| o  changeset:   1:2d50c7ab6b8f
|/
|
o  changeset:   0:c22be856358b

现在我需要从我的默认分支中删除修订版本1、2和3。您可以使用mq扩展的strip命令来执行此操作。hg strip会从存储库中删除变更集及其所有后代。
通过将以下行添加到您的配置文件(.hgrc或Mercurial.ini)中,启用该扩展:

vim ~/.hgrc并添加:

[extensions]
mq =

现在将此代码库还原到版本1。

hg strip 1

这里我们来了

@  changeset:   3:0e85ae268e35
|  branch:      feature/my_feature
|
o  changeset:   2:1450cb9ec349
|  branch:      feature/my_feature
|
o  changeset:   1:7b9836f25f28
|  branch:      feature/my_feature
|
o  changeset:   0:c22be856358b

注:变更集不同,但修订版本相同。

5

对于那些倾向于使用GUI的人

  1. 进入 Tortoise Hg -> 文件 -> 设置,然后勾选 rebase

enter image description here

  1. 重新启动Tortoise UI。

  2. 创建新分支,在当前分支名称上单击 -> 选择 打开新命名的分支 -> 选择分支名称。

enter image description here

  1. 如果您想要移动的更改尚未被公开(例如草稿),请执行第5步。(如果更改已经被发布并且您不是高级开发人员,则应与某个高级人员交谈(找个替罪羊),因为您可能会犯大错,我不承担任何责任 :))。

进入 查看 -> 显示控制台(或 Ctrl + L)然后在控制台中输入 hg phase -f -d 2 - 其中2是您将要移动到新分支的最低修订版本。

  1. 进入分支和修订版本(如果您正在将更改移动到第3步创建的新分支,则应该是最高修订版本)。 右键单击 -> 更新

  2. 进入您将从中移动更改的分支和修订版本 右键单击 -> 修改历史记录 -> Rebase

enter image description here

  1. 点击 Rebase,祈祷没有冲突,必要时进行合并。

  2. 推送更改,此时所有修订版本仍应为 draft

  3. 进入您将更改移动到的分支中的最高修订版本 右键单击 -> 更改阶段为 -> 公共

希望这能为您节省一些时间。

在此输入图片描述


干得好!我要试一下,只有一个问题 - 为什么最后要将阶段更改为公共的?“在远程存储库中看到的任何变更集都是公共的”,所以当你推送时,它不会自动设置为公共吗? - Joshua Duxbury
@JoshLeeDucks 当我进行推送时,它们不会自动更改为“public”(至少对我来说不会)。 - Matas Vaitkevicius

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