作为ElpieKay answered in a comment,使用git fetch <em>remote</em> HEAD,它将获取的提交的哈希ID保存在特殊的FETCH_HEAD文件中。然后您可以使用FETCH_HEAD 作为参考,直到下一个git fetch 覆盖它。
讨论
获取和推送操作都使用名称,但它们不是对称的。
在传输提交时,它们是对称的。也就是说,无论您运行git fetch <em>remote</em> [<em>refspec...</em>] 还是git push <em>remote</em> [<em>refspec...</em>],发送和接收Git 系统都会进行涉及对象哈希ID 的对话,其中发送方会通告发送方希望将哪些哈希ID 提供给接收方:我有 为你,然后接收者回复说发送者应该发送那个,或者——如果接收者已经拥有那个对象——不发送它。 (比这复杂一点,因为 fetch-receiver 以第一个“想要”开始该过程,但足够接近。)
完成后,push 操作让发件人发送一系列推荐的 对:请将您的 refs/heads/master 设置为 a123456...例如。这意味着,如果您正在执行git push,而您在您的 存储库中的一个分离的HEAD 上,您仍然必须为此提交给其他 Git 一个名称:
git push origin HEAD:refs/heads/somebranch
例如,让您的 Git 为您的 HEAD 提交发送哈希 ID 就足够了,但建议他们的 Git 设置 他们的 refs/heads/somebranch to 时完毕。你不能要求他们设置他们的HEAD:如果你尝试,他们只会创建一个名为HEAD 的branch,即refs/head/HEAD,如果你现在在一个分支上,或者如果没有,请拒绝您的推送请求:
error: unable to push to unqualified destination: HEAD
另一方面,当您运行git fetch 时,您 控制最终更新哪些引用(如果有)。他们的 Git 只是发送一个列表所有他们的引用(无论如何在协议 v0 中;v2 更漂亮)。你的 Git 会选择列表,如果他们向你发送了他们的 refs/heads/master 和 refs/heads/branch 的新哈希 ID,你的 Git 通常会更新你自己的 refs/remotes/origin/master 和 refs/remotes/origin/branch。你的 Git 获取他们的引用列表,生成你方的“想要”哈希 ID 列表,并将其传递给发送者以启动拥有/想要哈希 ID 对话。
也就是说,如果你运行 git fetch origin,你的 Git 会这样做,no 添加 refspec 参数,并假设你的配置是正常的(不是特殊的例如为--single-branch 克隆留下的配置)。但是如果你做添加 refspec 参数,例如:
git fetch origin refs/heads/master:refs/weird/name
然后你的 Git 要求他们的 Git 只发送你需要使用他们的master 的提交。也就是说,拥有/想要的对话以 only 他们refs/heads/master 中的哈希 ID 开始(即使那样,只有在您还没有它的情况下)。当拥有/想要完成并且对象已到达您的存储库时,您的 Git 然后会创建或更新您的 refs/weird/name 引用。
请记住,这些 refspec 具有一般形式 <em>src</em>:*dst。 src 部分是源引用——发送者用来查找提交的名称或哈希 ID——以及 dst部分是 destination reference,接收者应该使用它来记住最后的哈希 ID。您可以通过编写 src 或 :<em>dst</em> 省略两者之一,根据推送与获取,它们具有各种特殊情况的含义。原始哈希 ID 在此表达式的 src 部分中是否有效取决于两件事:
- 如果您正在执行
push,它始终有效(只要对象存在);
- 如果您正在执行
fetch,当且仅当他们允许时,它才有效。
(所以在这里,我们已经看到 fetch 和 push 是不对称的。)
对于git fetch,如果你省略了引用规范中的:<em>dst</em> 部分——例如git fetch origin refs/heads/master 或git fetch origin master——你的Git 会跳过创建或更新部分,除了所谓的opportunistic更新(在这种情况下创建或更新refs/remotes/origin/master)。但是,对于您的 git fetch 获得的每个名称,您的 Git 总是 将该 对写入您的 FETCH_HEAD 文件:
$ git fetch origin HEAD master
From ...
* branch HEAD -> FETCH_HEAD
* branch master -> FETCH_HEAD
$ cat .git/FETCH_HEAD
f84b9b09d40408cf91bbc500d9f190a7866c3e0f <url>
f84b9b09d40408cf91bbc500d9f190a7866c3e0f branch 'master' of <url>
(请注意,尽管git fetch 在来自origin 的名称/ID 对列表中获得了许多分支和标签,但我们只询问 HEAD 和master,所以这就是git fetch 写到.git/FETCH_HEAD。)
结论
如果您要发送提交,您必须为其他 Git 提供 名称。通常名称是隐含的:您推送您的分支bran,因此您希望them 设置的名称是their 分支bran。您可以推送任何对象:由他们的 Git 在收到对象后决定是否接受 配对。通常,您将推送一个提交对象,该对象将与它一起拖动所需的所有其他对象,并且您将让它们设置一个分支名称。
但是,如果您接收提交,则不需要在您的身边提供名称。他们的 Git 将发送他们的姓名和对象,您的 Git 将使用您的 .git/FETCH_HEAD 文件来记住您从他们那里获得的哈希 ID。如果你确实提供了名称,你的 Git 会更新这些名称,如果你不这样做,Git 有一些复杂的默认获取规则,通过refs/remotes/<em>remote</em>/ 名称记住它们的分支名称。
虽然HEAD 本身不是分支 名称,但它是一个有效的名称。您可能无法让他们更新其分离的HEAD(通过push),但您通常可以让他们将存储在其分离的HEAD 中的提交哈希发送给您,您的Git将在您的.git/FETCH_HEAD 中记住为“未命名”。