Git-当两个遥控器具有相同标签名时签出一个远程标签

我曾希望这能起作用:

git checkout remote/tag_name

但事实并非如此。 这样做:

git checkout tags/tag_name

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

Narfanator asked 2020-06-20T18:19:02Z
4个解决方案
82 votes

1-使用以下方法从远程获取标签:

git fetch origin --tags 

或者,要从其他远程使用中签出标签:

git fetch your_remote --tags

2通过运行签出标签

git checkout tags/<tag_name>

更多内容:使用Git下载特定标签

Russell Fair answered 2020-06-20T18:22:37Z
76 votes

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

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


您的问题询问有关签出“远程标签”的问题,但是Git没有远程标签,因此:

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

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

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

实际上,大多数参考(例如refs/tags/refs/remotes/refs/remotes/stuff_from_bobs_computer/以及其他类似的东西)的名称实际上都是以stuff_from_bobs_computer开头的名称拼写的。这些名称以类似于目录或文件夹的结构1的形式保存,带有子目录 -directories:refs/remotes/包含您的标签,2 refs/heads/包含您的所有分支,而refs/remotes/包含所有远程分支。

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

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

当您的Git接触“远程”时(通常是通过远程,但对于git ls-remote(以及该步骤的初始--single-branch),您的Git也会询问远程Git3问题:“您拥有哪些本地分支?它们的SHA-1值是多少?” 实际上,这就是--single-branch的工作方式:作为简化的描述,获取过程包括向远程Git询问“嘿,whaddaya得到了吗?” 它为您提供了一组名称和SHA-1。 然后,您的Git会检查它是否具有相同的SHA-1。 如果是这样,对话就完成了; 如果不是,您的Git会说“好,我需要这些SHA-1的提交内容”,实际上是另一堆SHA-1,而您的Git和他们的工作人员将其找出来 SHA-1标识哪些文件以及您所需的文件。 您的Git带来了这些对象,并将新的SHA-1填充到您的--tags中,并以远程名称命名,然后以其本地分支名称命名。

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

因此,当您转到远程fetch = +*:*并要求其提供标签时会发生什么,并说“我有git ls-remote--single-branch”,这将为您创建本地标签--single-branch--tags,在您的参考中也分别命名为--no-tags和293164143599052424934 名称空间。

现在,您转到Bob的计算机(上面的远程名为fetch = +*:*),并询问其标签。 他是神经病学专家,而不是Warner Brothers和Sister,他的标签是git ls-remote--single-branch,第二个标签可能与--single-branch上的标签不相关。

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

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

最简单的refspec看起来就像两个引用名称,它们之间带有冒号:例如fetch = +*:*。 实际上,您甚至可以省去git ls-remote,而Git会替您省去6,有时您也可以省去冒号和重复的名称。 这是您在--single-branch中使用的一种东西:--single-branch的意思是使用您的--no-tags推送到--tags,并在到达其“ Git”时也将其称为--prune

但是,对于fetch = +*:*,在执行远程分支时,您将获得如下所示的refspec:

+refs/heads/*:refs/remotes/origin/*

前面的fetch = +*:*表示“力”,而git ls-remotes做明显的事情。 您的Git与他们的交谈,并获取参考列表。 那些与--single-branch匹配的文件(随需要随其库对象一起移入)—但随后将它们以--single-branch开头的名称粘贴到您的存储库中,现在您拥有--tags.7中的所有“远程分支”

当您运行fetch = +*:*时,您的git会将git ls-remote添加到它使用的refspecs中。8将其标签放到本地标签中。 因此,您要做的就是给--single-branch一个refspec,看起来像:

+refs/tags/*:refs/rtags/origin/*

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

唯一需要了解的方便事项是fetch = +*:*从Git配置文件中获取任何给定遥控器的默认refspecs。9如果检查您的Git配置文件,您将在每个遥控器下看到一条git ls-remote,使用远程名称/ *串。 每个遥控器可以有任意多的--single-branch行,因此您可以添加一行以移走它们的标签,但是可以将它们放在新近(重新)发明的“远程标签”名称空间中。 您可能还想通过在同一部分中设置--no-tags来将--tags设置为该遥控器的默认值。 有关详细信息,请参阅user200783的注释。

与所有将名称解析为原始SHA-1的Git命令一样,然后您可以通过完整的ref-name来fetch = +*:*进入相应SHA-1上的“分离式HEAD”模式:

git checkout refs/rtag/stuff_from_bobs_computer/spinal_cord

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


1实际上,它是一个真实目录,位于fetch = +*:*。但是,还有一个“打包”的引用形式,出现在git ls-remote中。打包形式旨在节省时间和精力,而引用却不会经常更改(或在 所有,与代码一样)。 还在不断努力重写“后端”存储系统以供参考,因此在某些时候,很多情况可能会改变。 Windows和Mac系统需要此更改。 Git认为分支名称和标签名称区分大小写:您可以在擦皮擦鞋材料上使用分支--single-branch,在香肠上使用--single-branch。 压缩版本区分大小写,因此可以使用; 但是文件存储版本有时不是,所以不是!

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

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

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

5较旧的Git版本在推送(但不一定要提取)期间将“分支”规则应用于标签,如果标签是快进的,则允许更新标签,否则需要使用force标志。 较新版本的fetch = +*:*仅需要强制标记。 来自git ls-remote的访存refspec没有设置强制标志,但表现得与之相同。 我尚未尝试使用--single-branch进行push。关于--tags--no-tags与显式refspec相比,还有另一种特殊的--single-branch怪异之处,与--prune的工作方式有关。 该文档说--prune适用于任何显式命令行refs/tags/ refspec,但不适用于隐式--tags refspec。 我也没有尝试验证这一点。

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

7对于fetch = +*:*,省略冒号和第二个名称不能很好地起作用:它告诉您的Git根本不更新自己的引用! 这似乎毫无意义,但实际上是有用的,因为git ls-remote始终会写特殊文件--single-branch。您可以从特殊文件中获取Git对象ID(SHA-1),然后查看获取的内容。 这主要是对Git早期版本的保留,这是在发明了远程跟踪分支之前。

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

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

torek answered 2020-06-20T18:22:04Z
9 votes

以我为例,当一个新标签添加到远程存储库中时(我正在使用Stash),新标签在HEAD detached at tag_name中不可用。
但是我能够使用git ls-remote --tags查看新添加的标签。
我必须运行以下命令才能将所有最新标签添加到本地存储库:
git pull --tags现在,运行git tag -l还会显示新添加的标签。

为了签出标签,请使用:
HEAD detached at tag_name

注意:运行git status并找到类似以下的消息是正常的:
HEAD detached at tag_name

hipsandy answered 2020-06-20T18:23:28Z
0 votes

我心中有一些问题:

  • 为什么不同的遥控器(在同一棵树中)具有不同的代码?
  • 为什么远程代码会影响您签出标签?

事情是这样的:

当您使用fetch签出标签时,它将在您当前的存储库(在您的计算机上)中寻找合适的标签。

如果要从特定遥控器签出标签,则必须先对其进行fetch(特定遥控器的树)签出,然后再签出。

Langusten Gustel answered 2020-06-20T18:24:10Z
translate from https://stackoverflow.com:/questions/22108391/git-checkout-a-remote-tag-when-two-remotes-have-the-same-tag-name