来自 Loeliger 2ed 的 Git 版本控制,
What if you don’t specify a refspec at all on a git push command? How does Git know what to do or where to send data?
First, without an explicit remote given to the command, Git assumes you want to use origin.
Without a refspec, git push will send your commits to the remote for all branches that are common between your repository and the upstream repository. Any local branch that is not already present in the upstream repository will not be sent upstream; branches must already exist and match names.
您的存储库和上游存储库之间共有的分支”与本地存储库中的所有远程跟踪分支和远程存储库中相应的跟踪分支相同吗?
git push
.它(尤其是没有refspec 的情况下的部分)是否适用于
git fetch
并到 git pull
? 最佳答案
(恐怕这个答案又一次相当长了,因为这些问题做出的假设 - 至少在今天 - 是不正确的。跳到粗体部分以获得实际答案,但在此之前的所有内容也很重要。)
您引用的书籍文本已过时,并且(现在)完全错误(这是不断发展的软件的危险,书籍已过时):
First, without an explicit remote given to the command, Git assumes you want to use origin.
在相对快速地浏览 git 自己的 git 历史记录时,我还没有准确地找到行为发生变化的时间,但是 git 1.8.2.1 和 now says 中的文档发生了变化。 :
When the command line does not specify where to push with the
<repository>
argument,branch.*.remote
configuration for the current branch is consulted to determine where to push. If the configuration is missing, it defaults to origin.
(这个行为也匹配git fetch
——不出所料,因为他们使用相同的源代码来得到那个结果。)这没有提到可选的branch.$branch.pushremote
设置,覆盖branch.$branch.remote
.在所有情况下,这里$branch
代表您当前的分支,如git symbolic-ref --short HEAD
的输出所示. (如果您处于“分离的 HEAD”模式,因此git symbolic-ref
失败,git push
通常会给您一个“致命的:您当前不在分支上”错误,我认为自 2.0 版以来默认值已更改。)
这还不是全部。 the git-config documentation增加了一个怪癖:
remote.pushDefault
The remote to push to by default. Overridesbranch.<name>.remote
for all branches, and is overridden bybranch.<name>.pushRemote
for specific branches.
(幸运的是,截至今天,我认为这涵盖了所有内容。也就是说,git 首先为当前分支查找pushremote
设置。如果没有这样的设置,它接下来会查找remote.pushdefault
。如果这也是未设置,它回退到当前分支的remote
设置。旧版本的 git 中的行为可能会有所不同。还要注意配置项不区分大小写:pushremote
和pushRemote
是相同的配置名称 [这让我想知道分支名称部分是否也不区分大小写;我将不得不在某个时候对其进行测试]。)
关于 refspecs 的下一部分更错误,因为 git 随着时间的推移获得了一些更改,其中一些甚至在 git 的内置文档中也没有很好地记录。您的报价如下:
Without a refspec, git push will send your commits to the remote for all branches that are common between your repository and the upstream repository.
new documentation说:
When the command line does not specify what to push with
<refspec>...
arguments or--all
,--mirror
,--tags
options, the command finds the default<refspec>
by consultingremote.*.push
configuration, and if it is not found, honorspush.default
configuration to decide what to push (See git-config for the meaning ofpush.default
).push.default
设置是在 git 1.8 版左右添加的,但其默认值在 git 2.0 中更改。如果您还没有配置push.default
你会收到这个警告:warning: push.default is unset; ...
自从配置项可用以来。咨询the git-config documentation ,您现在会发现:
push.default
Defines the actiongit push
should take if no refspec is explicitly given. Different values are well-suited for specific workflows ...
有五个选项,我将在此处简单列出(有关详细信息,请参阅链接文档):nothing
,current
,simple
,upstream
, 和matching
.您引用的书中文字描述matching
,这是 git 2.0 版之前的默认行为。新的默认值是simple
.
上git push
, 如果您配置“匹配”行为
Are "all branches that are common between your repository and the upstream repository" the same as all the remote-tracking branches in the local repository and the corresponding tracked branches in the remote repository?
不。
我建议您尝试运行git ls-remote origin
(或将origin
替换为任何其他 Remote 的名称):$ 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]
然后,尝试git for-each-ref refs/heads
:$ git for-each-ref refs/heads
您将看到类似的输出,但具有不同的 SHA-1 和单词commit
夹在中间。
这里的要点是refs/heads
中列出的每个“头” — 在两个输出中,来自ls-remote
来自for-each-ref
— 代表git push
的(本地)分支在进行“匹配”时考虑。匹配的头部被添加到推送列表中,给出一组 refspecs(以内部形式,但很容易表示为name:name
或者,如果您使用--force
标志,+name:name
)。
即使没有为这些本地分支配置上游,也会发生这种情况。因此,如果他们(远程)有refs/heads/bob
这是供 Bob Roberts 使用的,您有一个refs/heads/bob
您正在使用有关您的管道浮标或钓鱼浮标或其他任何信息的信息,即使您的bob
git 也会尝试匹配这些信息。并不意味着要逆流而上。
上push
对比fetch
The quote is for
git push
. Does it (especially the part for the case without a refspec) apply togit fetch
and togit pull
?
不。git fetch
的行为更容易解释,因为它不会对你做所有奇怪的事情git pull
做。git pull
命令应该很方便,但是git pull
正试图将一个基本上存储库范围的“获取”操作与一个基本上受分支约束的“merge ”操作混合在一起。这两者不能很好地结合在一起。1(我认为git pull
充其量可以在某个时候进行修改以执行更简单的、存储库范围的“获取所有内容,然后检查并 merge ,成对地,一些基于分支的on tracking configs and arguments”序列。我认为这会使其表现得像大多数人似乎期望的那样。它也主要是向后不兼容的,并且表现得像现在一样仅适用于最简单但默认的情况: 获取所有,然后只 merge 当前分支。但这无论如何都是猜测。)
如果您省略所有引用规范,git fetch
阅读您的remote.$remote.fetch
配置行。 (请注意,此“省略所有引用规范”子句意味着您还必须避免旧的“$GIT_DIR/branches
中的命名文件|”方法,例如。)
名为origin
的远程的默认配置行(单数)通常看起来像这样(查看您的本地存储库配置文件以查看它):[remote "origin"] +refs/heads/*:refs/remotes/origin/*
这是“远程跟踪分支”产生的实际机制。fetch
过程以相同的git ls-remote origin
开始step,它从远程获取每个引用的列表——分支、标签或你有什么。fetch
代码继续将这些与fetch =
中的每一个匹配起来。线下[remote "origin"]
. refspec 左侧的星号具有明显的含义;右侧的星号将替换为左侧星号匹配的任何内容。 (在当前版本的 git 中,*
必须匹配“整个部分”,松散地定义为“斜线之间的东西”,但在即将到来的 git 中,这个约束将放宽——尽管我不确定有什么用处。)
您可能有很多fetch =
随心所欲。每个原始引用都遍历每一行以获得新的(替换)引用:如果左侧匹配,则右侧提供替换。 (如果右侧缺失或为空,由于历史原因,行为会变得有点奇怪,部分是为了保持git pull
工作,部分是因为所需的行为在 git 1.8 左右发生了变化。)
所有这些替换的结果形成了重命名的引用,并决定了哪些引用被复制了;但是对于每个原始引用,最多只能有一个结果:例如,您不能将“他们的”refs/heads/foo 映射到“您的”refs/remotes/origin/bar 和您的 refs/remotes/origin/zoink。
要使存储库充当镜像,您可以使用+refs/*:refs/*
在不重命名的情况下带来所有引用(但这会破坏每个fetch
上的本地分支,因此这主要仅对--bare
有意义)。
(“修剪”——根据另一方在启动协商期间为获取或推送发送的内容删除“死”引用——是单独完成的,并且仅当您设置了--prune
标志时。)
1它不是这样开始的。其实原pull
脚本完全早于 Remote 和远程跟踪分支。提交7ef76925d9c19ef74874e1735e2436e56d0c4897
拆分pull
进入pull
和fetch
然后两者随着时间的推移朝着不同的方向发展;一旦“远程”和“远程跟踪分支”出现,它们已经发展到试图混合它们的地步,我认为,只是一个坏主意,现在更糟。 :-)
关于git - 在没有 refspec 参数的情况下运行 git push、pull 和 fetch,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34523494/