【问题标题】:Git: Fetch a detached HEAD from remoteGit:从远程获取一个分离的 HEAD
【发布时间】:2019-03-13 00:16:23
【问题描述】:

我检查一个特定的提交(因此,最终处于分离的 HEAD 状态),然后在它之上进行一些提交。假设我在存储库 A 中执行此操作。让我们进一步假设我有另一个存储库 B,其中 A 作为其远程之一。现在,在 B 中,如何获取 A 的分离 HEAD 而无需在 A 中创建新分支?

【问题讨论】:

  • 现在不在A repo 中创建分支,您将无法推送您所做的提交。所以,不可能从B repo 获取新的提交(据我所知)
  • 您提到的链接,您需要在A repo 中创建一个远程分支,但您说不想创建新分支(“...没有在 A 中创建新分支”)
  • 试试git fetch <remote> HEAD。如果成功,A 的HEAD 的tip 将存储到B 的FETCH_HEAD

标签: git


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    作为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:如果你尝试,他们只会创建一个名为HEADbranch,即refs/head/HEAD,如果你现在在一个分支上,或者如果没有,请拒绝您的推送请求:

    error: unable to push to unqualified destination: HEAD
    

    另一方面,当您运行git fetch 时, 控制最终更新哪些引用(如果有)。他们的 Git 只是发送一个列表所有他们的引用(无论如何在协议 v0 中;v2 更漂亮)。你的 Git 会选择列表,如果他们向你发送了他们的 refs/heads/masterrefs/heads/branch 的新哈希 ID,你的 Git 通常会更新你自己的 refs/remotes/origin/masterrefs/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>:*dstsrc 部分是源引用——发送者用来查找提交的名称或哈希 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/mastergit 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 对列表中获得了许多分支和标签,但我们只询问 HEADmaster,所以这就是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 中记住为“未命名”。

    【讨论】:

      猜你喜欢
      • 2014-03-17
      • 2021-09-09
      • 1970-01-01
      • 2015-04-17
      • 2023-04-09
      • 2020-06-09
      • 2012-03-21
      相关资源
      最近更新 更多