215

有什么方法可以从远程 Git 存储库中只检索一个特定的提交而不在我的 PC 上克隆它?远程仓库的结构和我的完全一样,因此不会有任何冲突,但我不知道怎么做,我不想克隆那个巨大的仓库。

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

4

10 回答 10

120

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

请参阅Fredrik Medley ( )的提交 68ee628,2015年5 月 21 日。(由Junio C Hamano 合并 -- --提交 a9d3493中,2015 年 6 月 1 日)moroten
gitster

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

uploadpack.allowReachableSHA1InWant

允许upload-pack接受请求可从任何参考提示访问的对象的获取请求。但是,请注意,计算对象可达性的计算成本很高。
默认为false.

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

git fetch --depth=1 ../testrepo/.git <full-length SHA1>

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

git cat-file commit <full-length SHA1>

" git upload-pack" that services " git fetch" 可以被告知为不在任何 ref 顶端的提交提供服务,只要它们可以通过uploadpack.allowReachableSHA1InWant 配置变量从 ref 访问。

正如马特评论中指出的那样:

注意 SHA 必须是完整的未缩写的 SHA,否则 Git 会声称它找不到提交


完整的文档是:

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

uploadpack.allowReachableSHA1InWant服务器端设置配置选项后,“ git fetch”可以使用“want”行发出请求,该行命名尚未公布的对象(可能已从带外或从子模块指针获得)。
只有从分支提示可到达的对象,即广告分支和被隐藏的分支的并集transfer.hideRefs,才会被处理。
请注意,必须回溯历史记录以检查可达性会产生相关成本。

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

有用的案例是例如

  • 历史中包含大文件的存储库,
  • 仅获取子模块结帐所需的数据,
  • 在共享 sha1 而不告诉它属于哪个确切分支以及在 Gerrit 中时,如果您考虑的是提交而不是更改编号。
    (Gerrit 案例已经解决,allowTipSHA1InWant因为每个 Gerrit 更改都有一个参考。)

Git 2.6(2015 年第三季度)将改进该模型。
请参阅Jeff King ( )的提交 2bc31d1提交 cc118a6(2015 年 7 月 28 日) 。(由Junio C Hamano 合并 -- --824a0be 提交中,2015 年 8 月 19 日)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 月/12 月)将再次改进:

请参阅提交 948bfa2提交 00b293e(2015 年 11 月 5 日)、提交 78a766a提交 92cab49提交 92cab49提交 92cab49(2015 年 11 月 3 日)、提交 00b293e提交 00b293e (2015年11 月 5日)和提交 92cab49提交92cab49 Lukas Fleischer ( )提交 92cab49(2015 年 11 月 3 日) 。 帮助者:Eric Sunshine ( )(由Jeff King 合并 -- --提交 dbba85e中,2015 年 11 月 20 日)lfos
sunshineco
peff

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

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

hideRefs:添加对匹配完整参考的支持

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

因此,新文档

transfer.hideRefs:

如果名称空间正在使用中,则名称空间前缀会在与transfer.hiderefs模式匹配之前从每个引用中剥离。
例如,如果refs/heads/master在中指定transfer.hideRefs且当前命名空间为foorefs/namespaces/foo/refs/heads/master 则从广告中省略,但refs/heads/masterrefs/namespaces/bar/refs/heads/master作为所谓的“拥有”行进行广告。
为了在剥离之前匹配 refs,^请在 ref 名称前添加一个。如果组合!^!必须首先指定。


R..在评论中提到了 config uploadpack.allowAnySHA1InWant,它允许upload-pack接受一个fetch请求任何对象的请求。(默认为false)。

请参阅David "novalis" Turner ( )的提交 f8edeaa(2016 年 11 月,Git v2.11.1 ) :novalis

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

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

此外,它在分布式系统中很活跃——也许一个服务器发布了一个 ref,但另一台服务器已经强制推送到该 ref,也许这两个 HTTP 请求最终被定向到这些不同的服务器。


使用 Git 2.34(2021 年第四季度),在 ( man ) 的另一侧运行的 " " ( man )git upload-pack处理want - ref 请求时忘记考虑 ref 命名空间。git fetch

请参阅Kim Altintop () 的commit 53a66eccommit 3955140commit bac01c6(2021 年 8 月 13 日(由Junio C Hamano 合并——提交 1ab13eb中,2021 年 9 月 10 日)kim
gitster

docs: 阐明 transfer.hideRefs 和命名空间的交互

签字人:Kim Altintop
审核人:Jonathan Tan

展开文档中关于命名空间的部分transfer.hideRefs,指出 和 之间的细微upload-pack差别receive-pack

3955140(“ upload-pack.c:对待希望引用相对于命名空间”,2021-07-30,Git v2.34.0 -批次 #5中列出的合并)教导拒绝s 隐藏引用,现在提到。 需要澄清的是,隐藏的 ref 的名称在任何时候都不会显示,但它指向的对象 id 可能。upload-packwant-ref

git config现在在其手册页中包含:

在与模式匹配之前引用transfer.hiderefs。为了在剥离之前匹配 refs,^请在 ref 名称前添加一个。如果组合!^!必须首先指定。

git config现在在其手册页中包含:

从广告中省略。如果uploadpack.allowRefInWant设置, upload-packwant-ref refs/heads/master在协议 v2 fetch命令中视为refs/namespaces/foo/refs/heads/master不存在。 receive-pack另一方面,仍然会宣传 ref 指向的对象 id 而不会提及其名称(所谓的“ .have”行)。

于 2015-06-08T05:22:17.167 回答
104

您只克隆一次,因此如果您已经克隆了远程存储库,则从其中提取不会再次下载所有内容。只需指出您要提取的分支,或获取更改并签出您想要的提交。

从新存储库获取带宽非常便宜,因为它只会下载您没有的更改。考虑 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

于 2013-02-14T10:23:16.903 回答
64

您可以简单地获取远程仓库的单个提交

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

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

于 2014-06-06T14:50:35.090 回答
64

我拉动了我的 git repo:

git pull --rebase <repo> <branch>

允许 git 提取分支的所有代码,然后我去重置我感兴趣的提交。

git reset --hard <commit-hash>

希望这可以帮助。

于 2013-12-03T12:43:17.463 回答
21

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

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
于 2015-07-16T17:32:16.637 回答
6

这效果最好:

git fetch origin specific_commit
git checkout -b temp FETCH_HEAD

将“temp”命名为您想要的任何名称......虽然这个分支可能是孤立的

于 2019-05-16T23:15:14.440 回答
1

我认为'git ls-remote'(http://git-scm.com/docs/git-ls-remote)应该做你想做的事。无需强制获取或拉动。

于 2015-01-28T15:42:04.597 回答
1

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

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

2) git remote add origin " url-of-repository "

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

4) git cherry-pick " Enter-long-commit-hash-that-you-need "

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

输入长提交哈希:

你可以使用 -> git log --pretty=oneline

于 2017-01-03T04:19:49.577 回答
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
于 2019-06-16T14:56:11.073 回答
0

在一个项目中,我们遇到了一个问题,因此我们不得不恢复到某个提交。我们使用以下命令成功实现了它:

git reset --hard <commitID>
于 2020-11-12T08:20:43.207 回答