Git:从远程获取分离的HEAD

时间:2018-10-08 10:31:46

标签: git

我签出特定的提交(因此,最终以分离的HEAD状态结束),然后在其上面进行一些提交。假设我在存储库A中进行了此操作。进一步假设我有另一个存储库B,该存储库B以A作为其远程服务器之一。现在,在B中,如何在不创建A的新分支的情况下获取A 的分离的HEAD?

2 个答案:

答案 0 :(得分:2)

ElpieKay answered in a comment一样,使用git fetch remote HEAD,这会将获取的提交的哈希ID保存在特殊的FETCH_HEAD文件中。然后,您可以使用FETCH_HEAD作为参考,直到下一个git fetch覆盖它为止。

讨论

获取和推送操作都可以使用名称,但是它们不是对称的。

在传输 commits 时,它们 是对称的。也就是说,无论您运行git fetch remote [refspec...]还是git push remote [refspec...],发送和接收Git系统都会进行涉及对象哈希ID的对话,在该会话中,发送方将发送方想要提供给接收方的哪些哈希ID公告: em>我为您准备了 ,接收方发回答复,说发送方应发送该对象,或者-如果接收方已经具有该对象,则不发送该对象。 (这比这要复杂一些,因为获取接收器会从第一个“想要”开始该过程,但要足够接近。)

不过,完成此操作后,push操作将使发送者发送一系列推荐的对:请将您的refs/heads/master设置为{{1 }} 。这意味着,如果您在{em>您的存储库中的a123456...上处于分离状态,git push,则仍必须给 other Git一个提交的名称:

HEAD
例如,

足以让您的Git发送您的git push origin HEAD:refs/heads/somebranch 提交的哈希ID,但是建议他们的Git将 HEAD 设置为完成后该哈希ID。您不能要求他们设置他们的refs/heads/somebranch:如果尝试,他们只会创建一个名为HEAD分支,即HEAD(如果您现在在分支机构上,否则请拒绝您的推送请求:

refs/head/HEAD

另一方面,当您运行error: unable to push to unqualified destination: HEAD 时,控制哪个参考(如果有的话)最终得到更新。他们的Git只是发送 all 他们的引用的列表(无论如何,协议v0; v2更为出色)。您的Git会选择列表,如果他们为您的git fetchrefs/heads/master发送了新的哈希ID,则您的Git通常会更新您自己的refs/heads/branchrefs/remotes/origin/master。您的Git会获取他们的引用列表,生成您一方的“想要的”哈希ID列表,然后将其传递给发送者,以开始进行有/想要的哈希ID对话。

也就是说,如果您运行refs/remotes/origin/branch,并且添加了 no git fetch origin 参数,并且假设您的配置正常,那么Git就是这样做的(例如,不是refspec克隆的特殊配置)。但是,如果您执行添加refspec参数,例如:

--single-branch

然后,您的Git要求其Git仅发送您与他们的git fetch origin refs/heads/master:refs/weird/name 合作所需的提交。也就是说,有/想要的对话以其master中的哈希ID only 开始(即使如此,仅当您还没有哈希ID时)。完成需求后,对象已到达存储库中,Git然后创建或更新您的refs/heads/master引用。

请记住,这些refspec的常规格式为refs/weird/name src:*dst 部分是源引用(发送方用来查找提交的名称或哈希ID)和 src 部分是目标参考,接收者应使用该参考来最终记住哈希ID。您可以通过编写 dst src来省略两者之一,具体取决于推与取,它们具有各种特殊情况的含义。原始哈希ID是否在此表达式的 :dst 部分中起作用取决于两件事:

  • 如果您正在执行src,则它始终有效(只要对象存在);
  • 如果您正在使用push,则当且仅当他们允许时,它才有效。

(因此,在这里,我们已经看到提取和推送是不对称的。)

对于fetch,如果您省略了refspec的git fetch部分(例如:dstgit fetch origin refs/heads/master),您的Git会跳过创建或更新部分,但用于所谓的机会更新(在这种情况下,创建或更新git fetch origin master)。但是,对于您的refs/remotes/origin/master获得的每个名称,您的Git 总是对写入您的git fetch文件中:

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的名称/ ID对列表中有许多分支和标签,但我们{em>只是为origin和{ {1}},这就是HEAD写到master的内容。)

结论

如果您正在发送提交,则必须为另一个Git提供一个名称。通常,该名称是隐式的:您按下分支git fetch,因此要 them 设置的名称是 their 分支.git/FETCH_HEAD。您可以推送任何对象:接收对象后,由其Git决定是否接受配对。通常,您将推送一个提交对象,该提交对象将与它一起拖动所有其他所需的对象,并使它们设置分支名称。

但是,如果您正在接收,则不需要您的身边提供名称。他们的Git将发送其名称和对象,而您的Git将使用您的bran文件来记住您从他们那里获得的哈希ID。如果确实提供名称,则Git会更新这些名称,否则,Git会具有一些复杂的默认获取规则,以便通过bran名称记住其分支名称。

虽然.git/FETCH_HEAD本身不是分支名称,但它是有效的名称。您可能无法使他们更新其分离的refs/remotes/remote/(通过HEAD),但是通常可以让他们向您发送存储在其分离的{{1 }},您的Git会在您的HEAD中将其记为“未命名”。

答案 1 :(得分:-1)

我认为您不能只推一个独立的头。如果要查看B中的这些更改,则必须将提交推送到A中的某个位置。要么进入新分支,要么进入现有分支。 由于您不想在A中创建新分支,因此我假设您已将提交推送到原始分支中。因此,您可以通过简单的拉动来访问它们。

如果您还没有将提交推送到任何地方,那么我可以说,最好的方法是直接在存储库B中进行更改。