在没有refspec参数的情况下运行git push,pull和fetch

时间:2015-12-30 05:32:19

标签: git

来自Loeliger 2ed的Git版本控制,

  

如果您未在 git push 命令中完全指定refspec,该怎么办?怎么样   Git知道该做什么或在哪里发送数据吗?

     

首先,如果没有给命令显式的远程命令,Git会假设   你想使用原产地。

     

如果没有refspec git push 会将您的提交发送到远程您之间常见的所有分支   存储库和上游存储库。任何本地分支都不是   已存在于上游存储库中的数据不会向上游发送;   分支必须已存在且匹配名称。

  • 是“全部 您的存储库和上游存储库之间通用的分支“与本地存储库中的所有远程跟踪分支以及远程存储库中相应的跟踪分支相同?

  • 引用是git push。 是否(特别是没有refspec的情况下的部分)适用于git fetchgit pull

1 个答案:

答案 0 :(得分:5)

(我担心这个问题的答案会再次变长,因为这些问题的假设至少在今天是不正确的。跳转到粗体部分以获得实际答案,但之前的所有内容也很重要。)

你引用的书籍文字已经过时,而且(现在)显然是错误的(这对于不断发展的软件来说是危险的,书籍已经过时了):

  
    

首先,如果没有给出命令的显式远程,Git假定你想使用origin。

  

我没有,通过git自己的git历史记录进行相对快速的扫描,确切地发现行为发生了变化,但文档在git 1.8中发生了变化.2.1和now says

  

当命令行没有指定推送的位置时   <repository>参数,branch.*.remote配置   咨询当前分支以确定推送的位置。如果   配置缺失,默认为 origin

(此行为与git fetch匹配 - 不出所料,因为他们使用相同的源代码来获得该结果。)这未提及可选的branch.$branch.pushremote设置,该设置覆盖{{1 }}。在所有情况下, branch.$branch.remote 代表您当前的分支,如$branch的输出所示。 (如果您处于&#34;分离的HEAD&#34;模式,以致git symbolic-ref --short HEAD失败,git symbolic-ref通常会给您一个&#34;致命:您目前不在分支机构& #34;错误,我认为自版本2.0以来默认值发生了变化。)

仍然不是整个故事; the git-config documentation又增加了一个怪癖:

  

git push
   默认情况下推送到的遥控器。覆盖remote.pushDefault   对于所有分支,并被branch.<name>.remote覆盖   具体分支。

(幸运的是,截至今天,我认为涵盖了所有内容。也就是说,git首先为当前分支寻找branch.<name>.pushRemote设置。如果没有这样的设置,它接下来查找pushremote。如果还没有设置,它会回退到当前分支的remote.pushdefault设置。旧版git中的行为可能会有所不同。另请注意,配置项是大小写的-sensensitive:remotepushremote是相同的配置名称[这让我想知道分支名称部分是否也不区分大小写;我必须在某个时候测试它。)

关于refspecs的下一部分更加错误,因为git随着时间的推移已经获得了一些变化,其中一些甚至在git的内置文档中都没有很好地记录。你的引用如下:

  
    

如果没有refspec,git push会将您的提交发送到您的存储库和上游存储库之间通用的所有分支的远程。

  

new documentation说:

  

当命令行未指定要使用pushRemote推送的内容时   命令查找参数或<refspec>...--all--mirror选项   咨询--tags配置的默认<refspec>,   如果找不到,请尊重remote.*.push配置来决定   要推送的内容(有关push.default的含义,请参阅git-config。)

在git的1.8版本周围添加了push.default设置,但在git 2.0中更改了其默认的。如果您尚未配置push.default,则会收到此警告:

push.default

自配置项目可用以来。咨询the git-config documentation,您现在可以找到:

  

warning: push.default is unset; ...
   如果未明确指定refspec,则定义应采取的操作push.default。不同的值非常适合特定的工作流程......

有五个选项,我将在此处列出(有关详细信息,请参阅链接文档):git pushnothingcurrentsimple和{{ 1}}。您引用的书籍文本描述了upstream,这是git 2.0版之前的默认行为。新默认值为matching

matching上,如果您配置&#34;匹配&#34;行为

  

是&#34;您的存储库和上游存储库之间共有的所有分支&#34;与本地存储库中的所有远程跟踪分支以及远程存储库中相应的跟踪分支相同吗?

没有

我建议您尝试运行simple(或将git push替换为任何其他遥控器的名称):

git ls-remote origin

然后,尝试origin

$ git ls-remote origin
28274d02c489f4c7e68153056e9061a46f62d7a0        HEAD
1ff88560c8d22bcdb528a6629239d638f927cb96        refs/heads/maint
28274d02c489f4c7e68153056e9061a46f62d7a0        refs/heads/master
0ac5344e619fec2068de9ab2afdb99d1af8854be        refs/heads/next
5467631257c047b16d95929559dd1887d27b0ddc        refs/heads/pu
68a0f56b615b61afdbd86be01a3ca63dca70edc0        refs/heads/todo
d5aef6e4d58cfe1549adef5b436f3ace984e8c86        refs/tags/gitgui-0.10.0
3d654be48f65545c4d3e35f5d3bbed5489820930        refs/tags/gitgui-0.10.0^{}
[snip -- lots more omitted]

您会看到类似的输出,但是使用不同的SHA-1,并且中间夹着单词git for-each-ref refs/heads

这里的要点是每个&#34; head&#34; $ git for-each-ref refs/heads 中列出的commit中列出的refs/headsls-remote - 表示for-each-ref在执行&#34;匹配&#34;时所考虑的(本地)分支。匹配的头部将添加到推送列表中,提供一组refspecs(内部形式,但很容易表示为 git push ,或者,如果您使用name:name标志,{ {1}})。

即使没有为这些本地分支配置上游,也会发生。因此,如果他们(遥控器)有一个--force意味着Bob Roberts可以使用,并且您有一个+name:name,您可以使用refs/heads/bob来获取有关您的管道摆锤的信息或钓鱼浮子或其他任何东西,即使你的refs/heads/bob不打算上游,git也会尝试匹配它们。

bob vs push

  

报价是fetch。是否(特别是没有refspec的情况下的部分)适用于git pushgit fetch

没有

git pull的行为更容易解释,因为它并没有完成git fetch所做的所有奇怪的事情。 git pull命令应该很方便,但是git pull正在尝试在一个基本的存储库范围内混合&#34; fetch&#34;操作与基本上分支约束&#34;合并&#34;操作。这两个不能很好地协同工作。 1 (最好的情况是,我认为git pull在某些时候可能会被修改为更简单,存储库范围内的&#34;获取全部,然后检查out和merge,pairwise,一些分支基于跟踪配置和参数&#34;顺序。我认为这会使它的行为与大多数人看起来的方式一样。它也会大多向后兼容,并且表现得很好它现在的方式只适用于最简单但默认情况:获取全部,然后仅合并当前分支。但无论如何,这都是猜测。)

如果省略所有refspec,git pull会读取git fetch个配置行。(请注意,此&#34;省略所有refspecs&#34;子句意味着您还必须例如,避免在remote.$remote.fetch&#34;方法中使用旧的&#34;命名文件。)

名为$GIT_DIR/branches的远程的默认配置行(单数)通常如下所示(查看本地存储库配置文件以查看它):

origin

这是&#34;远程跟踪分支机构的实际机制。成立。

[remote "origin"] +refs/heads/*:refs/remotes/origin/* 进程以相同的fetch步骤开始,该步骤获取每个引用分支,标记或来自远程的内容的列表。 git ls-remote origin代码继续与fetch下的fetch =行匹配。 refspec左侧的星号具有明显的含义;右侧的星号将替换为左侧星号匹配的任何内容。 (在当前版本的git中,[remote "origin"]必须匹配&#34;整个部分&#34;,松散地定义为&#34;斜杠和#34;之间的东西,但是在即将到来的git中,这个约束将被放宽 - 虽然我不确定有什么用处。)

您可以拥有尽可能多的*行。每个原始引用都通过每一行来获得一个新的(替换)引用:如果左侧匹配,则右侧提供替换。 (如果右侧缺失或为空,由于历史原因,行为有点奇怪,部分原因是为了保持fetch =正常工作,部分原因是因为所需的行为在git 1.8左右发生了变化。)

所有这些替换的结果形成重命名的引用,并确定复制哪些引用;但每个原始参考文件必须至多有一个结果:您无法映射&#34;他们的&#34; refs / heads / foo to&#34;你的&#34;例如,refs / remotes / origin / bar 你的refs / remotes / origin / zoink。

要使存储库充当镜像,您可以使用git pull来覆盖所有没有重命名的引用(但这会破坏每个+refs/*:refs/*上的本地分支,所以这通常只对fetch)。

(&#34;修剪&#34; -removing&#34;死亡&#34;基于另一方在启动谈判期间为获取或推送发送的内容的引用 - 单独完成并且仅在您设置{时{1}}标志。)

1 它没有这样开始。实际上,原始--bare脚本完全取决于遥控器和远程跟踪分支。将7ef76925d9c19ef74874e1735e2436e56d0c4897分成--prune提交到pullpull,然后两者随着时间的推移不同方向发展;一次&#34;遥控器&#34;和&#34;远程跟踪分支&#34;它们已经存在,它们已经发展到了这样一种程度,即我认为试图混合它们只是一个坏主意,现在情况更糟。 : - )