首页 > 解决方案 > Git:使用cherry-pick将标签从一个分支复制到另一个分支

问题描述

我有一个包含多个提交和标签的 MASTER 分支。我只想将标签从 MASTER 复制到 RELEASE 分支(而不是其他提交)。

我首先创建了一个空的 MASTER 分支,并仅使用消息提交它。然后我创建了一个空的 RELEASE 分支。我向 MASTER 添加了几个提交,内容如下:

在 MASTER 中,我用 C2 创建了一个标签 T1(其中包含 file1 和 file2) 现在,我想将标签 T1 复制到 RELEASE 分支。看来我需要使用cherry-pick来做到这一点。

我首先注意到 MASTER 中标签 T1 的 SHA-ID。然后我做:

成功,但 RELEASE 分支现在只显示 file2。它不应该显示标签 T1 的内容,即 file1 和 file2 吗?

同样,我的目标只是在 RELEASE 中显示来自 MASTER 的标签(而不是其他提交)。这可能吗?提前致谢。

标签: gittagscherry-pick

解决方案


让我们从这个开始:

...我的目标只是在 RELEASE 中显示来自 MASTER 的标签(而不是其他提交)

这个目标在 Git 中毫无意义。在 Git 中,所有引用名称都存在于提交集之外。此外,名称之间没有容器/包含关系(一个约束继承自 Git 当前实现这些名称的方式)。也就是说,名称AB是完全相互独立的。名称feature/Xfeature/Y也完全相互独立。进行任何更改(包括创建新名称或删除旧名称)都不会影响任何其他名称。

(这里的例外是一旦你有了名字feature/Xor feature/Y,你就不能再使用这个名字feature了。那个名字现在被feature/其他两个名字的一部分“占用”了。你可以继续使用feature/来容纳更多的名字,并且您可以featur在没有 final 的情况下使用e,但您不能创建名称feature来标识对象,因为feature/存在feature/X和/或feature/Y。)

标签名称不包含在分支中。分支名称不包含在标签中。它们都是独立的实体,彼此并存。由你来组织它们。一种明智的方法是使用这些斜杠:对于您和/或其他人正在开发其名称(或代号)为. 表单的分支名称可能是组织提交将进入特定版本的好短名称,其名称(或代码名称)为. 当针对某个版本的某个特定提交已由 QA 验证并正在交付时,表单的标签名称可能是该版本的一个很好的短名称。feature/namenamerelbranch/namenamereleases/name

(请注意,git for-each-ref通常用于处理引用的内部 Git 命令对斜杠分隔的名称组件特别满意:例如,git for-each-ref refs/tags/releases遍历 中的所有标签refs/tags/releases/*。)

有关标签和分支名称的更多信息

标签只是提交的指针。也就是说,每个提交对象都有自己的“真名”,这是一个大而丑陋的哈希 ID,如5d826e972970a784bd7a7bdf587512510097b8c7. 此名称对于这一提交是唯一的(它是 Git 存储库中的一个提交,因此除非您有 Git 的 Git 存储库,否则您将不会拥有这一提交)。Git 用来访问对象的这些真名对人类来说既笨拙又无用,因此 Git 为我们提供了名称。您可以将标签名称命名为v2.20.0,它的主要功能——或者有时是两个这样的功能之一——是它取代了记忆的需要5d826e972970a784bd7a7bdf587512510097b8c7

分支名称也是如此,但有几个重要区别:

  • 预计分支名称会随着时间而改变。也就是说,在您提交 C1(无论其实际哈希 ID 是什么)之后,该名称master就是提交 C1 的名称。但是随后提交 C2 的行为在 onmaster时将名称更改master为现在的名称提交 C2。当您创建 C3 时,Gitmaster再次更改,以便它现在识别提交 C3。

  • 标记名称应保持不变。也就是说,如果您创建一个名为 commit C2的标签T ,那么任何地方的每个Git——嗯,你曾经直接或间接连接到 Git 存储库的每个 Git 存储库——都可以假设,从现在开始,T表示“提交 C2” . 如果您在存储库中删除标记T并创建一个名为 commit C3 的新T,则所有其他Git 存储库如果继续将名称T转换为 C2,则它们是正确的。(如果他们更改为 C3 也是正确的,但他们不需要更改。)

  • 允许标签名称通过标签对象间接指向提交。Git 将这种标签称为带注释的标签。标签对象可以存储一些额外的信息,例如一个 PGP 签名密钥,表明我,签名者,已经检查了这个特定的提交是有效的并且应该被使用。 在 Git 的 Git 存储库中就是这种情况v2.20.0,例如:

    $ git cat-file -p v2.20.0
    object 5d826e972970a784bd7a7bdf587512510097b8c7
    type commit
    tag v2.20.0
    tagger Junio C Hamano <gitster@pobox.com> 1544329907 +0900
    
    Git 2.20
    -----BEGIN PGP SIGNATURE-----
    
    iQIzBAABCAAdFiEE4fA2sf7nIh/HeOzvsLXohpav5ssFAlwMmrMACgkQsLXohpav
    5sv6pg//VIRzIkTz+DQ4ITzWXpH41lGjhsbSN554a/Kj5W1RvHiQmzpv5HDM65vr
    Dr9DqYiP3HBOPElUTxT5iS2qgsajrRZ1yvKMEnb+YxLbix0NhkvdhJxHmsTUYmEH
    SOve1ddx9spKHEdRjgw6eyoTiG5yQgcea7XkdATeTYeJzZIfMcrXVR920ZjUi9dK
    DRambd/KGYFIPftN0EdVCVPUDrNlKvmK3RhS7arZUxFBxSGDVzGiStK0r2aSw0lb
    gT27Ygy+cz0StWL2q4kV4ghPhjpAv9QqypNNADRg9ZxDhY446V2flU67oV0PLCm/
    E4GmgkjGOphQOujWJv6Uz+6F4E1DvGx9Wt78Xbl3kXZruyhwIv/7yk53nUPxtaI5
    PjBqy+2vJPmZoUONH3/zSYlGW4ZwURatXTDe3FOK15Eq3EV+IpbRGhpuu4Ju9U3c
    L1dpTFdauiKJFuSNkrsdrJPhpX2nbgYl3PloxHWAhPzoqFGib4reRqrm12lczpRp
    BytNhs8RWwR+4CZXAFYtITFEdBLhHvWodklYnGfTFlMKs/OZ4S+XNS2LOb6Wjc3S
    EFF4U87QGnHm6vCREpKwVOMroAEOUXsrbHc3tzxrX16GlXHNWYI/fgAkD6twffE8
    GEIclUQ7v/fRFlmznDJKGOoWVDTUzwLCVeb36lmpd6w+CpRm7cc=
    =1E0P
    -----END PGP SIGNATURE-----
    

    (注解标签的对应物是轻量级标签,它直接指向一个提交。默认情况下,git describe忽略轻量级标签,只使用注解标签为一些原始提交哈希提供更人性化的名称。)

因为分支名称会移动,所以它们应该用于您希望人们选择并使用旧名称的新值的任何情况。因为标签名称不会移动,所以它们应该用于您希望人们永远使用一个特定提交的任何情况。因为带注释的标签可以提供对数字签名的访问,所以它们也适用于这些情况。

关于樱桃采摘

请注意,git cherry-pick 确实复制提交。为此,它首先提交转换为变更集。(这个解释有点手动,忽略了cherry-pick是通过合并机制实现的事实,但足以考虑这些问题。)请记住,提交保存了每个文件的快照,形式为当您(或任何人)做出该承诺时。

按原样复制提交并不好。例如,假设您想要对也将进入新版本的旧版本进行相同的更改(修复)。获取新版本的固定提交(快照)并将其直接复制到旧版本分支中,将使旧版本的下一个版本与新版本的固定提交 100% 相同,而不仅仅是导入一个修复。所以cherry-pick根本不会复制快照

要将提交(快照)转换为变更集,Git 必须将提交与其直接前任进行比较。例如,C3 的前身是 C2,因此通过比较 C2 中的快照和 C3 中的快照,Git 可以告诉您C2 到 C3 的变化。

那么,要进行挑选,首先要检查一些现有的提交(当然,C2 或 C3 除外)。通常这将是 via ,使用正在开发此特定版本的分支的名称。然后你告诉 Git:首先,弄清楚C3 相对于 C2发生了什么变化。然后对我当前的 not-C2 not-C3 提交进行相同的更改,并使用结果进行新的提交。git checkout name

进行了一个新的提交——它得到一个新的大丑哈希 ID,不同于其他所有提交的大丑哈希 ID——Git 像往常一样将新提交的哈希 ID 写入当前分支名称。现在,无论您现在使用的哪个分支名称master(可能不是,但这取决于您)都指的是这个新快照。您可以创建一个标签来指向这个新的提交,但是因为人们(和软件)希望标签不会改变,所以删除任何现有标签并用一个相同名称的新标签替换它通常是不明智的,指向不同的犯罪。


推荐阅读