如何在 Mercurial 中挑选单个版本?

发布于 2024-08-10 02:09:01 字数 208 浏览 10 评论 0原文

在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

诗化ㄋ丶相逢 2024-08-17 02:09:01

通法是对的。您所描述的不是“合并”(或“推”或“拉”);而是“合并”(或“推”或“拉”)。这是“采摘樱桃”。推或拉将所有变更集从一个存储库移动到另一个存储库中尚未存在的变更集。 “合并”需要两个“头”,并将它们合并为一个新的变更集,该变更集是两者的组合。

如果您确实需要将 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 中已有的变更集的重复项。

那么,您的选择是什么?

  1. 不在乎。您的数据仍然在那里,您只是最终得到具有不同名称的相同变更集,并且在两个存储库之间的未来交换中需要做更多工作。这没有错,只是可能有点笨拙,而且有些人不在乎。
  2. 将所有 D、E 和 F 移至存储库 A。如果所有变更集无害,您可以将其移至存储库 A 并避免所有麻烦。如果它们不是那么无害,您可以将它们移过去,然后执行“hg backout”以消除新变更集 H 中 D、E 和 F 的影响。
  3. 首先为 G 提供更好的出身。 对我来说,提及这一点很卑鄙,因为走这条路已经太晚了(没有编辑历史记录)。在处理变更集 G 之前,您应该做的是hg update C。如果 G 不依赖或不需要变更集 D、E 和 F,那么它不应该是他们的孩子。

相反,如果您首先更新到 C,您将得到一个像这样的图表:

A - B - C - D - E - F
          \
            G

那么,这个问题的整个答案就是 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?

  1. Don't care. Your data is still there you just end up with the same changesets with different names and more work on future exchanges between the two repos. It's not wrong, it's just a little clumsy maybe, and some folks don't care.
  2. Move all of D,E, and F over to Repo A. You can move all the changesets over if they're harmless and avoid all the hassle. If they're not so harmless you can move them over and then do a 'hg backout' to undo the effects of D,E and F in a new changeset H.
  3. Give G better parentage to begin with. It's mean for me to mention this because it's too late to go this route (without editing history). What you should have done before working on changeset G was to 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:

A - B - C - D - E - F
          \
            G

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.

安稳善良 2024-08-17 02:09:01

参考标题,它解决了一般的樱桃采摘问题,我给出了在一个存储库中工作的例子,因为互联网搜索引擎可能会将人们带到这里进行一般的樱桃采摘。在一个存储库中工作,可以使用 hgraft 来完成

hg update C
hg graft G

结果是:

            G'
          / 
A - B - C - D - E - F - G

额外警告:两个变更集将被视为对同一文件的独立、并行提交,并可能使您遇到合并冲突,这就是为什么在分支管理中通常应避免挑选。例如,如果 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:

hg update C
hg graft G

The result is:

            G'
          / 
A - B - C - D - E - F - G

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 as 1.0.1, you should rather merge the freeze branch with it, and from time to time merge the master branch with the freeze branch's bugfixes.

倥絔 2024-08-17 02:09:01

这是另一种方法:

hg import =(hg diff -c 7b44cc577701f956f12b029ad54d32fdce0a002d services/webpack/package.json)

这会为要修补的变更集创建一个差异,然后将其保存到 临时文件 并导入它。文件名是可选的。

如果您不使用 zsh (而是创建一个命名管道),<(...) 似乎也可以工作。或者您可以手动将补丁保存到文件中:

hg diff -c xxx > mypatchfile

Here's another approach:

hg import =(hg diff -c 7b44cc577701f956f12b029ad54d32fdce0a002d services/webpack/package.json)

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 using zsh (creates a named pipe instead). Or you can manually save the patch to a file:

hg diff -c xxx > mypatchfile
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文