在不使用refspec参数的情况下运行git push,pull和fetch [英] Run git push, pull and fetch without refspec argument
问题描述
从Loeliger 2ed的《使用Git进行版本控制》中,
From Version Control with Git by Loeliger 2ed,
如果您完全没有在 git push 命令上指定refspec怎么办?如何 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?
首先,在没有为命令提供明确的远程控制的情况下,Git假定 您想使用原点.
First, without an explicit remote given to the command, Git assumes you want to use origin.
没有参考说明, git push 会将您的提交发送到远程的所有分支之间的分支 存储库和上游存储库.任何非本地分支机构 上游存储库中已经存在的将不会向上游发送; 分支必须已经存在并且与名称匹配.
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.
-
都是全部 您的存储库和上游存储库之间共有的分支是否与本地存储库中的所有远程跟踪分支以及远程存储库中的相应跟踪分支相同?
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 push
. 它是否适用于(git fetch
)和git pull
(尤其是没有refspec的情况下的部分)?The quote is for
git push
. Does it (especially the part for the case without a refspec) apply togit fetch
and togit pull
?推荐答案
(恐怕这个答案又会很长,因为这些问题至少在今天是不正确的.实际答案,但在此之前的所有内容也很重要.)
(I'm afraid this answer is once again rather long, because the questions make assumptions that are—at least today—incorrect. Jump to the boldface section for the actual answers, but everything that comes before that also matters.)
您引用的书文本已经过时,并且现在(现在)完全是错误的(这对软件的发展是一种危害,书已经过时了):
The book text you quote is outdated and (now) just plain wrong (this is a hazard with evolving software, the books get outdated):
首先,在没有为命令提供明确的远程控制的情况下,Git假定您要使用origin.
First, without an explicit remote given to the command, Git assumes you want to use origin.
在git自己的git历史上相对快速的扫描中,我还没有准确地发现行为的更改时间,但是git 1.8.2.1中的 documentation 更改了,并且现在说:
I have not, in a relatively quick scan through git's own git history, found precisely when the behavior changed, but the documentation changed in git 1.8.2.1, and now says:
当命令行未指定使用
<repository>
自变量,branch.*.remote
配置 咨询当前分支以确定将推送到何处.如果 配置丢失,默认为原始.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版以来,默认值已更改.)(This behavior matches
git fetch
as well—unsurprisingly, since they use the same bit of source code to get that result.) This fails to mention the optionalbranch.$branch.pushremote
setting, which overridesbranch.$branch.remote
. In all cases here$branch
represents your current branch, as shown by the output ofgit symbolic-ref --short HEAD
. (If you're in "detached HEAD" mode, so thatgit symbolic-ref
fails,git push
normally gives you a "fatal: You are not currently on a branch" error, I think since version 2.0 when the defaults changed.)这还不是全部,而是全部. git-config文档又添加了一个怪癖:
This is still not the whole story; the git-config documentation adds yet one more quirk:
remote.pushDefault
默认情况下要推送到的遥控器.覆盖branch.<name>.remote
对于所有分支,并被branch.<name>.pushRemote
覆盖 特定分支.remote.pushDefault
The remote to push to by default. Overridesbranch.<name>.remote
for all branches, and is overridden bybranch.<name>.pushRemote
for specific branches.(幸运的是,到目前为止,我 think 涵盖了所有内容.也就是说,git首先为当前分支寻找
pushremote
设置.如果没有这样的设置,则接下来查找remote.pushdefault
.如果还没有设置,它将退回到当前分支的remote
设置.git的旧版本中的行为可能会有所不同.注意配置项不区分大小写:pushremote
和pushRemote
是相同的配置名称[这使我想知道分支名称部分是否也不区分大小写;我必须在某个时候进行测试].(Fortunately, as of today, I think that covers everything. That is, git starts by looking for a
pushremote
setting for the current branch. If there is no such setting, it next looks forremote.pushdefault
. If that is also not set, it falls back on theremote
setting for the current branch. The behavior in older versions of git may vary. Note also that configuration items are case-insensitive:pushremote
andpushRemote
are the same configuration name [this makes me wonder if the branch name parts are case-insensitive as well; I'll have to test that out sometime].)关于refspecs的下一部分甚至更加错误,因为git随时间获得了一些更改,即使git的内置文档中也没有很好地记录其中的一些内容.你的报价写着:
The next part about refspecs is even more wrong, due to git having acquired several changes over time, some of which are not documented well even in git's built-in documentation. Your quote reads:
在没有refspec的情况下,git push会将您的提交发送到远程存储库和上游存储库之间公用的所有分支.
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.
新文档说:
当命令行未指定要使用
<refspec>...
推送的内容时 参数或--all
,--mirror
,--tags
选项,该命令将找到 通过咨询remote.*.push
配置获得默认的<refspec>
, 如果找不到,则使用push.default
配置来决定 推送内容(请参见 git-configpush.default
的含义.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左右添加的,但其默认 value 在git 2.0中已更改.如果尚未配置push.default
,则会收到以下警告:The
push.default
setting was added around version 1.8 of git, but its default value changed in git 2.0. If you have not configured apush.default
you get this warning:warning: push.default is unset; ...
自配置项可用以来.咨询 git-config文档,您将现在找到这个:
ever since the configuration item became available. Consulting the git-config documentation, you will now find this:
push.default
定义在未明确给出refspec的情况下git push
应该执行的操作.不同的值非常适合特定的工作流程...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
.There are five options, which I will simply list here (see the linked documentation for details):
nothing
,current
,simple
,upstream
, andmatching
. The book text you quote describesmatching
, which was the default behavior prior to git version 2.0. The new default issimple
.您的存储库和上游存储库之间共有的所有分支"是否与本地存储库中的所有远程跟踪分支以及远程存储库中的相应跟踪分支相同?
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
替换为任何其他遥控器的名称):I recommend that you try running
git ls-remote origin
(or replaceorigin
with the name of any other 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
夹在中间.You'll see similar output, but with different SHA-1s, and the word
commit
sandwiched in the middle.这里的要点是,在
refs/heads
中列出的每个头"(在来自ls-remote
和for-each-ref
的两个输出中)都表示git push
在进行匹配"时考虑的(本地)分支.匹配的头将添加到推式列表中,提供一组refspec(内部形式,但很容易表示为name:name
,或者,如果使用了--force
标志,则表示为+name:name
).The main point here is that each "head" listed in
refs/heads
—in both outputs, fromls-remote
and fromfor-each-ref
—represent the (local) branches thatgit push
considers when doing "matching". The heads that match are added to the push list, giving the set of refspecs (in internal form but easily expressed asname:name
or, if you used the--force
flag,+name:name
).即使没有为这些本地分支配置上游,也会发生 .因此,如果他们(远程)具有供鲍勃·罗伯茨使用的
refs/heads/bob
,并且您要使用refs/heads/bob
来获取有关水管鲍勃,钓鱼鲍勃或其他东西的信息,则git会尝试匹配即使您的bob
并非本意是上游的.This happens even if there is no upstream configured for those local branches. Thus, if they (the remote) have a
refs/heads/bob
that's meant for Bob Roberts to use, and you have arefs/heads/bob
that you're using for information about your plumbing bobs or fishing bobbers or whatever, git will attempt to match those up even though yourbob
is not meant to go upstream.报价为
git push
.它是否适用(特别是没有refspec的情况下的部分)是否适用于git fetch
和git pull
?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
试图将基本在存储库范围内的获取"操作与基本受分支约束的合并"操作混在一起.这两个不能很好地配合使用. 1 (充其量,我认为可以在某些时候修改git pull
以进行更简单的,整个存储库范围内的全部提取,然后以逐对的方式签出并合并,某些分支基于跟踪配置和参数"序列.我认为这将使其行为像大多数人期望的那样.它也大多是向后不兼容的,并且行为仅适用于现在最简单(但默认)的情况是:先提取所有内容,然后仅合并当前分支.但这全都是推测.)The behavior of
git fetch
is easier to explain, because it doesn't do all the weird stuff on you thatgit pull
does. Thegit pull
command is supposed to be convenient, butgit pull
is trying to mash a fundamentally repository-wide "fetch" operation together with a fundamentally branch-constrained "merge" operation. These two do not play well together.1 (At best, I thinkgit pull
could at some point be modified to do a simpler, repository-wide "fetch all, then check out and merge, pairwise, some branch(es) based on tracking configs and arguments" sequence. I think this would make it behave the way most people seem to expect it to. It would also be mostly backwards-incompatible, and behave the way it does now only for the simplest—but default—case: fetch all, then merge current branch only. But that's all speculation anyway.)如果省略所有refspec,则
git fetch
会读取您的remote.$remote.fetch
配置行.(请注意,此忽略所有refspecs"子句意味着您还必须避免使用方法.) If you omit all refspecs,
git fetch
reads yourremote.$remote.fetch
configuration lines. (Note that this "omit all refspecs" clause means you must also avoid the old "Named file in$GIT_DIR/branches
" method, for instance.)名为
origin
的远程服务器的默认配置行(单数)通常如下所示(查看本地存储库配置文件以查看它):The default configuration line (singular) for a remote named
origin
usually looks like this (view your local repository configuration file to see it):[remote "origin"] +refs/heads/*:refs/remotes/origin/*
这是远程跟踪分支"成立的实际机制.
This is the actual mechanism by which "remote-tracking branches" come into existence.
fetch
过程从相同的git ls-remote origin
步骤开始,该步骤从远程获取每个引用的列表(分支,标签或您拥有的内容).fetch
代码继续将它们与[remote "origin"]
下的每个fetch =
行匹配. refspec左侧的星号具有明显的含义;右侧的星号将替换为左侧的星号匹配的内容. (在当前版本的git中,*
必须与整个部分"匹配,松散地定义为斜线之间的填充",但是在即将到来的git中,此约束将得到放松-尽管我不确定达到什么目的.)The
fetch
process starts off with that samegit ls-remote origin
step, which gets a list of every reference—branch, tag, or what-have-you—from the remote. Thefetch
code goes on to match these up with each of thefetch =
lines under[remote "origin"]
. Asterisks on the left side of a refspec have the obvious meaning; asterisks on the right side are replaced with whatever the left-side asterisk matched. (In current versions of git the*
must match a "whole part", loosely defined as "stuff between slashes", but in the upcoming git this constraint will be relaxed—though I'm not sure to what useful end.)您可能会喜欢任意多的
fetch =
行.每个原始引用都在每一行中运行,以获取新的(替换)引用:如果左侧匹配,则右侧提供替换. (如果右侧缺少或为空,则由于历史原因,该行为会变得有些奇怪,部分原因是保持git pull
正常运行,部分原因是所需行为在git 1.8左右变化.)You may have as many
fetch =
lines as you like. Each original reference is run through each line to get a new (replacement) reference: if the left side matches, the right side provides the replacement. (If the right side is missing or empty, the behavior gets a bit weird for historical reasons, partly to keepgit pull
working, partly because the desired behavior changed around git 1.8 or so.)所有这些替换的结果形成重命名的引用,并确定完全复制了哪些引用;但每个原始引用最多只能有一个结果:您不能将其"引用/heads/foo映射到您的"引用/remotes/origin/bar ,而您的引用/remotes/例如起源/动物园.
The results of all these replacements form the renamed references, and determine which references are copied at all; but there must be at most one result for each original reference: you can't map "their" refs/heads/foo to "your" refs/remotes/origin/bar and your refs/remotes/origin/zoink, for instance.
要使存储库充当镜像,您可以使用
+refs/*:refs/*
来带入所有引用而无需重命名(但这会破坏每个fetch
上的本地分支,因此仅在--bare
下才有意义)To make a repository act as a mirror, you can use
+refs/*:refs/*
to bring over all references with no renaming (but this will clobber your local branches on eachfetch
so this mostly makes sense only with--bare
).(修剪"(基于在启动协商期间对方为获取或推送而发送的内容删除死"引用,这是单独完成的,并且仅当您设置了
--prune
标志时才可以.)("Pruning"—removing "dead" references based on what the other side sent during the startup negotiations for a fetch or push—is done separately and only if you set the
--prune
flag.)1 它不是以这种方式开始的.实际上,原始的
pull
脚本完全早于远程和远程跟踪分支.提交7ef76925d9c19ef74874e1735e2436e56d0c4897
将pull
拆分为pull
和fetch
,然后随着时间的流逝,两个方向朝着不同的方向发展;一旦远程"和远程跟踪分支"出现了,它们就演变为试图将它们混合在一起的想法,我认为这只是一个坏主意,而现在变得更糟了. :-)1It didn't start out this way. In fact, the original
pull
script predated remotes and remote-tracking branches entirely. Commit7ef76925d9c19ef74874e1735e2436e56d0c4897
splitpull
intopull
andfetch
and then the two evolved in different directions over time; once "remotes" and "remote-tracking branches" came into existence, they'd evolved to the point that trying to mix them was, I think, just a bad idea, and now it's even worse. :-)这篇关于在不使用refspec参数的情况下运行git push,pull和fetch的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!