【问题标题】:Is it possible to download a single file from specified commits from remote?是否可以从远程指定的提交中下载单个文件?
【发布时间】:2020-12-18 03:58:32
【问题描述】:

我正在尝试从远程的特定提交中签出特定文件。

请注意,提交不在本地 repo 中,只是远程 repo 的一部分。

  1. 我不想从 GitHub/bitbucket 界面下载原始文件。因为我的遥控器不在类似的平台上。

  2. 我不想在 git fetch 之后执行 git checkout,因为执行 git fetch 会下载一堆我不想要的其他项目。我只对来自特定提交的特定文件感兴趣。

【问题讨论】:

  • 既然你使用了“checkout”这个词,每个人都认为你想在这个单个文件上使用正确的 git 进程。请尝试使用正确的词语,因为您真正想要做的只是从远程存储库下载文件。

标签: git


【解决方案1】:

编辑:来自 cmets:

我需要从分布在十几个分支的数百个提交中检查同一个文件。

为此,您将需要其他仓库管理员的合作。

在 Git 中,历史是通过给它一个引用名(分支、标签等)和通过共享文件系统或托管服务器的某种访问来发布的。

不值得给出自己的引用名的东西要么是已发布历史的一部分(确实有自己的引用名),要么不是。

如果是这样,Git 将确保您获得一个完整的、内部一致的包,让您及时了解您要求的已发布历史记录。 Git 专注于使特定操作尽可能快速和高效。

如果不是,那么托管 repo 没有发布它,并且 (a) 你通常根本无法获得它,并且 (b) 你通常甚至不知道如何请求它,它的对象 id .

要找到对象的 id,您必须通过历史记录检查快照,...这意味着您必须拥有快照...看到了吗?

Git 不喜欢支付两次间接费用,它被构建为 vcs。您正在尝试像共享文件系统一样使用它。文件系统的构建是为了高效地频繁且重复地为同一个客户端提供单个对象。 dvcs 的构建是为了高效地服务于多个完整的修订,间隔相对较长,每个客户端一次。这是工程权衡的领域:你不可能在这两个方面都非常高效,而且你在其中一个方面做得越好,重新调整工具和做另一件事就越困难。

话虽如此:如果您可以让其他 repo 管理员为您做一些自定义工作,这并不难:

git rev-list --branches --objects -- path/to/file | git pack-objects pack

将打包该文件的所有分支版本的历史记录:引入新版本的提交、显示它们去向的树及其内容,并将其放入名为pack-<hashcode>.{idx,pack} 的两个文件中。将该包放在任何 repo 的 objects/pack 目录中,您就可以:您拥有处理该文件所需的一切。

这样的切片历史相对难以处理,而按需填充缺失位的开销正是 Git 旨在避免的,但使用你所拥有的东西,你可以使用例如git verify-pack -v 显示包的确切内容,git cat-file -p 打印单个对象。该包中的提交是引入新版本的提交,您可以通过将 :path/to/file 附加到其提交 ID 来引用其中一个文件。

因此,当您运行验证包以查看您所拥有的内容时,您会得到关于其内容和结构的太多信息的转储。为了使它对您的目的有用,您可以只刮掉提交 ID,并按日期顺序列出它们,使用

# this is the pack I made for testing 
git verify-pack -v .git/objects/pack/pack-8d3bb7bca6a4cdc086778ad55c79f45e672ae7e5.idx \
| awk '$2=="commit"{print $1}' \
| git rev-list --stdin --date-order --no-walk

sub in log for rev-list 查看日志消息,或者您可以显示您获取的 blob,例如git show <commit-hash>:path/to/file。要按时间顺序显示斑点,您可以

git     git verify-pack -v .git/objects/pack/pack-8d3bb7bca6a4cdc086778ad55c79f45e672ae7e5.idx \
| awk '$2=="commit"{print $1}' \
| git rev-list --stdin --date-order --no-walk --pretty=%h:path/to/file \
| git cat-file --batch

这将以可扫描的形式转储内容。

。 . .实际上,如果一个多合一的历史转储就可以了,并且您只需要匹配的内容和顺序,而不是生成的提交 ID,Git's fast-export 可能会为您完成所有工作,有管理员做的

git fast-export --branches -- path/to/file | zstd >my-stuff.zst

它甚至可能比包文件更紧凑(因为它不必保留 id)并将其发送给您。

【讨论】:

  • 这很有趣;我设法得到文件的 .{idx,pack} 。我将 .{idx,pack} 移至对象/包。我不清楚你建议的下一件事是什么。我的意思是我如何利用这个包信息。
  • GIT中验证包-v包-ffd199abe9c8db57dff06404dbad16a91458dd11.pack c4e6eabc55304837476d5d4cb02aa79a4ed9082b提交259 179 12 222fe027d32ac6357000d9c541506a65d43adb06提交259 180 191非增量:2个对象PACK-ffd199abe9c8db57dff06404dbad16a91458dd11.pack:确定 span>
  • 好吧,我承认我把那部分省略了,因为我怀疑是否会引起兴趣,我现在就添加它。
  • 。 . .等等,这是您的验证包输出的完整转储吗?两个对象?我看不出如何从我给出的命令中得到那种结果,. ... gaak.. 我在我给出的命令中留下了一个 arg,sorry。将 --objects 添加到 rev-list 中添加 pack-objects,现在编辑它。
【解决方案2】:

我不想在 git checkout 之后执行 git fetch,因为执行 git fetch 会下载一堆我不想要的其他项目。

你需要做git fetch。这是让远程服务器向您发送内容的方式。但是,您可以使用类似

git fetch --force --depth 1 origin $COMMIT_SHA:tmp

将从远程 origin 获取 just 提交 $COMMIT_SHA(以及完成它所需的所有文件 - AFAIK,你无法避免),并将其命名为 @987654325 @。如果名为 tmp 的分支已经存在,--force 将防止失败(当然,可以重复使用,但要小心使用)。

然后你可以git cat-file blob tmp:somepathgit checkout tmp -- somepath 或任何你想访问的文件内容。

如果您在完成后git branch -D tmp ; git gc,则应该几乎没有积累的垃圾。

【讨论】:

    【解决方案3】:

    如果服务器端配置不在您的控制之下,这是可能的,但可能不起作用。

    Git 有一个内置命令,可以在特定提交中检索文件。

    git archive --remote=<url_to_the_repo> <commit> --format=tar <path> | tar xvf -
    

    一些托管服务不允许git archive --remote。如果是这样,则此命令根本无法工作。

    一些托管服务禁止获取未公布的对象。如果是这样,对于&lt;commit&gt;,只允许有效的 ref 而不是 sha1 值。使用 ref,只能获取提示提交的文件。对于没有被任何 ref 引用的提交,不可能以这种方式检索它。

    另一种可能但不实用的方法是为您感兴趣的文件的所有 blob 对象创建标签,然后获取标签以检索其内容。

    比较实用的方法之一是获取所有必要的数据,并使用git show &lt;commit&gt;:&lt;path&gt; 读取内容。这需要时间和磁盘空间,但它非常可靠。并尽可能避免git checkout,以节省一点时间和空间。

    【讨论】:

      【解决方案4】:

      如果你碰巧知道包含这个提交的特定远程分支,你可以单独获取这个分支:

      git fetch origin some_branch
      

      然后,在您想要的确切提交处签出文件:

      git checkout abc123 -- path/to/your/file.ext
      

      【讨论】:

      • 不,我不想获取整个分支。我有来自多个分支的提交,我只想依赖提交。
      • ...您可以在完成后随时删除分支。
      • :) 抱歉,我需要从分布在十几个分支的数百个提交中检查同一个文件。在我的情况下,维护提交 ID 和分支名称的列表是不切实际的。同样的提交也可能是几个分支的一部分。我只需要依赖提交 ID。
      【解决方案5】:

      很遗憾,您无法按照您在问题和 cmets 中描述的方式进行操作。

      git 不能像subversion 或其他源代码管理系统那样在文件级别工作。 git 在快照级别工作。 Every commit is like a snapshot of your code(这是 git 工作原理的一个非常简单的模型,它的底层更复杂)。因此,您必须获取所需文件的唯一方法是

      • 首先将快照从服务器获取到您的本地计算机 (git-fetch)
      • 其次,获得快照后,您可以从快照中提取文件 (git-checkout)。

      The answer from @hobbs to this same question 告诉你怎么做。

      【讨论】:

      • "另外,您不能使用 git-fetch 命令下载单个提交。"当然可以。这不是这个答案中唯一错误的地方。
      • 好吧,我不认为这是错误的:stackoverflow.com/questions/3697707/… 我已经更新了答案以包含链接,如果你能指出其他错误的地方,我会更多很乐意纠正它们。
      • 您可以使用--depth=1 获取单个提交。如果远程已配置,您可以获取单个 arbitrary 提交。您可以使用例如获取单个分支git fetch origin master:refs/remotes/origin/master,您不需要编辑文件(完成后再次编辑)。
      • 听起来 OP 甚至不想从各种提交中下载提交,只是单个文件。 Git 不是为了轻松(或根本)做到这一点而构建的。
      • @jthill 非常感谢您的 cmets。我正在调查您的答案以及您提到的有关正确配置遥控器的内容。我想说,使用命令 git-fetch 您可以使用 --depth=1 获取单个任意提交(再次感谢)
      猜你喜欢
      • 2016-02-24
      • 2014-08-23
      • 2023-03-29
      • 1970-01-01
      • 2017-04-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多