通常,git标签是对提交的固定引用。但有时它们会用于标记某些事件(last-build
,base-line
等等。)并且它们会经常更改。
我有一个脚本可以刷新参考存储库中的那些“浮动”标记。
git fetch --tags --force
并从一个分支拉出来:
git pull origin <mybranch>
我知道很多git用户警告使用浮动标签,但我不得不处理这个问题。我的问题是:
如果分支由其中一个浮动标记标记...命令的执行顺序是否重要?
我担心git pull
在本地存在标记时不会刷新标记,如果标记首先运行,它可能会与所有标记的引用一起使用。
git pull
有一个--force
选项,但选项--no-tags
的帮助解释了默认行为:
默认情况下,指向从中下载的对象的标记 远程存储库被提取并存储在本地。
这是否意味着应首先下载对象以便能够刷新标签?在这种情况下,git pull
应该先行。
哪个订单正确?
答案 0 :(得分:9)
这进入了Git中一个比较模糊的角落,但最终答案是&#34;最初你使用哪个订单&#34;并不重要。但是,我建议一般不要使用git pull
,也不要在脚本中使用它。另外,正如我们将在下面看到的那样,以不同的方式确切地 。因此,我建议您首先运行自己的git fetch
,然后根本不使用git pull
。
git fetch
普通git fetch
(没有--tags
)默认使用奇怪的混合标记更新,尽管每个远程可以定义一个覆盖此默认值的默认标记选项。奇怪的混合是你引用的:标记指向从远程存储库下载的对象被提取并存储在本地。这个的基本机制有点棘手,我会离开以后。
将--tags
添加到git fetch
参数与在命令行上refs/tags/*:refs/tags/*
指定几乎相同。 (我们稍后会看到差异。)请注意,这没有在refspec中设置强制标志,但测试表明所取出的标签都是强制更新的。
添加--force
与在每个显式refspec中设置force标志具有相同的效果。换句话说,git fetch --tags --force
大致相当于运行git fetch '+refs/tags/*:refs/tags/*'
:如果远程标记refs/tags/foo
指向提交1234567...
,则您的Git将替换任何现有的refs/tags/foo
这样你现在拥有自己的refs/tags/foo
也指向提交1234567...
。 (但正如在实践中所观察到的那样,即使仅使用--tags
也是如此。)
请注意,在所有案例中,git fetch
会将有关内容的信息写入文件FETCH_HEAD
。例如:
$ cat .git/FETCH_HEAD
e05806da9ec4aff8adfed142ab2a2b3b02e33c8c branch 'master' of git://git.kernel.org/pub/scm/git/git
a274e0a036ea886a31f8b216564ab1b4a3142f6c not-for-merge branch 'maint' of git://git.kernel.org/pub/scm/git/git
c69c2f50cfc0dcd4bcd014c7fd56e344a7c5522f not-for-merge branch 'next' of git://git.kernel.org/pub/scm/git/git
4e24a51e4d5c19f3fb16d09634811f5c26922c01 not-for-merge branch 'pu' of git://git.kernel.org/pub/scm/git/git
2135c1c06eeb728901f96ac403a8af10e6145065 not-for-merge branch 'todo' of git://git.kernel.org/pub/scm/git/git
(来自之前没有--tags
的提取运行,然后是):
$ git fetch --tags
[fetch messages]
$ cat .git/FETCH_HEAD
cat .git/FETCH_HEAD
d7dffce1cebde29a0c4b309a79e4345450bf352a branch 'master' of git://git.kernel.org/pub/scm/git/git
a274e0a036ea886a31f8b216564ab1b4a3142f6c not-for-merge branch 'maint' of git://git.kernel.org/pub/scm/git/git
8553c6e5137d7fde1cda49817bcc035d3ce35aeb not-for-merge branch 'next' of git://git.kernel.org/pub/scm/git/git
31148811db6039be66eb3d6cbd84af067e0f0e13 not-for-merge branch 'pu' of git://git.kernel.org/pub/scm/git/git
aa3afa0b4ab4f07e6b36f0712fd58229735afddc not-for-merge branch 'todo' of git://git.kernel.org/pub/scm/git/git
d5aef6e4d58cfe1549adef5b436f3ace984e8c86 not-for-merge tag 'gitgui-0.10.0' of git://git.kernel.org/pub/scm/git/git
[much more, snipped]
我们马上回过头来看看。
获取可能取决于它找到的任何其他refspec-这通常由remote.origin.fetch
配置条目控制 - 更新一些远程跟踪分支,并创建或更新某些标记。如果您被配置为获取镜像,并且更新refspec为+refs/*:refs/*
,那么您将获得所有内容。请注意,此refspec设置了强制标志,并带来所有分支,所有标记,所有远程跟踪分支和所有注释。关于什么时候使用refspec会有更多模糊的细节,但使用--tags
,有或没有--force
,不会覆盖配置条目(而写一组显式的refspecs,所以这是一种方式 - 可能是唯一的方式 - --tags
与写出refs/tags/*:refs/tags/*
)不同。
您自己的参考空间中的更新 - 您自己的远程跟踪分支和标记,通常 - 执行很重要,但......不适用于pull
,因为我们会看到在下一节中。
git pull
我想说git pull
只运行git fetch
后跟第二个Git命令,其中第二个命令默认为git merge
,除非您指示它使用git rebase
。这是真实和正确的,但在方式上有一个模糊的细节。在将git fetch
重写为C代码之前,这更容易说:当它是脚本时,您可以按照脚本的git fetch
和git merge
命令查看实际参数是
当git pull
运行git merge
或git rebase
时,不会使用远程跟踪分支和标记。相反,它使用FETCH_HEAD
中留下的记录。
如果您查看上面的示例,您会看到他们告诉我们,最初,refs/heads/master
上的存储库中的git.kernel.org
指向了提交e05806d...
。在我运行git fetch --tags
之后,新的FETCH_HEAD
文件告诉我们refs/heads/master
上的git.kernel.org
指向fetch
(当我运行d7dffce...
时,它可能有现在改变了)提交git pull
。
当git merge
运行git rebase
或git fetch
时,它会通过这些原始SHA-1号码。因此,您的参考无关紧要名称解析为。我运行的origin/master
确实更新了$ git rev-parse origin/master
d7dffce1cebde29a0c4b309a79e4345450bf352a
:
git pull
但即使没有,d7dffce1cebde29a0c4b309a79e4345450bf352a
也会将--force
传递给第二个命令。
因此,假设您在没有1234567...
的情况下获取标记并获得了对象git rev-parse refs/tags/last-build
。进一步假设,如果您使用强制获取标记,这将是--force
的结果,但是因为您不使用last-build
,你自己的存储库留下8888888...
指向last-build
(在中国是一个非常幸运的提交:-))。如果你个人说'#34;告诉我关于8888888...
&#34;您将获得修订版git pull
。但是1234567...
知道它得到1234567...
并且无论发生什么,它只会将数字FETCH_HEAD
传递给它的第二个命令,如果有什么要求的话。
再次,它从FETCH_HEAD
中获取该数字。那么这里的重要内容是-a
的(完整)内容,这取决于您是否使用--append
/ --append
获取。在这里不适用的特殊情况下(当您从多个单独的存储库中获取数据,或者在单独的步骤中进行调试以获取调试目的时,或者其他某些情况下)时,您只需要/ {需要last-build
。
如果您希望/需要更新git fetch --tags --force
代码,则必须在某个时刻运行git fetch
- 现在我们会遇到原子性问题。
假设您运行--tags
,有或没有--force
且有或没有git pull
,可能是运行git fetch
而--tags
没有1234567...
1}}。您现在已在本地提交last-build
,名称8888888...
指向1234567...
(未更新)或git fetch --tags --force
(已更新)。现在您运行last-build
来更新所有内容。 现在可能,遥控器再次移动了8888888...
。如果是这样,您将获得新值,并更新您的本地代码。
按照这个顺序,您从未见过8888888...
。您可能有一个包含该提交的分支,但不知道该标记的提交 - 现在您 更新了您的标记,您不会通过该标记知道git pull
现在 。这是好事,坏事还是无动于衷?这取决于你。
git pull
由于git fetch
仅运行git fetch
后跟第二个命令,因此您可以自己运行fetch
,然后运行第二个命令。这使您可以完全控制fetch
步骤,并且可以避免冗余提取。
由于您执行控制git ls-remote
步骤,您可以使用refspecs精确指定您想要更新的内容。现在是时候访问奇怪的混合标签更新机制了。
获取您方便的任何存储库并运行git fetch
。这将显示$ git ls-remote | head
From git://git.kernel.org/pub/scm/git/git.git
3313b78c145ba9212272b5318c111cde12bfef4a HEAD
ad36dc8b4b165bf9eb3576b42a241164e312d48c refs/heads/maint
3313b78c145ba9212272b5318c111cde12bfef4a refs/heads/master
af746e49c281f2a2946222252a1effea7c9bcf8b refs/heads/next
6391604f1412fd6fe047444931335bf92c168008 refs/heads/pu
aa3afa0b4ab4f07e6b36f0712fd58229735afddc refs/heads/todo
d5aef6e4d58cfe1549adef5b436f3ace984e8c86 refs/tags/gitgui-0.10.0
3d654be48f65545c4d3e35f5d3bbed5489820930 refs/tags/gitgui-0.10.0^{}
33682a5e98adfd8ba4ce0e21363c443bd273eb77 refs/tags/gitgui-0.10.1
729ffa50f75a025935623bfc58d0932c65f7de2f refs/tags/gitgui-0.10.1^{}
在连接时看到的内容:
gitgui-0.10.0^{}
你的Git从远程Git获取所有引用及其目标的列表。对于作为(带注释的)标记的引用,这也包括标记对象的最终目标:这里是refs/heads/*
。此语法表示去皮标记(请参阅gitrevisions
,但它不使用单词&#34;去皮&#34;此处)。
默认情况下,您的Git会将每个分支 - 所有名为--force
的内容 - 通过询问他们指向的提交,以及完成所需的任何其他提交和其他对象那些承诺。 (您不必下载已有的对象,只需要那些缺少但需要的对象。)然后,您的Git可以浏览所有剥离的标记,以查看是否有任何标记指向其中一个提交。如果是这样,您的Git接受或不接受--force
模式,具体取决于您的获取 - 给定标记。如果该标记指向标记对象,而不是直接指向提交,那么Git也会将该标记对象添加到集合中。
在1.8.2之前的Git版本中,Git错误地将分支规则应用于推送标签更新:只要结果是快进,它们就不允许--force
。也就是说,先前的标记目标仅需要是新标记目标的祖先。这显然只影响轻量级标签,无论如何,Git版本1.8.2及更高版本在没有--tags
&#34;的情况下永远不会替换标签。 推送上的行为。然而,在使用git fetch --tags --force --prune
时,Git 2.10.x和2.11.x的观察行为是标记在获取时被替换。
但无论如何,如果你的目标是以通常的方式强制更新所有标记和所有远程跟踪分支,git fetch --prune '+refs/tags/*:refs/tags/*' '+refs/heads/*:refs/remotes/origin/*'
将会这样做;或者您可以+
使用--prune
语法强制标记和远程跟踪分支更新。 (git merge
像往常一样是可选的。)强制标志可能是不必要的,但在这里至少是无害的,并且可能在某些Git版本中做一些有用的事情。现在您的标签和远程跟踪分支已更新,您可以使用git rebase
或git pull
完全没有参数,使用当前分支的上游进行合并或变基。您可以根据需要为多个分支重复此操作,从不需要运行fetch
(及其冗余{{1}})。
答案 1 :(得分:1)
关于订单:任何订单都有效(通勤)。
关于您运行的命令的说明:
git fetch --tags
已经&#34;强制更新&#34;您当地的标签--force
选项仅适用于不以+
选项开头的refspec git pull --tags origin mybranch
将一次性应用您想要的所有内容(获取所有代码,并更新您当地的分支机构)答案 2 :(得分:0)
我将回答以下问题(您没有明确要求):
每次致电
git fetch
或git pull
时,如何自动更新固定的一组代码?
我的地方情况完全相同,这就是我对它的看法。
默认情况下,遥控器的refspec是:
[remote "origin"]
url = git@server:repo # or whatever
fetch = +refs/heads/*:refs/remotes/origin/*
这就是它只从遥控器获取分支的原因 - 它只从遥控器获取refs/heads/*
个引用。
这是默认配置,但您可以添加您认为合适的任何引用。
您可以使用erefspec tell git从远程获取refs/tags/last-build
,并自动更新本地标记:
[remote "origin"]
url = git@server:repo # or whatever
fetch = +refs/heads/*:refs/remotes/origin/*
fetch = +refs/tags/last-build:refs/tags/last-build
# this line tells :
# - get the 'refs/tags/last-build' (first ref, before ':') from the remote
# - store it in my local tag (second ref after, ':')
# - allow forced updates (initial '+')
警告:此特定行会在每次提取时删除您的本地last-build
标记,并且git不会保留标记的reflog。考虑到这些标签的含义,我发现这种行为没问题。
如果您对此感到不舒服,可以指定另一个本地参考:
# you will see two tags 'last-build' and 'origin/last-build' in your repo :
fetch = +refs/tags/last-build:refs/tags/origin/last-build
显然,为每个相关标签添加一条这样的行......
参考:refspec doc