当前位置:  开发笔记 > 开发工具 > 正文

是"git fetch --tags --force"和"git pull <branch>"交换操作吗?

如何解决《是"gitfetch--tags--force"和"gitpull<branch>"交换操作吗?》经验,为你挑选了1个好方法。

通常,git标签是对提交的固定引用.但有时它们被用来纪念某些事件(last-build,base-line,等),他们经常改变.

我有一个脚本,从参考存储库刷新那种"浮动"标签.

git fetch --tags --force

并从一个分支拉出:

git pull origin 

我知道很多git用户警告使用浮动标签,但我不得不处理这个问题.我的问题是:

如果分支由其中一个浮动标记标记...命令的执行顺序是否重要?

我担心git pull当它们存在于本地时不会刷新标记,并且如果它首先运行,它可能与所有标记的引用一起工作.

git pull有一个--force选项,但该选项的帮助--no-tags解释了默认行为:

默认情况下,指向从远程存储库下载的对象的标记将被提取并存储在本地.

这是否意味着应首先下载对象以便能够刷新标签?在那种情况下git pull应该先行.

哪个订单正确?



1> torek..:

这进入了Git较为模糊的角落之一,但最终答案是"最初使用哪个订单并不重要".但是,我建议git pull一般避免使用它,并且永远不要在脚本中使用它.此外,这非常重要,以不同的方式,正是你取,因为我们将在下面看到.所以我建议先运行自己的git fetch,然后根本不使用git pull.

git fetch

普通git fetch(不--tags)默认使用奇怪的混合标记更新,尽管每个远程可以定义一个覆盖此默认值的默认标记选项.奇怪的混合是您所引用的:指向从远程存储库下载的对象的标记被提取并存储在本地. 这个潜在的机制有点棘手,我会留待以后.

添加--tagsgit 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

(从之前的fetch运行开始--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设置了强制标志,并带来所有分支,所有标记,所有远程跟踪分支和所有注释.关于refspecs使用什么的更多模糊细节,但是使用--tags,有或没有--force,不会覆盖配置条目(而写一组明确的refspecs,所以这是一种方式 - 可能是唯一的方式 - --tags不同于写出refs/tags/*:refs/tags/*).

您自己的参考空间中的更新 - 您自己的远程跟踪分支和标签,通常重要的,但是......不是pull,正如我们将在下一节中看到的那样.

git pull

我想说git pull只是运行git fetch后跟第二个Git命令,其中第二个命令默认为默认,git merge除非你指示它使用git rebase.这是真实和正确的,但在方式上有一个模糊的细节.在git fetch重写为C代码之前,这更容易说:当它是一个脚本时,您可以按照脚本git fetchgit merge命令查看实际参数是什么.

git pull运行git merge或者git rebase,它不使用您的远程跟踪分支和标签.相反,它使用留下的记录FETCH_HEAD.

如果你检查上面的例子,你会看到他们告诉我们最初,refs/heads/mastergit.kernel.org指向提交的存储库中e05806d....在我运行之后git fetch --tags,新FETCH_HEAD文件告诉我们refs/heads/mastergit.kernel.org指向的存储库中(当我运行时fetch,它可能已经改变了)提交d7dffce....

git pull运行git mergegit rebase,它通过穿过这些原始SHA-1的数字. 因此,引用名称解析的内容并不重要.在git fetch我跑事实上更新做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"你会得到修改8888888....但是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--tags1234567...last-build8888888...1234567...git fetch --tags --forcelast-build

按照这个顺序,你可能从未见过8888888....您可能有一个包含该提交的分支,但不知道该标记的提交 - 现在您正在更新您的标记,您现在也不会知道8888888...该标记.这是好事,坏事还是无动于衷?随你(由你决定.

避免 git pull

由于git pull仅运行git fetch后跟第二个命令,您可以git fetch自己运行,然后运行第二个命令.这使您可以完全控制fetch步骤,并允许您避免冗余提取.

由于您确实控制了该fetch步骤,因此您可以使用refspecs精确指定您想要更新的内容.现在是时候访问奇怪的混合标签更新机制了.

获取您方便并运行的任何存储库git ls-remote.这将显示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^{}

你的Git从远程Git获取所有引用及其目标的列表.对于带有(注释)标记的引用,这也包括标记对象的最终目标:就是gitgui-0.10.0^{}这里.此语法表示去皮标签(请参阅gitrevisions,但此处不使用"去皮"一词).

默认情况下,你的Git会带来每个分支 - 所有命名的东西refs/heads/*- 通过询问它们指向的提交,以及完成这些提交所需的任何其他提交和其他对象.(您不必下载已有的对象,只需要那些缺少但需要的对象.)然后,您的Git可以浏览所有剥离的标记,以查看是否有任何标记指向其中一个提交.如果是这样,您的Git接受或不接受--force模式,具体取决于您的获取 - 给定标记.如果该标记指向标记对象,而不是直接指向提交,则Git也会将该标记对象添加到集合中.

在1.8.2之前的Git版本中,Git错误地应用了分支规则来推送标签更新:--force只要结果是快进,它们就被允许.也就是说,先前的标记目标仅需要是新标记目标的祖先.这只会影响轻量级的标签,显然,在任何情况下的Git版本1.8.2及以上有"永远不更换标签--force的行为" .然而,Git 2.10.x和2.11.x的观察行为是标签在使用时被取代--tags.

但无论如何,如果您的目标是以通常的方式强制更新所有标签所有远程跟踪分支,那么git fetch --tags --force --prune就会这样做; 或者您可以git fetch --prune '+refs/tags/*:refs/tags/*' '+refs/heads/*:refs/remotes/origin/*'使用+语法强制标记和远程跟踪分支更新.(这--prune是通常可选的.)force标志可能是不必要的,但在这里至少是无害的,并且可能在某些Git版本中做一些有用的事情.现在您的标签和远程跟踪分支已更新,您可以使用git mergegit rebase根本不使用任何参数,使用当前分支的上游配置进行合并或变基.您可以根据需要为多个分支重复此操作,从不需要运行git pull(具有冗余fetch).

推荐阅读
mobiledu2402852357
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有