如何在 Mercurial 中挑选单个版本?
在 Mercurial/TortoiseHg 中,给出以下示例,将修订版“G”合并到存储库 A 中而不采用 D、E 和 F 的最简单方法是什么(假设 G 不依赖于 D、E 或 F)。
Repo A: A - B - C
Repo B (Clone of A) A - B - C - D - E - F - G
补丁是最好的选择吗?
In Mercurial/TortoiseHg, given the following example, what is the easiest way to merge revision "G" into repo A without taking D,E and F (Assume that G has no dependency on D,E or F).
Repo A: A - B - C
Repo B (Clone of A) A - B - C - D - E - F - G
Is a patch the best bet?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
通法是对的。您所描述的不是“合并”(或“推”或“拉”);而是“合并”(或“推”或“拉”)。这是“采摘樱桃”。推或拉将所有变更集从一个存储库移动到另一个存储库中尚未存在的变更集。 “合并”需要两个“头”,并将它们合并为一个新的变更集,该变更集是两者的组合。
如果您确实需要将 G 移过去,但又无法忍受那里有 D、E、F,您应该从存储库 A 中“hg 导出”G,然后在存储库 A 中“hg 导入”它。 移植扩展 是导出/导入的包装器,具有一些细节,有助于避免多次移动相同的变更集。
但是,使用导入/导出、移植和樱桃采摘的缺点是,如果没有其祖先,您就无法真正移动 G,因为在 Mercurial 中,变更集的名称 是它的“hashid”,其中包括其父代的 hashid。不同的父级(G 的新父级将是 C 而不是 F)意味着不同的 hashid,因此它不再是 G —— 它是 G 的工作,但名称上是一个新的变更集。
将 G 作为新的东西,让我们称之为 G'(Gee prime),对于某些用途来说并不是什么大问题,但对于其他用途来说它是一个大皮塔饼。当仓库 B 很快得到一个新的变更集 H 时,您想要将其移动到其父变更集上,该变更集将从 G 更改为 G',它们具有不同的哈希值。这意味着 H 将作为 H' 移动——接下来有 100 个变更集,所有内容都会有不同的 hashid,因为你无法忍受仓库 A 中存在 D、E、F。
事情会变得更加不正常。如果/当您想将内容从存储库 A 移动到存储库 B(与之前移动的方向相反)。如果您尝试从 A 到 B 进行简单的“hg Push”,您将得到 G'(和 H' 以及后续后代),这将是您在 Repo B 中已有的变更集的重复项。
那么,您的选择是什么?
hg update C
。如果 G 不依赖或不需要变更集 D、E 和 F,那么它不应该是他们的孩子。相反,如果您首先更新到 C,您将得到一个像这样的图表:
那么,这个问题的整个答案就是 hg push -r G ../repoA ,并且 G 会干净地移动,保持相同的 hashid,D、E 和 F 不会同意。
更新:
正如评论中所指出的。对于现代 Mercurials,
hgraft
命令是实现此目的的完美方法。Tonfa is right. What you're describing isn't 'merging' (or 'pushing' or 'pulling'); it's 'cherry-picking'. A push or a pull moves all the changesets from one repo to another that aren't already in that repo. A 'merge' takes two 'heads' and merges them down to a new changeset that's the combination of both.
If you really need to move G over but can't possibly abide having D,E,F there you should 'hg export' G from repo A, and then 'hg import' it in repo A. The Transplant extension is a wrapper around export/import with some niceties to help avoid moving the same changeset over multiple times.
However, the drawback to using import/export, transplant, and cherry-picking in general is that you can't really move over G without its ancestors, because in Mercurial a changeset's name is its 'hashid' which includes the hashids of its parents. Different parents (G's new parent would be C and not F) means a different hashid, so it's not G anymore -- it's the work of G but a new changeset by name.
Moving over G as something new, let's call it G' (Gee prime), isn't a big deal for some uses, but for others it's a big pita. When soon repo B get's a new changeset, H, and you want to move it over its parent will be changing from G to G', which have different hashes. That means H will move over as H' -- 100 changesets down the line and you'll have different hashids for everything all because you couldn't stand having D,E,F in repo A.
Things will get even more out of whack if/when you want to move stuff from Repo A into Repo B (the opposite direction of your earlier move). If you try to do a simple 'hg push' from A to B you'll get G' (and H' and by subsequent descendants) which will be duplicates of the changesets you already have in Repo B.
What then, are your options?
hg update C
. If G doesn't rely on or require changesets D,E, and F then it shouldn't be their kid.If instead you update to C first you'll have a graph like this:
then, the whole answer to this question would just be
hg push -r G ../repoA
and G would move over cleanly, keeping its same hashid, and D, E, and F wouldn't go with it.UPDATE:
As pointed out in the comments. With modern Mercurials the
hg graft
command is the perfect way to do this.参考标题,它解决了一般的樱桃采摘问题,我给出了在一个存储库中工作的例子,因为互联网搜索引擎可能会将人们带到这里进行一般的樱桃采摘。在一个存储库中工作,可以使用
hgraft
来完成:结果是:
额外警告:两个变更集将被视为对同一文件的独立、并行提交,并可能使您遇到合并冲突,这就是为什么在分支管理中通常应避免挑选。例如,如果
G
是应用于标记为1.0.1
的稳定版本分支的错误修复,您应该合并freeze
分支与其一起,并且时不时地将master
分支与freeze
分支的错误修复合并。Refering to the title, which addresses cherry picking in general, I give the example of working in one repo, as internet search engines might bring people here for cherry picking in general. Working in one repository, it would be done with
hg graft
:The result is:
Extra warning: The two changesets will be treated as independent, parallel commits on the same files and might make you run into merge conflicts, which is why cherry picking should be avoided in general for branch management. For example, if
G
is a bug fix applied to a stable version branch bookmarked as1.0.1
, you should rather merge thefreeze
branch with it, and from time to time merge themaster
branch with thefreeze
branch's bugfixes.这是另一种方法:
这会为要修补的变更集创建一个差异,然后将其保存到 临时文件 并导入它。文件名是可选的。
如果您不使用
zsh
(而是创建一个命名管道),<(...)
似乎也可以工作。或者您可以手动将补丁保存到文件中:Here's another approach:
This creates a diff for the changeset you want to patch in, then saves it to a temporary file and imports it. The filename(s) are optional.
<(...)
also seems to work if you're not usingzsh
(creates a named pipe instead). Or you can manually save the patch to a file: