来自Loeliger 2ed的Git版本控制,
如果您未在 git push 命令中完全指定refspec,该怎么办?怎么样 Git知道该做什么或在哪里发送数据吗?
首先,如果没有给命令显式的远程命令,Git会假设 你想使用原产地。
如果没有refspec , git push 会将您的提交发送到远程您之间常见的所有分支 存储库和上游存储库。任何本地分支都不是 已存在于上游存储库中的数据不会向上游发送; 分支必须已存在且匹配名称。
是“全部 您的存储库和上游存储库之间通用的分支“与本地存储库中的所有远程跟踪分支以及远程存储库中相应的跟踪分支相同?
引用是git push
。
是否(特别是没有refspec的情况下的部分)适用于git fetch
和git pull
?
答案 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:remote
和pushremote
是相同的配置名称[这让我想知道分支名称部分是否也不区分大小写;我必须在某个时候测试它。)
关于refspecs的下一部分更加错误,因为git随着时间的推移已经获得了一些变化,其中一些甚至在git的内置文档中都没有很好地记录。你的引用如下:
如果没有refspec,git push会将您的提交发送到您的存储库和上游存储库之间通用的所有分支的远程。
当命令行未指定要使用
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 push
,nothing
,current
,simple
和{{ 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/heads
和ls-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 push
和git 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
提交到pull
和pull
,然后两者随着时间的推移不同方向发展;一次&#34;遥控器&#34;和&#34;远程跟踪分支&#34;它们已经存在,它们已经发展到了这样一种程度,即我认为试图混合它们只是一个坏主意,现在情况更糟。 : - )