简体   繁体   English

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

[英]Retrieve specific commit from a remote Git repository

Is there any way to retrieve only one specific commit from a remote Git repo without cloning it on my PC?有什么方法可以只从远程 Git 存储库检索一个特定的提交,而无需在我的 PC 上克隆它? The structure of remote repo is absolutely same as that of mine and hence there won't be any conflicts but I have no idea how to do this and I don't want to clone that huge repository.远程仓库的结构与我的完全相同,因此不会有任何冲突,但我不知道该怎么做,我不想克隆那个巨大的仓库。

I am new to git, is there any way?我是git的新手,请问有什么办法吗?

Starting with Git version 2.5+ (Q2 2015), fetching a single commit (without cloning the full repo) is actually possible.从 Git 版本 2.5+(2015 年第二季度)开始,实际上可以获取单个提交(无需克隆完整的 repo)。

See commit 68ee628 by Fredrik Medley ( moroten ) , 21 May 2015.请参阅Fredrik Medley ( moroten )提交 68ee628,2015年 5 月 21 日。
(Merged by Junio C Hamano -- gitster -- in commit a9d3493 , 01 Jun 2015) (由Junio C Hamano -- gitster --提交 a9d3493中合并,2015 年 6 月 1 日)

You now have a new config (on the server side)您现在有一个新配置(在服务器端)

uploadpack.allowReachableSHA1InWant

Allow upload-pack to accept a fetch request that asks for an object that is reachable from any ref tip.允许upload-pack接受一个 fetch 请求,该请求要求一个可从任何 ref 提示访问的对象。 However, note that calculating object reachability is computationally expensive.但是,请注意,计算对象可达性的计算成本很高。
Defaults to false .默认为false

If you combine that server-side configuration with a shallow clone ( git fetch --depth=1 ), you can ask for a single commit (see t/t5516-fetch-push.sh :如果将该服务器端配置与浅克隆( git fetch --depth=1 )结合使用,则可以请求一次提交(请参阅t/t5516-fetch-push.sh

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

You can use the git cat-file command to see that the commit has been fetched:您可以使用git cat-file命令查看提交是否已获取:

git cat-file commit <full-length SHA1>

" git upload-pack " that serves " git fetch " can be told to serve commits that are not at the tip of any ref, as long as they are reachable from a ref, with uploadpack.allowReachableSHA1InWant configuration variable.服务于“ git fetch ”的“ git upload-pack ”可以被告知提供不在任何 ref 顶端的提交,只要它们可以从 ref 访问,并且带有uploadpack.allowReachableSHA1InWant配置变量。

As noted by matt in the comments :正如马特评论中指出的那样:

Note that SHA must be the full unabbreviated SHA, otherwise Git will claim it couldn't find the commit注意 SHA 必须是完整的未缩写的 SHA,否则 Git 会声称它找不到提交


The full documentation is:完整的文档是:

upload-pack : optionally allow fetching reachable sha1 upload-pack :可选地允许获取可访问的 sha1

With uploadpack.allowReachableSHA1InWant configuration option set on the server side, " git fetch " can make a request with a "want" line that names an object that has not been advertised (likely to have been obtained out of band or from a submodule pointer).通过在服务器端设置uploadpack.allowReachableSHA1InWant配置选项,“ git fetch ”可以使用“want”行发出请求,该行命名尚未公布的对象(可能已从带外或从子模块指针获得) .
Only objects reachable from the branch tips, ie the union of advertised branches and branches hidden by transfer.hideRefs , will be processed.只有从分支提示可到达的对象,即广告分支和被transfer.hideRefs隐藏的分支的并集,才会被处理。
Note that there is an associated cost of having to walk back the history to check the reachability.请注意,必须回溯历史记录以检查可达性会产生相关成本。

This feature can be used when obtaining the content of a certain commit, for which the sha1 is known, without the need of cloning the whole repository, especially if a shallow fetch is used .当获取某个提交的内容时,可以使用此功能,其中 sha1 是已知的,而无需克隆整个存储库,尤其是在使用浅获取的情况下

Useful cases are eg有用的案例是例如

  • repositories containing large files in the history,历史中包含大文件的存储库,
  • fetching only the needed data for a submodule checkout,仅获取子模块结帐所需的数据,
  • when sharing a sha1 without telling which exact branch it belongs to and in Gerrit, if you think in terms of commits instead of change numbers.在共享 sha1 而不告诉它属于哪个确切分支以及在 Gerrit 中时,如果您考虑的是提交而不是更改编号。
    (The Gerrit case has already been solved through allowTipSHA1InWant as every Gerrit change has a ref.) (Gerrit 案例已经通过allowTipSHA1InWant解决,因为每个 Gerrit 更改都有一个参考。)

Git 2.6 (Q3 2015) will improve that model. Git 2.6(2015 年第三季度)将改进该模型。
See commit 2bc31d1 , commit cc118a6 (28 Jul 2015) by Jeff King ( peff ) .请参阅提交 2bc31d1提交 cc118a6 (2015 年 7 月 28 日)由Jeff King ( peff )
(Merged by Junio C Hamano -- gitster -- in commit 824a0be , 19 Aug 2015) (由Junio C Hamano -- gitster --提交 824a0be中合并,2015 年 8 月 19 日)

refs : support negative transfer.hideRefs refs : 支持transfer.hideRefs

If you hide a hierarchy of refs using the transfer.hideRefs config, there is no way to later override that config to "unhide" it.如果您使用transfer.hideRefs配置隐藏参考层次结构,则无法稍后覆盖该配置以“取消隐藏”它。
This patch implements a "negative" hide which causes matches to immediately be marked as unhidden, even if another match would hide it.这个补丁实现了一个“负面”隐藏,这会导致匹配立即被标记为未隐藏,即使另一个匹配会隐藏它。
We take care to apply the matches in reverse-order from how they are fed to us by the config machinery, as that lets our usual "last one wins" config precedence work (and entries in .git/config , for example, will override /etc/gitconfig ).我们注意以与配置机制提供给我们的方式相反的顺序应用匹配,因为这让我们通常的“最后一个获胜”配置优先工作(并且.git/config中的条目,例如,将覆盖/etc/gitconfig )。

So you can now do:所以你现在可以这样做:

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

to hide refs/secret in all repos, except for one public bit in one specific repo.隐藏所有 repos 中的refs/secret ,除了一个特定 repo 中的一个公共位。


Git 2.7 (Nov/Dec 2015) will improve again: Git 2.7(2015 年 11 月/12 月)将再次改进:

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

config.txt : document the semantics of hideRefs with namespaces config.txt :用命名空间记录hideRefs的语义

Right now, there is no clear definition of how transfer.hideRefs should behave when a namespace is set.目前,对于设置命名空间时transfer.hideRefs的行为方式还没有明确的定义。
Explain that hideRefs prefixes match stripped names in that case.说明在这种情况下hideRefs前缀匹配剥离的名称。 This is how hideRefs patterns are currently handled in receive-pack.这就是当前在接收包中处理hideRefs模式的方式。

hideRefs: add support for matching full refs hideRefs:添加对匹配完整参考的支持

In addition to matching stripped refs, one can now add hideRefs patterns that the full (unstripped) ref is matched against.除了匹配剥离的 ref 之外,现在还可以添加与完整(未剥离的)ref 匹配的hideRefs模式。
To distinguish between stripped and full matches, those new patterns must be prefixed with a circumflex ( ^ ).为了区分剥离匹配和完整匹配,这些新模式必须以抑扬符 ( ^ ) 为前缀。

Hence the new documentation :因此, 新文档

transfer.hideRefs:

If a namespace is in use, the namespace prefix is stripped from each reference before it is matched against transfer.hiderefs patterns.如果名称空间正在使用中,则名称空间前缀会在与transfer.hiderefs模式匹配之前从每个引用中剥离。
For example, if refs/heads/master is specified in transfer.hideRefs and the current namespace is foo , then refs/namespaces/foo/refs/heads/master is omitted from the advertisements but refs/heads/master and refs/namespaces/bar/refs/heads/master are still advertised as so-called "have" lines.例如,如果在transfer.hideRefs中指定了refs/heads/master并且当前命名空间是foo ,那么refs/namespaces/foo/refs/heads/master会从广告中省略,但refs/heads/masterrefs/namespaces/bar/refs/heads/master仍然被宣传为所谓的“拥有”行。
In order to match refs before stripping, add a ^ in front of the ref name.为了在剥离之前匹配 refs,请在 ref 名称前添加一个^ If you combine !如果结合! and ^ , !^ , ! must be specified first.必须先指定。


R.. mentions in the comments the config uploadpack.allowAnySHA1InWant , which allows upload-pack to accept a fetch request that asks for any object at all. R.. 在评论中提到了配置uploadpack.allowAnySHA1InWant ,它允许upload-pack接受请求任何对象的fetch请求。 (Defaults to false ). (默认为false )。

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

upload-pack : optionally allow fetching any sha1 upload-pack :可选地允许获取任何 sha1

It seems a little silly to do a reachabilty check in the case where we trust the user to access absolutely everything in the repository.在我们相信用户绝对可以访问存储库中的所有内容的情况下,进行可访问性检查似乎有点愚蠢。

Also, it's racy in a distributed system -- perhaps one server advertises a ref, but another has since had a force-push to that ref, and perhaps the two HTTP requests end up directed to these different servers.此外,它在分布式系统中很活跃——也许一个服务器发布了一个 ref,但另一台服务器已经强制推送到该 ref,也许这两个 HTTP 请求最终被定向到这些不同的服务器。


With Git 2.34 (Q4 2021), " git upload-pack " ( man ) which runs on the other side of git fetch ( man ) forgot to take the ref namespaces into account when handling want-ref requests.在 Git 2.34(2021 年第四季度)中,在git fetch man的另一端运行的“ git upload-packman在处理 want-ref 请求时忘记考虑 ref 命名空间。

See commit 53a66ec , commit 3955140 , commit bac01c6 (13 Aug 2021) by Kim Altintop ( kim ) .请参阅Kim Altintop ( kim )commit 53a66eccommit 3955140commit bac01c6 (2021 年 8 月 13 日)。
(Merged by Junio C Hamano -- gitster -- in commit 1ab13eb , 10 Sep 2021) (由Junio C Hamano -- gitster --提交 1ab13eb中合并,2021 年 9 月 10 日)

docs : clarify the interaction of transfer.hideRefs and namespaces docs :阐明 transfer.hideRefs 和命名空间的交互

Signed-off-by: Kim Altintop签字人:Kim Altintop
Reviewed-by: Jonathan Tan审核人:Jonathan Tan

Expand the section about namespaces in the documentation of transfer.hideRefs to point out the subtle differences between upload-pack and receive-pack .展开transfer.hideRefs文档中关于命名空间的部分,指出upload-packreceive-pack之间的细微差别。

3955140 (" upload-pack.c : treat want-ref relative to namespace", 2021-07-30, Git v2.34.0 -- merge listed in batch #5 ) taught upload-pack to reject want-ref s for hidden refs, which is now mentioned. 3955140 (“ upload-pack.c : 相对于命名空间处理 want-ref”,2021-07-30,Git v2.34.0 - 批次 #5中列出的合并)教导upload-pack拒绝隐藏引用的want-ref ,现在提到。
It is clarified that at no point the name of a hidden ref is revealed, but the object id it points to may.需要澄清的是,隐藏的 ref 的名称在任何时候都不会显示,但它指向的对象 id 可能。

git config now includes in its man page : git config现在包含在其手册页中:

reference before it is matched against transfer.hiderefs patterns.在与transfer.hiderefs模式匹配之前引用。 In order to match refs before stripping, add a ^ in front of the ref name.为了在剥离之前匹配 refs,请在 ref 名称前添加一个^ If you combine !如果结合! and ^ , !^ , ! must be specified first.必须先指定。

git config now includes in its man page : git config现在包含在其手册页中:

is omitted from the advertisements.从广告中省略。 If uploadpack.allowRefInWant is set, upload-pack will treat want-ref refs/heads/master in a protocol v2 fetch command as if refs/namespaces/foo/refs/heads/master did not exist.如果设置uploadpack.allowRefInWant ,则upload-pack将在protocol v2 fetch命令中处理want-ref refs/heads/master ,就好像refs/namespaces/foo/refs/heads/master不存在一样。 receive-pack , on the other hand, will still advertise the object id the ref is pointing to without mentioning its name (a so-called " .hav e" line).另一方面, receive-pack仍然会宣传 ref 指向的对象 id 而不会提及其名称(所谓的“ .hav e”行)。

You only clone once, so if you already have a clone of the remote repository, pulling from it won't download everything again.您只克隆一次,因此如果您已经克隆了远程存储库,则从其中提取不会再次下载所有内容。 Just indicate what branch you want to pull, or fetch the changes and checkout the commit you want.只需指出您要提取的分支,或获取更改并签出您想要的提交。

Fetching from a new repository is very cheap in bandwidth, as it will only download the changes you don't have.从新存储库获取带宽非常便宜,因为它只会下载您没有的更改。 Think in terms of Git making the right thing, with minimum load.考虑 Git 以最小的负载做出正确的事情。

Git stores everything in .git folder. Git 将所有内容存储在.git文件夹中。 A commit can't be fetched and stored in isolation, it needs all its ancestors.提交不能单独获取和存储,它需要它的所有祖先。 They are interrelated .它们是相互关联的。


To reduce download size you can however ask git to fetch only objects related to a specific branch or commit:但是,为了减少下载大小,您可以要求 git 仅获取与特定分支或提交相关的对象:

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

This will download only commits contained in remote branch branch (and only the ones that you miss) , and store it in origin/branch .这将仅下载远程分支branch中包含的提交(并且仅下载您错过的提交) ,并将其存储在origin/branch中。 You can then merge or checkout.然后,您可以合并或结帐。

You can also specify only a SHA1 commit:你也可以只指定一个 SHA1 提交:

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

This will download only the commit of the specified SHA-1 96de5297df870 (and its ancestors that you miss), and store it as (non-existing) remote branch origin/foo-commit .这将仅下载指定 SHA-1 96de5297df870(以及您错过的其祖先)的提交,并将其存储为(不存在的)远程分支origin/foo-commit

You can simply fetch a single commit of a remote repo with您可以简单地获取远程仓库的单个提交

git fetch <repo> <commit-id>

where,在哪里,

  • <repo> can be a remote repo name (eg origin ) or even a remote repo URL (eg https://git.foo.com/myrepo.git ) <repo>可以是远程仓库名称(例如origin )甚至是远程仓库 URL(例如https://git.foo.com/myrepo.git
  • <commit-id> is the commit's ID <commit-id>是提交的 ID

for example例如

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

after you fetched the commit (and the missing ancestors) you can simply checkout it with在您获取提交(以及丢失的祖先)之后,您可以简单地检查它

git checkout FETCH_HEAD

Note that this will bring you in the "detached head" state.请注意,这将使您进入“分离头”状态。

I did a pull on my git repo:我拉动了我的 git repo:

git pull --rebase <repo> <branch>

Allowing git to pull in all the code for the branch and then I went to do a reset over to the commit that interested me.允许 git 提取分支的所有代码,然后我去重置我感兴趣的提交。

git reset --hard <commit-hash>

Hope this helps.希望这可以帮助。

You can simply fetch the remote repo with:您可以简单地使用以下方法获取远程仓库:

git fetch <repo>

where,在哪里,

  • <repo> can be a remote repo name (eg origin ) or even a remote repo URL (eg https://git.foo.com/myrepo.git ) <repo>可以是远程仓库名称(例如origin )甚至是远程仓库 URL(例如https://git.foo.com/myrepo.git

for example:例如:

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

after you fetched the repos you may merge the commits that you want (since the question is about retrieve one commit, instead merge you may use cherry-pick to pick just one commit):在您获取存储库后,您可以合并您想要的提交(因为问题是关于检索一个提交,而不是合并,您可以使用cherry-pick 只选择一个提交):

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

for example:例如:

git cherry-pick 0a071603d87e0b89738599c160583a19a6d95545

or或者

git merge 0a071603d87e0b89738599c160583a19a6d95545

if is the latest commit that you want to merge, you also may use FETCH_HEAD variable :如果是您要合并的最新提交,您也可以使用 FETCH_HEAD 变量:

git cherry-pick (or merge) FETCH_HEAD

This works best:这效果最好:

git fetch origin specific_commit
git checkout -b temp FETCH_HEAD

name "temp" whatever you want...this branch might be orphaned though将“temp”命名为您想要的任何名称......虽然这个分支可能是孤立的

I think 'git ls-remote' ( http://git-scm.com/docs/git-ls-remote ) should do what you want.我认为'git ls-remote'( http://git-scm.com/docs/git-ls-remote )应该做你想做的事。 Without force fetch or pull.无需强制获取或拉动。

Finally i found a way to clone specific commit using git cherry-pick .最后,我找到了一种使用git cherry-pick克隆特定提交的方法。 Assuming you don't have any repository in local and you are pulling specific commit from remote,假设您在本地没有任何存储库并且您正在从远程提取特定提交,

1) create empty repository in local and git init 1)在本地和git init中创建空存储库

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

3) git fetch origin [this will not move your files to your local workspace unless you merge] 3) git fetch origin [这不会将您的文件移动到您的本地工作区,除非您合并]

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

Done.This way, you will only have the files from that specific commit in your local.完成。这样,您将只在本地拥有来自该特定提交的文件。

Enter-long-commit-hash:输入长提交哈希:

You can get this using -> git log --pretty=oneline你可以使用 -> git log --pretty=oneline

If the requested commit is in the pull requests of the remote repo, you can get it by its ID:如果请求的提交在远程仓库的拉取请求中,您可以通过其 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

In a project we had a problem so that we had to revert back to a certain commit.在一个项目中,我们遇到了一个问题,因此我们不得不恢复到某个提交。 We made it with the following command successfully:我们使用以下命令成功实现了它:

git reset --hard <commitID>
# make sure you fetch from the origin first
$ git fetch origin

# view code at COMMIT_ID (abc123)
$ git checkout abc123

# bring only COMMIT_ID (abc123)
# to your branch
# assuming your branch is master
$ git checkout master
$ git cherry-pick abc123

# bring all changes up to 
# COMMIT_ID (abc123) to your branch
# assuming your branch is master
$ git checkout master
$ git merge abc123

reference - https://unfuddle.com/stack/tips-tricks/git-pull-specific-commit/参考 - https://unfuddle.com/stack/tips-tricks/git-pull-specific-commit/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM