我想将远程存储库的单个提交(当然有历史记录)提取到本地存储库中。一些 Stack Overflow 回复表明以下内容应该有效,但事实并非如此:
md foo
cd foo
git init
git fetch https://github.com/ld4apps/lda-serverlib.git f1e32e18a90e10c150221af55c69aeafaa42c57a
这会产生以下错误:
error: no such remote ref f1e32e18a90e10c150221af55c69aeafaa42c57a
令我惊讶的是(对我而言)以下确实(有点)起作用:
git fetch https://github.com/ld4apps/lda-serverlib.git :f1e32e18a90e10c150221af55c69aeafaa42c57a
这会创建一个名为 f1e32e18a90e10c150221af55c69aeafaa42c57a
的新本地分支(我不想要),但至少新分支具有我尝试获取的内容。我可能期望以下命令会做同样的事情,但它会得到与第一个示例相同的错误:
git fetch https://github.com/ld4apps/lda-serverlib.git f1e32e18a90e10c150221af55c69aeafaa42c57a:f1e32e18a90e10c150221af55c69aeafaa42c57a
我在 Windows 和 Linux 上用几个不同的 git 版本尝试了这个,并看到了相同的行为。
谁能解释一下这是怎么回事?我对 Git、fetch
和 refspecs 有什么不了解的地方?我真正想要的是单个 git fetch
命令,我可以向其提供远程分支或标记的 ID 或提交 ID,它将获取相应的提交。
最佳答案
更新:自 Git 2.5(2015 年中左右)以来,服务器现在可能暴露原始哈希。这是一个服务器端配置项。您必须对服务器有足够的控制权才能进行设置,并且在设置之前应考虑潜在的安全问题。有关详细信息,请参见 this answer 至 Retrieve specific commit from a remote Git repository。 (原始答案,适用于 pre-2.5 或如果未设置配置旋钮,请参见下文。)
git fetch
命令或多或少地向远程传送引用(名称,而非原始提交 ID)。 (更具体地说,使用 git ls-remote <em>remotename</em>
查看远程愿意为您提供的名称。这会在左侧生成一个 SHA-1 列表,在右侧生成名称,而您的 fetch
唯一可以询问 for is the names-on-the-right. 此时您将获得 ID-on-the-left if Remote 上的名称仍指向该 ID,因此它取决于 Remote 更新的积极程度。)
可以通过多种方式将原始提交 ID 传送到远程并询问远程从该点开始可见的内容,有时也可以通过历史向后工作,但不是通过 git fetch
。 (您可以使用 git archive
但远程可以决定是否允许您通过原始提交 ID 进行访问;或者对于具有 Web 服务器访问权限的远程,包括特定提交,您通常可以只查看顶级内容提交,并用它来“向下钻取”,正如他们所说,到各个部分。但这是一种非常缓慢的方法。)
如果您想使用 git fetch
来获取某个特定的提交,最简单的方法可能是让有权访问远程的人为该提交 ID 附加一个名称(很可能是一个标签)。然后你可以让你的 git fetch
带上那个 refspec,并将它放在你喜欢的任何其他 refspec 下。例如,假设您可以直接通过 ssh 连接到任何主机 origin
:
$ ssh our.origin.host 'cd /repos/repo.git; git tag temporary f1e32e1'
[enter password, etc; observe tag created]
$ git fetch origin refs/tags/temporary:refs/heads/newbranch
[observe fetch happen; now you have local branch 'newbranch']
$ ssh our.origin.host 'cd /repos/repo.git; git tag -d temporary'
请注意,名称不必是分支,它只需要是一个引用,您可以使用 git fetch
parking 并使用 git ls-remote
查看。然后,您使用一个名称,该名称将在获取时与您的 refspec 左侧的名称相匹配。在您的 存储库中创建的名称由 refspec 的右侧控制(上例中为 refs/heads/newbranch
)。
这也是你最后一段问题的答案:你只能命名在远程有名字的东西(这部分是为了避免“泄漏”在垃圾收集之前保留在存储库中的未命名提交,所以它被认为功能而不是错误)。这些名称位于 refspec 的左侧。你自己的名字在右边。
你右边的名字被假定为一个分支或标签名(基于左边的名字匹配,虽然你可以明确拼出 refs/heads/
或 refs/tags/
来覆盖它),所以即使 f1e32e1...
是一个有效的 SHA -1,它在这里被视为一个分支名称——左边缺失的名称转换为 HEAD
,因为缺失的名称几乎总是如此——而 git fetch
创建了一个名称令人不安的 SHA-1ish 分支。 (顺便说一句,我曾经创建了一个看起来像 SHA-1 的分支名称,后来我把自己弄糊涂了。我忘记了具体的名称,比如没有连字符的 de-bead
。我将它重命名为带连字符的版本只是为了清楚我没有这意味着原始提交 ID!:-) )
关于Git 获取单个提交,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25815202/