养成使用origin 或github 之类的远程名称的习惯可能会好得多,但我自己对此有点疑惑,所以我进行了一些调查。简短的回答是,在没有 refspec 的情况下,git fetch <em>url</em> 会带来他们在HEAD 中的所有内容,并将其丢弃在您的FETCH_HEAD 中(见下文)。
git fetch 的三种模式
不包括“组”(这使情况更加复杂),git fetch 命令允许的有用语法是以下三种中的一种,但每次只能使用一种:
git fetch <em>remote</em> [<em>refspecs</em>]
git fetch url [<em>refspecs</em>]
git fetch --multiple <em>remote</em> [<em>remotes</em>]
方括号表示可选的附加参数。
remote 只是一个名称,例如 origin,您已将 git 存储在配置文件中。当您第一次克隆存储库时,git 会为您创建名称 origin;对于其他人,您通常希望使用 git remote add <em>name</em> <em>url</em> 添加一个名为 name 的新遥控器。 每个远程都存储一组默认的 fetch refspecs 以及 URL,当您运行 git fetch 时,如果您从命令行中省略它们,这些就是使用的 refspecs。 (如果您提供了至少一个 refspec,则配置的默认值将被忽略,而使用您提供的默认值。)
refspecs 决定了要获取什么。我稍后会详细描述一下。
如果您直接指定 URL 而不是远程名称,那么 git 在这里的行为仍然相同:它使用您提供的 refspecs 来确定要获取的内容。 URL 与命名远程的主要区别在于,对于 URL,没有配置文件条目来提供默认的 refspecs 集。这意味着您可能应该至少提供一个 refspec。 但是,如果您不这样做,那么在这种情况下默认的 refspec 就是 HEAD。请参阅下文了解这意味着什么。
(为了完整起见,最后一种形式,--multiple,只是告诉git fetch,所有参数都是远程名称,而不是一个远程名称后跟一些 refspecs。在这种情况下refspecs都像往常一样来自配置文件.换句话说--multiple只是告诉git,例如,当你说git fetch --multiple origin github时,你并不是要从origin获取refspec github,而是要从远程origin,然后也来自远程github。)
参考规范
我认为,Git 的 refspec 是使用 git 的文档最少且最令人困惑的方面之一。这是令人惊讶的,因为它们实际上非常简单和优雅,尽管您必须简单地学习和记住一些奇怪的东西。
refspec 的通常形式只是一对分支或标签名称,例如master:master 或v1.2:v1.2。完整形式拼出完整的参考名称,例如refs/heads/master 或refs/tags/v1.2,还包括一个可选的前导加号+(我将在这里忽略);还有一个更缩写的形式,只包含一个分支或标签名称,例如,master。
有点令人困惑的是fetch 和push 并不完全对称。
首先,使用fetch,您将他们的 分支名称放在左侧,您的 名称放在右侧。如果您想将分支master 从远程带到您的分支work,您可以将其写为master:work。但是,使用push,您将您的 分支名称放在左侧,将他们的 名称放在右侧:从您的work 推送到他们的master,你会写work:master。记住这一点的简单方法是它始终是<em>from</em>:<em>to</em>,左边是“源”,右边是“目的地”。提取的来源是“他们的东西”,而推送的来源是“你的东西”。
第二个更重要的是,对于fetch,如果您只写一个名称,“目标”部分默认为空:将获取的内容放在no 分支或标签。对于push,“目标”部分默认为一个相当复杂的方法,我不会在这里描述,只是说它永远不会为空。
通常,如果你带来一个分支,放置它的最佳位置是远程跟踪分支。例如,如果您从origin 中带入master,则应将结果放入refs/remotes/origin/master(这是origin/master 的完整拼写形式)。同样,如果你带了一个标签,最好的放置它的地方也是一个标签。如果您使用远程名称,git 将为您设置所有这些,您无需做任何特别的事情,您只需 git fetch origin 并将其所有分支复制到您自己的远程跟踪分支,并带有特殊标签为相应的标签做了魔术。
但是,如果您不想使用远程跟踪分支,则可以使用 git fetch 仍然处理它带来的事情的更老的方式。 git 在 .git 目录中保存了一个名为 FETCH_HEAD 的特殊文件。每次获取,即使只是去一个 URL,都会更新这个文件(通常完全替换它,但是用-a 或--append,保留旧内容并添加新内容)。无论git fetch 带来什么,它都会写入这个文件。
这有两个含义:
- 如果您通过参数提供 refspec,但将其目的地留空,
fetch 会带来您命名的源,但仅将结果放入 FETCH_HEAD。
- 如果您不提供任何参考规范,请记住,这仅适用于
git fetch 的纯 URL 形式,因为远程名称形式从以下位置获取默认参考规范配置文件1——然后git fetch 假装你给了它HEAD,这使得目的地为空。这带来了HEAD,并且与案例1一样,只将结果放入FETCH_HEAD。
特殊的HEAD 引用是遥控器上设置的HEAD。使用典型的“裸”存储库HEAD 通常是指向分支master 的符号引用,因此您使用URL 的默认设置可能会带来他们的master,但只将它放在您的FETCH_HEAD .但这取决于他们对HEAD 参考所做的处理(当然,这是他们可以随意控制的)。
1我实际上不确定当配置文件没有 fetch = 行时会发生什么:git fetch 是否将其视为“根本不提供任何参考”,还是将其视为这就像“我没有参考规范,所以提供默认的 HEAD 参考规范,目的地是空的,比如 URL”?