gpt4 book ai didi

git - Git-当两个 Remote 具有相同标签名称时 checkout 一个远程标签

转载 作者:行者123 更新时间:2023-12-02 00:24:14 27 4
gpt4 key购买 nike

我曾希望这能起作用:

git checkout remote/tag_name

但事实并非如此。这样做:
git checkout tags/tag_name

但是在有很多 Remote 的地方我做的事情很奇怪,我担心如果两个 Remote 使用相同的标签会发生什么。 checkout 标签时是否可以指定 Remote ?

最佳答案

内容提要:可能要实现的目标是可能的,但首先必须发明远程标记。

您可以通过一系列refspec来做到这一点,每个refspec一个。剩下的就是这些,它们是如何工作的,等等。

您的问题询问有关 checkout “远程标签”的问题,但是Git没有远程标签,这是:

but I'm doing something weird where I have a lot of remotes, and I'm worried about what happens if two remotes have the same tag. Is there a way to specify the remote when checking out the tag?



揭示(我认为)您困惑的根源。

让我们备份一会儿,仅讨论Git的一般含义,即“引用”。为了帮助巩固这个想法,特定形式的引用包括您的本地分支名称( masterdevelfeature等),“远程分支名称”(例如 origin/masterstuff_from_bobs_computer/master)以及标签名称。像Git的“隐藏”之类的东西也使用引用,甚至 HEAD也是引用,尽管它是一个非常特殊的引用,通常是“符号”引用。这里的要点是,Git有很多形式的引用,并且它们最终实际上都以相同的方式工作:引用名称最终将解析为那些SHA-1大值之一, 676699a0e0cdfd97521f3524c763222f1c30a094或其他。

实际上,大多数引用(例如 HEADORIG_HEADMERGE_HEAD以及其他类似内容)都是以 refs/开头的名称拼写的。它们保存在某种类似于目录或文件夹的结构中,1带有子目录: refs/tags/包含您的标签,2 refs/heads/包含您的所有分支, refs/remotes/包含您的所有远程分支。

远程分支进一步由远程名称细分: refs/remotes/origin/包含所有 origin远程分支,而 refs/remotes/stuff_from_bobs_computer/包含所有 stuff_from_bobs_computer远程分支。如果您有很多 Remote ,则 refs/remotes/中有很多子目录。

我刚才提到您的标签全都在 refs/tags/中。 Remote 的标签,所有各种 Remote 上的所有标签呢?好吧,再次,git没有“远程标签”。 Git确实有“远程分支”,但实际上所有分支都是本地的。它们存储在 refs/remotes/标题下的存储库中。

当您的Git与“远程”联系时(通常是通过 git fetch remote,也包括 push(以及初始 clone步骤),您的Git会询问远程Git3问题:“您拥有哪些本地分支?它们的SHA是什么-1值?”实际上,这就是 fetch的工作原理:作为简化的描述,获取过程包括向远程Git询问“嘿,whaddaya得到了吗?”。它为您提供了一组名称和SHA-1。然后,您的Git会检查它是否具有相同的SHA-1。如果是这样,对话就完成了;如果不是,您的Git会说“好吧,我需要这些SHA-1进行提交”,实际上是另一堆SHA-1,您的Git和他们的Git讨论了一下SHA-1可以识别哪些文件以及您所需的文件。您的Git带来了这些对象,并将新的SHA-1填充到 refs/remotes/中,以远程名称命名,然后以其本地分支名称命名。

如果您使用 fetch询问标签,您的Git还会执行更多操作。4您的Git不仅会询问他们的Git有关其分支的信息,还会询问他们的有关其标签的问题。同样,他们的Git只是为您提供了名称和SHA-1列表。然后,您的Git带来了所需的任何基础对象,然后-这是解决整个问题的关键- 将其标记名称写入refs/tags/中。

因此,当您转到远程 origin并询问其标签时会发生什么,并说“我有 refs/tags/pinkyrefs/tags/brain”,这会为您创建本地标签 pinkybrain,在您的引用中也称为 refs/tags/pinkyrefs/tags/brain namespace 。

现在,您转到Bob的计算机(上面的远程名为 stuff_from_bobs_computer),并询问其标签。他是神经病学专家,而不是Warner Brothers和Sister,他的标签是 refs/tags/spinal_cordrefs/tags/brain,第二个标签可能与 origin上的标签无关。哦哦!

确切的说,这里发生的事情有点复杂5,但是简而言之,这只是一个糟糕的情况,如果可能,您应该避免这种情况。有两种简单的方法可以避免这种情况。一种明显的缺点是:只是不获取其标签。这样您就不会有任何标签冲突。另一个是:将所有标签彼此分开(也可能与您的标签分开)。事实证明,第二个并不是真的那么困难。您只需要“发明”远程标签。

让我们快速看一下Git实际如何实现“远程分支”以及 fetch --tags的工作方式。它们都使用相同的基本机制,即git称为“refspecs”。

最简单的形式是refspec就像两个引用名称,它们之间带有冒号: refs/heads/master:refs/heads/master。实际上,您甚至可以省去 refs/heads/,Git会为您省去 git push,6,有时您也可以省去冒号和重复的名称。这是您与 git push origin branch一起使用的一种方式: origin表示使用 refs/heads/branch推送到 refs/heads/branch,并在到达“其” Git时也将其称为 fetch

但是对于 +,执行远程分支时,您会得到一个如下所示的refspec:
+refs/heads/*:refs/remotes/origin/*

前面的 *表示“力”,而 refs/heads/*则做明显的事情。您的Git与他们的交谈,并获取引用列表。那些与 refs/remotes/origin/匹配的文件将带入(以及需要时与它们的存储库对象一起)—但是随后,它们将它们以 origin开头的名称粘贴在您的存储库中,现在您拥有了 git fetch --tags .7的所有“远程分支”。

当您运行 +refs/tags/*:refs/tags/*时,您的git会将 fetch添加到其使用的refspecs中。8将其标签移到本地并放到本地标签中。因此,您要做的就是给 refs/rtags/一个refspec,看起来像:
+refs/tags/*:refs/rtags/origin/*

突然之间,您在 origin下将拥有一个全新的“远程标签”命名空间(在这种情况下,仅适用于 +)。在这里使用 --no-tags强制标志是安全的,因为您只是在更新其标签的副本:如果它们已强制移动(或删除并重新创建)了标签,则可以强制移动副本。您可能还希望甚至需要 --no-tags行为,可以通过在命令行上指定 git fetch来获得,或者,请参见下一段。

剩下唯一需要了解的方便事项是,对于任何给定的 Remote , fetch =从Git配置文件中获取其默认的refspecs。9如果您检查了Git配置文件,则将使用 +refs/heads/*:refs/remotes/remote-name/*字符串在每个 Remote 下看到 fetch =行。 。每个 Remote 可以具有任意数量的 --no-tags行,因此您可以添加一行以移走它们的标签,但可以将它们放在新创建的“(远程)标签”命名空间中。您可能还想通过在同一部分中设置 tagOpt = --no-tags来将 git checkout设置为该 Remote 的默认设置。有关详细信息,请参见 this comment by user200783

与所有将名称解析为原始SHA-1的Git命令一样,然后可以使用完整的引用名称 .git/refs进入相应的SHA-1上的“分离式HEAD”模式:
git checkout refs/rtag/stuff_from_bobs_computer/spinal_cord

由于Git没有内置“远程标签”的概念,因此您必须拼写长格式(有关详细信息,请参见 gitrevisions)。

1实际上,它是一个真实目录,位于 .git/packed-refs中。但是,还有一种“打包”形式的引用,以 polish结尾。压缩形式旨在节省不经常更改的引用的时间和精力(或根本不更改,这在标记中很常见)。还需要不断努力来重写“后端”存储系统以供引用,因此在某些时候,许多情况可能会改变。 Windows和Mac系统需要此更改。 Git认为分支名称和标签名称区分大小写:您可以为擦皮擦鞋 Material 使用 Polish分支,对香肠使用 refs/tags/。压缩版本区分大小写,因此可以使用;但是文件存储版本有时不是,所以不是!

2我在这里介绍轻量级标签和带注释的标签之间的区别。带注释的标签是存储库中的实际对象,而轻量级标签是 fetch空间中的标签。但是,通常,每个带注释的标签都有一个对应的轻量级标签,因此对于这种特殊用法,它们的工作原理相同。

3尽管现在有用于Git到Mercurial,svn等的适配器,它几乎总是另一个Git仓库。他们有自己的技巧来伪装成Git仓库。同样,该描述也不是确定的:实际的操作顺序是为了提高传输效率而编码的,而不是针对人类的。

4我在这里掩盖了一些关于普通 clone--tags的特殊怪异之处,即没有 --tags的版本。带有 --tags的版本很容易解释:它们使用我在这里描述的refspecs来带走所有标签-至少在Git 2.10和2.11中, +还会强制更新,就像设置了 --no-tags强制标志一样。但是,除非您明确要求 --tags,否则简单的获取(和克隆)将带来一些标签。它所做的偷偷摸摸的事情是寻找与由于获取而进入的对象相对应的标签,并将这些标签(不强制更新)添加到您的(全局)标签 namespace 中。没有 --tags,您的Git不会覆盖您自己的现有标签。使用 git push,根据2017年初进行的实际实验,您的Git至少会覆盖Git 2.10中自己的现有标签。

5较旧的Git版本在推送(但不一定要提取)期间将“分支”规则应用于标签,如果标签是快进的,则允许更新标签,否则需要使用force标志。较新版本的 --tags仅需要强制标签。从 --tags提取refspec并没有设置force标记,但是却像设置了一样。我还没有尝试使用 git fetch进行push。关于 --tags--no-tags与显式refspecs还有另一种特殊的 --prune怪异之处,与 --prune的工作方式有关。该文档说 refs/tags/适用于任何显式命令行 --tags refspec,但不适用于隐式 refs/heads/ refspec。我也没有尝试验证这一点。

6要让您的Git为您填写 refs/tags/git push,您的Git必须能够弄清楚您的意思是哪一个。在某些情况下会这样做,在某些情况下则不会。如果您的Git无法弄清楚,您将收到一条错误消息,并且可以在填写时再次尝试-但是在脚本中,您应该始终明确地填写它,以获得更可预测的行为。如果您只是运行 git fetch来推送现有分支,则几乎总是可以让Git找出来。

7撇开冒号和第二个名字对 git fetch来说效果不佳:它告诉您的Git根本不更新自己的引用!这似乎毫无意义,但实际上可能有用,因为 FETCH_HEAD总是写特殊文件 git fetch --tags。您可以从特殊文件中取出Git对象ID(SHA-1),然后查看获取的内容。这主要是对Git早期版本的保留,这是在发明了远程跟踪分支之前。

8 git push --tags+使用的refspec是在Git 2.10版中内部预先编译的,并由某些特殊情况的代码处理。预编译的表单没有设置 --tags标志;但是实验表明,在Git 2.10 / 2.11中强制更新了获取的标签。我记得几年前使用Git 1.x进行试验,发现这些 --tags提取的标签未强制更新,因此我认为情况已经改变,但这可能只是错误的内存。无论如何,如果您(正在)发明远程标签,则您很可能不想使用显式的 fetch = +*:*

9实际上,这就是镜像的工作方式。例如,使用 git ls-remote,您将获得一个纯粹的获取镜像。提取过程可以查看所有引用。您可以使用 --single-branch自己查看它们。这也是 --single-branch的工作方式:如果在克隆过程中使用ojit_code,则Git配置文件将仅在访存行中列出一个分支。要将单分支转换为全分支,只需编辑该行以包含常规的glob-pattern条目即可。

关于git - Git-当两个 Remote 具有相同标签名称时 checkout 一个远程标签,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22108391/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com