在Git存储库中,如何通过相应的Blob哈希值查找文件?

5

假设我有一个文件,可能已经存在于Git仓库中,并且它可能存在于多个路径下,甚至在同一个提交中。

如何找到所有包含与该文件对应哈希值的blob的提交,并列出每个提交中文件所在的路径名?

是否有一种按哈希查找文件的技术,也可以搜索索引和工作目录?


1
@RiccardoPetraglia,那是错误的:哈希标识Git存储的所有内容,并且它存储三种类型的对象:blob(文件内容)、tree和commit。Commits引用trees和它们的父提交;trees引用其他trees和blobs。所有这些“参考”都通过这些对象的SHA-1名称(那些“哈希”)发生。 - kostix
2
可能是Which commit has this blob?的重复问题。 - kostix
1
你只需要正确地提出问题;-) 在 Git 的用语中,文件的内容称为“blob”,因此您需要搜索“哪个 git 提交包含 blob”。请参阅我链接的已有答案。 - kostix
1
@kostix 我非常支持使用正确的术语,但是文件的内容真的被称为 blob 吗?一个 blob 包括一个头部和文件的内容,如果文件的内容也被称为 blob,那么就会导致递归定义!-) - lionel
不,blob中不含有标头;只有提交才会含有标头。关于术语的详细说明,请参见我针对@RiccardoPetraglia的另一条评论。实际上,原始 内容并不是 blob;要“获取”一个blob,你需要使用 git hash-object -w filename 命令,它 a) 实际上将文件内容转换为一个 blob;b) 将其写入对象存储(如果尚未存在);c) 打印 blob 的 SHA-1 名称。然而,唯一的区别在于,blob 只包含数据,通常被压缩,并且没有与之相关联的元数据。 - kostix
显示剩余7条评论
2个回答

2

好的,进一步解释被接受的答案

如果要找到所有包含路径名的提交,那么被接受的答案中的脚本唯一没有为您完成的就是打印路径名。但不用担心,这很容易修改。

如果您进入附近的Git存储库并运行git ls-tree -r HEAD,您会看到该命令转储由命名提交(在我们的情况下为HEAD)引用的整个树层次结构,其中包括SHA-1名称和“常规”文件名。答案中的脚本只是使用grep搜索此输出以查找SHA-1名称并忽略其余部分。

因此,我们可以将其修改为:

#!/bin/sh
obj_name="$1"
shift
git log "$@" --pretty=format:'%T %h %s' \
| while read tree commit subject ; do
    git ls-tree -r "$commit" | while read _ _ sha name; do \
      if [ "$sha" == "$obj_name" ]; then
        echo "$sha\t$name"
        break
      fi
    done
  done

现在,它还将打印与目标blob关联的文件名称以及提交名称。


这个例子只给出了基本名称,而没有路径。你现在清楚了吗?你所谓的重复只涵盖了我提出问题的50%。而且只有当你读取一个未被接受的答案来获取提示时,才能搜索索引(虽然不是工作目录,但我承认它缺乏由git管理的搜索所有地方的实际应用)。 - lionel
@lionel,不好意思,但是你怎么定义“basename”呢?我的意思是,由git ls-tree -r <commit>显示的路径名是相对于此提交所在存储库的根目录,这是我认为很自然(实际上也是唯一可能的)的事情。你期望的是什么?或许透过你的期望,问题会更加清晰明了。 - kostix
我的错误:-r 标志确实使 ls-tree 输出路径(不仅是基本名称)。但是,为了找到所有出现的情况,难道您还需要 --full-tree 选项吗? - lionel
你所谓的“被接受的答案”中还缺少一件事,那就是从索引中获取任何实例。 - lionel

1

我猜你可能可以在这里找到答案这里(重复)。

总结:

git rev-list <commit-list> | \
xargs -n1 -iX sh -c "git ls-tree -r X | grep <SHA1> && echo X"

您可以使用--all代替<commit-list>来查看所有提交。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接