Git - 当两个遥控器具有相同的标签名称时,检出远程标签

时间:2014-03-01 00:28:31

标签: git git-remote git-tag

我曾希望这会奏效:

git checkout remote/tag_name

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

git checkout tags/tag_name

但是我做了一些奇怪的事情,我有很多遥控器,而且我担心如果两个遥控器有相同的标签会发生什么。有没有办法在签出标签时指定遥控器?

4 个答案:

答案 0 :(得分:81)

1 - 使用以下命令从遥控器获取标签:

git fetch origin --tags 

或者,从不同的远程用户签出标签:

git fetch your_remote --tags

2通过运行

签出标签
git checkout tags/<tag_name>

更多信息:Download a specific tag with Git

答案 1 :(得分:75)

执行摘要:您希望实现的目标是什么,但首先您必须发明远程标签。

您可以使用一系列refspec执行此操作,每个遥控器一个。剩下的就是这些是什么,它们是如何工作的等等。


您的问题询问了如何查看&#34;远程标记&#34;,但Git没有拥有远程标记,并且:

  

但是我做了一些奇怪的事情,我有很多遥控器,而且我担心如果两个遥控器有相同的标签会发生什么。有没有办法在签出标签时指定遥控器?

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

让我们回顾一下,然后谈谈Git在一般意义上的含义,这些是&#34;引用&#34;。为了巩固这一想法,参考文献的特定表单包括您的本地分支名称(masterdevelfeature等等),&#34;远程分支名称&#34;例如origin/masterstuff_from_bobs_computer/master以及代码名称。像Git&#34; stash&#34;也使用引用,甚至HEAD也是一个参考,虽然它是一个非常特殊的参考,通常是一个象征性的&#34;参考。这里的要点是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远程分支。如果你有很多遥控器,你在refs/remotes/内有很多子目录。

我刚才提到你的标签都在refs/tags/。那遥控器&#39;标签,所有各种遥控器上的所有标签?好吧,git还没有&#34;远程标签&#34;。 Git确实有#34;远程分支&#34;,但实际上这些都是本地的。它们存储在您的存储库中,位于refs/remotes/标题下。

当您的Git通过git fetch remote联系&#34;远程&#34;时,push(以及最初的clone步骤),< em>你的 Git问远程Git 3 这个问题:&#34;你有哪些本地分支机构?他们的SHA-1值是多少?&#34;事实上,这就是fetch的工作原理:作为一个简化的描述,提取的过程包括询问远程Git&#34;嘿,whaddaya得到了什么?&#34;它为您提供了一组名称和SHA-1。然后你的Git会检查它是否有相同的SHA-1。如果是这样,谈话就完成了;如果不是,那么你的Git会说&#34;好吧,我需要提交这些SHA-1&#34;中的任何内容,实际上它们是另一堆SHA-1,而你的Git和他们谈论它以确定哪些文件和你需要的,所有这些都由SHA-1识别。你的Git会带来这些对象,并将新的SHA-1填入您的refs/remotes/,在遥控器的名称下,然后在它们的本地分支名称下。

如果你要求使用fetch标签,那么你的Git会做得更多。 4 你的Git也不会向他们的Git询问他们的分支,而是向他们询问他们的标签是好。同样,他们的Git只给你一个名字和SHA-1的列表。然后你的Git会带来所需的任何底层对象,然后 - 这就是整个问题的关键 - 它将他们的标签名称写入你的refs/tags/

那么,当您转到远程origin并向其询问标记时会发生什么,并且它说'#34;我有refs/tags/pinkyrefs/tags/brain&#34;,是这会为您创建本地标记pinkybrain,在您的引用名称空间中也称为refs/tags/pinkyrefs/tags/brain

现在你转到Bob的计算机(上面名为stuff_from_bobs_computer的遥控器)并询问它是否有标签。他是神经病学家,而不是华纳兄弟和姐妹,他的标签是refs/tags/spinal_cordrefs/tags/brain,第二个可能与origin上的标签无关。哦,哦!

这里发生的事情有点复杂, 5 但简而言之,这只是一个糟糕的情况,你应该尽可能避免它。有两种简单(好......)的方法可以避免它。一个有明显缺点的是:只是没有得到他们的标签。然后你就没有任何标签冲突。另一个是:保持所有标签彼此分开(也可能与你的标签分开)。事实证明,第二个并不是那么困难。你只需要发明&#34;远程标签。

让我们快速看看Git如何实现&#34;远程分支&#34;以及fetch --tags如何工作。它们都使用相同的基本机制,git称之为&#34; refspecs&#34;。

在最简单的形式中,refspec看起来就像两个带有冒号的引用名称:refs/heads/master:refs/heads/master。事实上,你甚至可以省略refs/heads/而Git会把它放进去, 6 有时你也可以省略冒号和重复的名字。这是git push使用的内容:git push origin branch表示使用origin推送到refs/heads/branch,并在到达时将其称为refs/heads/branch &#34;它们的&#34; Git也是。

对于fetch,做远程分支,你会得到一个如下所示的refspec:

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

前面的+表示&#34;强制&#34;,*做了明显的事情。你的Git与他们谈话并获得一份参考列表。匹配refs/heads/*的那些,你的庄稼带来了(以及他们的存储库对象) - 但随后它会在名为盯着refs/remotes/origin/的名称下将它们粘贴在你的回购中,现在你拥有所有&#34;远程分支&#34;来自origin 7

当您运行git fetch --tags时,您的git会将+refs/tags/*:refs/tags/*添加到它使用的refspec。 8 这会将其标记结束并将它们放入您的本地标记中。所以你要做的就是给fetch一个看起来像这样的refspec:

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

突然之间你会有一个全新的名称空间&#34;远程标签&#34;在refs/rtags/下(仅适用于origin)。在这里使用+ force-flag是安全的,因为您只是更新了他们的标签副本:如果他们强行移动(或删除并重新创建)标签,强行移动你的副本。您可能还需要甚至需要--no-tags行为,您可以通过在命令行上指定--no-tags来获取该行为,或者,请参阅下一段。

要知道的唯一剩下的便利项目是git fetch从Git配置文件获取任何给定远程的默认refspec。 9 如果你检查你的Git配置文件,你和& #39;将使用fetch =字符串在每个遥控器下看到+refs/heads/*:refs/remotes/remote-name/*行。每个遥控器你可以拥有尽可能多的fetch =行,所以你可以添加一个来覆盖他们的标签,但是把它们放在新的(重新)发明的#34;远程标签中。命名空间。您可能还希望通过在同一部分中设置--no-tags,使tagOpt = --no-tags成为此遥控器的默认设置。有关详细信息,请参阅this comment by user200783

与将名称解析为原始SHA-1的所有Git命令一样,您可以通过完全引用名称git checkout进入&#34;分离的HEAD&#34;相应SHA-1上的模式:

git checkout refs/rtag/stuff_from_bobs_computer/spinal_cord

因为Git不知道&#34;远程标签&#34;内置,你必须拼出长格式(详见gitrevisions)。


1 事实上,它是.git/refs中的真实目录。然而,还有一个&#34;包装&#34; refs的形式,在.git/packed-refs结束。打包表单旨在通过不经常更改的引用(或者根本不像标记那样)来节省时间和精力。还在不断努力重写&#34;后端&#34;存储系统的参考,所以在某些时候,这可能会改变很多。 Windows和Mac系统需要进行此更改。 Git认为分支和标签名称区分大小写:您可以为您的擦鞋材料分支polish,为您的香肠分配Polish。打包的版本 区分大小写,因此这有效;但是存储文件版本有时不是,所以它没有!

2 我在这里对轻量级和带注释标签之间的差异进行了掩饰。带注释的标签是存储库中的实际对象,而轻量级标签是refs/tags/空间中的标签。但是,一般来说,每个带注释的标签都有一个相应的轻量级标签,因此对于这种特殊用法,它们的效果相同。

3 它几乎总是另一个Git repo,虽然现在有适用于Git的Merigial,svn等适配器。他们有自己的技巧假装成Git回购。此外,这种描述并不是确定性的:实际的操作顺序是为了传递效率而不是为了对人类有意义而编码。

4 我已经对这里的普通fetchclone的一些特殊的怪异,即没有--tags的版本进行了掩饰。带有 --tags版本很容易解释:它们使用我在此处描述的refspec来引入所有标签 - 至少在Git 2.10和2.11中{{1}也会强制更新,就像设置了--tags强制标志一样。但除非您明确要求+,否则普通提取(和克隆)会带来一些标记。它做的偷偷摸摸的事情是寻找与由于获取而进入的对象相对应的标签,并将它们(不强制更新)添加到您的(全局)标签名称空间。如果没有--no-tags,您的Git就不会覆盖您自己的现有代码;使用--tags,您的Git 覆盖您自己现有的标签,至少在Git 2.10中,根据2017年初的实际实验进行。

5 旧版本的Git应用&#34;分支&#34; push 期间的标记规则(但不一定是获取),如果是快进标记,则允许标记更新,否则需要强制标记。较新版本的--tags只需要force-tag。来自git push fetch refspec没有设置强制标志,但就像它一样。我还没有尝试使用--tags进行推送。关于--tags vs git fetch与明确的refspec相比,还有一个特殊的--tags奇怪的问题,与--no-tags的工作方式有关。文档说--prune适用于任何显式命令行--prune refspecs,但不适用于隐式refs/tags/ refspec。我也没有尝试验证这一点。

6 为了让你的Git为你填写--tagsrefs/heads/,你的Git必须能够弄明白你是哪一个意思。在某些情况下它确实存在,而某些情况则不存在。如果你的Git没有弄清楚,你会得到一条错误信息,并且可以再次尝试填写它 - 但是在脚本中你应该总是明确地填写它,以获得更可预测的行为。如果您只是运行refs/tags/来推送现有分支,您几乎总能让Git弄明白。

7 退出冒号和第二个名称对git push不起作用:它告诉你的Git根本不更新你自己的引用!这似乎毫无意义,但实际上可以有用,因为git fetch 总是写入特殊文件git fetch。您可以从特殊文件中提取Git对象ID(SHA-1)并查看获取的内容。在发明远程跟踪分支之前,这主要是Git早期版本的延续。

8 FETCH_HEADgit fetch --tags使用的refspec是在内部预编译的,在Git版本2.10中,并由一些特殊情况代码处理。预编译的表单没有设置git push --tags标志;然而实验表明,在Git 2.10 / 2.11中强制更新了获取的标签。我记得几年前用Git 1.x进行了实验,并发现这些+ - 获取的标签强制更新,所以我认为这已经改变,但这可能只是错误的记忆。在任何情况下,如果您(重新)发明远程标签,您很可能想要使用明确的--tags

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

答案 2 :(得分:9)

在我的情况下,当新标记添加到远程存储库[我使用Stash]时,新标记在git tag -l的结果中不可用。
但是我能够使用git ls-remote --tags查看新添加的标签 我必须运行以下命令才能将所有最新的标签发送到我的本地存储库:
git pull --tags 现在,运行git tag -l也会显示新添加的标签。

要结帐标签,请使用:
git checkout <tag_name>

注意:运行git status并查找如下消息是正常的:
HEAD detached at tag_name

答案 3 :(得分:0)

我心中有一些问题:

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

事情如下:

当您使用git checkout tags/fancytag签出代码时,它会在您当前的存储库(在您的计算机上)中查找拟合标记。

如果要从特定遥控器签出标签,首先必须fetch它(特定遥控器的树),然后检查它。