从远程Git存储库中检索特定的提交


189

有什么方法可以从远程Git存储库中仅检索一个特定的提交,而无需将其克隆到我的PC上吗?远程回购的结构与我的完全相同,因此不会有任何冲突,但是我不知道如何执行此操作,并且我不想克隆该大型存储库。

我是git的新手,有什么办法吗?


1
您现有的仓库已经是远程仓库的克隆,还是完全不同?
CharlesB

好吧,该回购是Linux内核源代码,并且几乎相同
Varun Chitre

那是克隆还是没有?
CharlesB

1
不完全是。考虑到这一点,让远程仓库位于D头,而我的仓库位于A头,然后由B,C,D提交落后。我希望合并一个仓库中的提交B和另一个仓库中的C以及另一个仓库中的D的合并,因为这些仓库中的B,C,D提交具有各自的特色
Varun Chitre 2013年

1
@VarunChitre您可以接受VonC的其他答案吗?
CharlesB

Answers:


109

从Git 2.5+版本(2015年第二季度)开始,实际上可以获取单个提交(不克隆完整存储库)。

提交68ee628弗雷德里克混合泳(moroten,2015年5月21日
(以合并JUNIOÇ滨野- gitster-提交a9d3493,2015年6月1日)

现在,您有了一个新的配置(在服务器端)

uploadpack.allowReachableSHA1InWant

允许upload-pack接受从任何参考提示中请求可访问对象的提取请求。但是,请注意,计算对象的可达性在计算上是昂贵的。
默认为false

如果将该服务器端配置与浅表克隆(git fetch --depth=1)结合使用,则可以要求进行一次提交(请参阅t/t5516-fetch-push.sh

git fetch --depth=1 ../testrepo/.git $SHA1

您可以使用以下git cat-file命令来查看是否已提取提交:

git cat-file commit $SHA1

可以告诉git upload-pack服务“ git fetch”的“ ”提供带有uploadpack.allowReachableSHA1InWant 配置变量的服务,只要它们可以从引用访问,只要提交不在任何引用的顶端。


完整的文档是:

upload-pack:可选地允许获取可达的sha1

通过uploadpack.allowReachableSHA1InWant在服务器端设置配置选项,“ git fetch”可以用“ want”行发出请求,该行命名一个尚未发布的对象(可能是从带外或从子模块指针获得的)。
仅处理分支提示中可到达的对象,即,已通告的分支与被隐藏的分支的并集transfer.hideRefs
请注意,必须走回历史记录以检查可及性,这具有相关的成本。

当获取已知提交的特定提交的内容时,可以使用此功能,而无需克隆整个存储库,尤其是在使用浅层提取的情况下

有用的案例例如

  • 历史记录中包含大文件的存储库,
  • 仅获取子模块检出所需的数据,
  • 在共享sha1时不知道它属于哪个确切分支以及在Gerrit中时,是否考虑提交而不是更改编号。
    (Gerrit案已经解决,allowTipSHA1InWant因为每次Gerrit更改都有参考。)

Git 2.6(2015年第三季度)将改进该模型。
参见Jeff King()的commit 2bc31d1cc118a6(2015年7月28日(通过合并JUNIOÇ滨野- -提交824a0be 8月19日2015)peff
gitster

refs:支持负面 transfer.hideRefs

如果使用transfer.hideRefs配置隐藏参考的层次结构,则以后将无法覆盖该配置以“取消隐藏”它。
该补丁实现了“负”隐藏,即使其他匹配将其隐藏,该匹配也会立即将匹配标记为未隐藏。
我们注意按照与配置机器提供给我们的方式相反的顺序应用匹配项,因为这样可以使我们通常的“最后一个获胜”配置优先级起作用(.git/config例如中的条目将被覆盖/etc/gitconfig)。

因此,您现在可以执行以下操作:

git config --system transfer.hideRefs refs/secret
git config transfer.hideRefs '!refs/secret/not-so-secret'

隐藏refs/secret在所有回购中,但一个特定回购中只有一个公开位除外。


Git 2.7(2015年11月/ 2015年)将再次得到改进:

参见commit 948bfa2commit 00b293e(2015年11月5日),commit 78ca766acommit 92cab49commit 92cab49commit 92cab49(2015年11月3日),commit 00b293ecommit 00b293e(2015年11月5日)和commit 92cab49commit 92cab49commit 92cab49,由Lukas Fleischer(提交92cab49(2015年11月3日。 协作者:Eric Sunshine((通过合并杰夫·金- -提交dbba85e 11月20日2015)lfos
sunshineco
peff

config.txt:记录hideRefs命名空间的语义

目前,还没有明确定义在transfer.hideRefs设置命名空间时应如何表现。
说明hideRefs在这种情况下,前缀匹配剥离的名称。这就是hideRefs当前在接收包中处理模式的方式。

hideRefs:添加对匹配完整裁判的支持

除了匹配剥离的ref,现在还可以添加hideRefs与完整(未剥离)的ref匹配的模式。
为了区分剥离匹配项和完全匹配项,这些新模式必须以抑音符(^)开头。

因此,新文档

transfer.hideRefs:

如果使用了名称空间,则在将其与transfer.hiderefs模式匹配之前,将从每个引用中删除该名称空间前缀。
例如,如果refs/heads/master在被指定transfer.hideRefs并且目前的命名空间foo,然后refs/namespaces/foo/refs/heads/master 从广告省略,但refs/heads/masterrefs/namespaces/bar/refs/heads/master仍然通告为所谓的“有”行。
为了在剥离之前匹配参考^,请在参考名称之前添加一个。如果将!和组合在一起^,则!必须先指定。


R .. 在注释中提到config uploadpack.allowAnySHA1InWant,它允许upload-pack接受一个fetch根本不要求任何对象的请求。(默认为false)。

参见David“ novalis” Turner()的commit f8edeaa(2016年11月,Git v2.11.1 novalis

upload-pack:可选地允许获取任何sha1

在我们信任用户绝对访问存储库中的所有内容的情况下,进行可及性检查似乎有些愚蠢。

此外,它在分布式系统中非常流行-也许一台服务器宣传一个引用,但是另一台服务器随后对该引用进行了强制推送,也许两个HTTP请求最终指向了这些不同的服务器。


4
您能否给出一个更完整的示例,说明如何仅通过一次提交即可创建回购克隆?我尝试了但是失败了..谢谢!
拉尔斯·比尔克

1
我想推送到GitHub。也许他们不允许这样做。
拉尔斯·比尔克

2
@LarsBilke我们在这里谈论克隆或拉动,而不是推。而且我很确定GitHub在服务器端还没有Git 2.5。
VonC

2
现在更好的是,uploadpack.allowAnySHA1InWant没有可达性计算损失(和DoS向量)。
R .. GitHub STOP HELPING ICE

1
谢谢!我觉得有趣的是,他们将其描述为“信任用户访问”,而不是“信任回购作者不要随意散发他们不打算公开的废话”。
R .. GitHub STOP HELPING ICE

97

您只需克隆一次,因此,如果您已经有一个远程存储库的克隆,那么从它中提取将不会再次下载所有内容。只需指出您要拉的分支,或获取更改并签出所需的提交即可。

从新存储库获取的带宽非常便宜,因为它只会下载您没有的更改。考虑一下Git用最小的负载做正确的事情。

Git将所有内容存储在.git文件夹中。提交不能孤立地获取和存储,它需要其所有祖先。它们是相互关联的


为了减少下载大小,您可以要求git只获取与特定分支或提交相关的对象:

git fetch origin refs/heads/branch:refs/remotes/origin/branch

这将仅下载包含在远程分支中的提交branch (并且仅下载您错过的提交,并将其存储在中origin/branch。然后,您可以合并或签出。

您还可以仅指定SHA1提交:

git fetch origin 96de5297df870:refs/remotes/origin/foo-commit

这将仅下载指定的SHA-1 96de5297df870(及其遗漏的祖先)的提交,并将其存储为(不存在)远程分支origin/foo-commit


3
您似乎对克隆的含义感到困惑。从远程存储库中获取更改时,您不会克隆它,而只是在历史记录中获得提交。然后,您选择要签出的提交,或将其合并到您的历史记录中
CharlesB 2013年

1
它仍然使用git fetch下载大量数据(430mb)。所需的提交只有几kbs。真的没有特殊命令可以执行此操作吗?如果我想删除“ git fetched”仓库,该怎么办?它存储在哪里?
Varun Chitre

9
现在这已经过时了。我们既可以执行浅表克隆,又可以获取单个提交。现在,允许浅层克隆正常推入和提取,而无需了解项目的完整历史记录,因此,不再没有祖先就不能单独提交就不再正确。您说的是在初始克隆之后进行取回的说法是正确的,但我们还有更便宜的选择。
西奥多·默多克

6
最后一条命令(使用SHA1提交)对我不起作用。该命令会静默执行“某些操作”一段时间,然后退出,没有任何消息或明显的副作用。
HRJ

1
@HRJ是的,在使用Git的Ubuntu 16.04上,我也遇到了这种情况2.7.4-0ubuntu1.3。但是,在2.16.2-0ppa1~ubuntu16.04.1git-core PPA中使用时,此操作应正常进行。听起来像个已修复的错误。不能通过快速搜索找到对此的引用。如果有人可以帮我指点一下,我很乐意将此修补程序向后移植。
gertvdijk

62

我在git repo上做了一个拉:

git pull --rebase <repo> <branch>

允许git提取分支的所有代码,然后我进行了一次重置以使我感兴趣的提交。

git reset --hard <commit-hash>

希望这可以帮助。


1
没有任何答案有效,尽管这个答案挽救了我的生命!谢谢一群!
michaeltintiuc

重置-克隆后为我辛苦了!谢谢。
Nick-ACNB 2015年

3
-1:“破坏性”命令(如)git reset --hard在通用解决方案中共享时,可能导致人们陷入丢失数据的陷阱(或者在这种情况下:处于无法收回数据的状态)。
yaauie

54

您只需使用以下命令即可获取远程回购的一次提交

git fetch <repo> <commit>

哪里,

  • <repo>可以是远程仓库名称(例如origin),甚至可以是远程仓库URL(例如https://git.foo.com/myrepo.git
  • <commit> 可以是SHA1提交

例如

git fetch https://git.foo.com/myrepo.git 0a071603d87e0b89738599c160583a19a6d95545

在获取提交(和丢失的祖先)之后,您可以使用

git checkout FETCH_HEAD

请注意,这将使您进入“分离头”状态。


10
当我尝试fetch像您在那里那样执行特定的修订时,git失败,错误代码为1,并且没有输出。这在过去的版本中曾经有用吗?(我是v2.0.2。)
杰克·奥康纳

2
编辑:如果我已经在本地进行了提交,它确实可以工作,就像我已经完成了提交一样fetch,尽管在那种情况下我不确定用途是什么。
Jack O'Connor 2014年

2
确实,在git 2.0.2中,这似乎对我也不再起作用。:(
流程

2
git checkout FETCH_HEAD帮助。
lzl124631x 2015年

1
此方法不适用于浅抓取(例如--depth=1)!
kingmakerking

16

您可以使用以下命令简单地获取远程仓库:

git fetch <repo>

哪里,

  • <repo>可以是远程仓库名称(例如origin),甚至可以是远程仓库URL(例如https://git.foo.com/myrepo.git

例如:

git fetch https://git.foo.com/myrepo.git 

在获取存储库之后,您可以合并所需的提交(由于问题是关于检索一个提交,因此合并可以使用cherry-pick来选择一个提交):

git merge <commit>
  • <commit> 可以是SHA1提交

例如:

git cherry-pick 0a071603d87e0b89738599c160583a19a6d95545

要么

git merge 0a071603d87e0b89738599c160583a19a6d95545

如果是要合并的最新提交,则还可以使用FETCH_HEAD变量:

git cherry-pick (or merge) FETCH_HEAD

这需要在机器上设置Git帐户。它在测试帐户下不起作用。在测试帐户下,您是否有可以使用的功能?
jww

你是什​​么意思 ?你不能做git fetch吗?
塞尔吉奥

嗯,这样的命令将是 git config set uploadpack.allowReachableSHA1InWant
亚历山大·米尔斯

2

这最有效:

git fetch origin specific_commit
git checkout -b temp FETCH_HEAD

无论您想要什么,都可以命名为“ temp” ...尽管这个分支可能是孤立的


显然不支持1.8.x之类的旧git版本
-sorin

1

最后,我找到了一种使用git cherry-pick克隆特定提交的方法。假设您在本地没有任何存储库,并且要从远程提取特定的提交,

1)在本地和git init中创建空的存储库

2)git remote添加来源存储库URL

3)git fetch origin [除非您合并,否则不会将您的文件移动到本地工作空间]

4)git cherry-pick输入您需要的长期提交哈希

完成。这样,您将只在本地拥有该特定提交的文件。

输入长提交哈希:

您可以使用-> git log --pretty = oneline来获得它



0

如果请求的提交在远程仓库的拉取请求中,则可以通过其ID获取它:

# Add the remote repo path, let's call it 'upstream':
git remote add upstream https://github.com/repo/project.git

# checkout the pull ID, for example ID '60':
git fetch upstream pull/60/head && git checkout FETCH_HEAD
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.