【问题标题】:How to compute the git hash-object of a directory?如何计算目录的 git 哈希对象?
【发布时间】:2011-08-26 01:16:25
【问题描述】:

有人有在目录上使用 git hash-object 的例子吗?它在文件上很容易工作*,但不像我对目录的期望那样工作**

*:  git hash-object c:\somefile.txt
**: git hash-object -t tree c:\somedirectory

当我尝试对目录使用 hash-object 时,它会抱怨“致命:无法打开 'C:\someDirectory': Permission denied”

【问题讨论】:

    标签: git


    【解决方案1】:

    根据您希望这样做的原因,以下 git 命令可能有用:

    git ls-files -s somedirectory | git hash-object --stdin
    

    这给出了一个考虑文件名和内容的单一哈希。

    它是这样工作的。 git ls-files -s .... 将文件列表及其哈希作为文本输出到stdout,然后git hash-object 为其从stdin 接收的数据生成哈希。

    我的用例如下 - 我想知道一个分支目录中的(git 管理的)文件是否与另一个分支中的文件完全匹配(*)。具体用途是比较“目录哈希”决定是否需要重新生成缓存的派生文件。

    默认情况下git ls-files 也会列出子目录中的文件。如果您不希望这样,请尝试查看answers to "how to git ls-file for just one directory level。还有其他各种options to git ls-files,包括指定要包含的文件列表的能力。

    (*) 不包括哈希冲突

    【讨论】:

    • 我认为git ls-tree HEAD somedirectory 就足够了,git 已经对目录进行了哈希处理。无需ls-files 整个目录并使用git hash-object 重新散列它。
    • 如果您需要限制哈希计算中包含的文件,我想我上面的较长解决方案可能会很方便,例如到特定的文件扩展名,或排除子目录。
    • 我想知道,这可以在 git repo 之外工作吗?另见stackoverflow.com/questions/69730660/…
    【解决方案2】:

    git hash-object -t tree 期望文件参数是描述树中条目的文件,而不是文件系统中的目录。我从评论here 了解到,此命令需要一个以二进制格式描述树的文件,并且使用git mktree 来创建树对象会更容易。

    git mktree 理解您从(例如)git ls-tree HEAD 获得的格式输入。在Git Community Book 中有一个使用git hash-objectgit mktree 从头构造树的好例子。

    【讨论】:

    • git book 不再包含mktree 示例,而且 GitHub 上的源代码无法追溯到旧版本中。
    【解决方案3】:

    我不确定是否要获取 git 存储库之外的目录(及其所有内容)的哈希,但对于存储库内的目录,请尝试仅打印哈希:

    git rev-parse HEAD:some/directory
    

    无需使用其他需要额外处理的命令。

    这也可以,但会提供您可能不想要的其他信息(例如文件模式和其他数据):

    git ls-tree HEAD some/directory
    

    【讨论】:

    • 是的! git rev-parse 只打印树 sha,git ls-tree 只打印树体
    • @MilaNautikus 感谢您指出这一区别!
    【解决方案4】:

    我遇到了同样的问题并破解了Python script to hash a complete directory。它的局限性在于它没有考虑.gitignore 文件,但到目前为止它已经达到了它的目的(哈希目录、制作提交对象、store it on the gh-pages branch)。

    【讨论】:

      【解决方案5】:

      我想改进@Fred Foo 的答案,通过提供他的脚本的修改版本,不同之处在于它不会将文件和目录存储在存储库中作为计算其哈希值的副作用:@987654322 @

      不幸的是,我不知道有什么方法可以强制 git mktree 不在存储库中创建树对象,因此代码必须生成树的二进制表示并将其传递给 git hash-object -t tree

      这个脚本也是基于What is the internal format of a git tree object?的回答

      一般的想法是使用git hash-object -- data.txt获取文件的哈希值,并使用git hash-object --stdin -t tree < TreeDescription获取目录,其中:

      • TreeDescription 是"mode name\0hash" 的串联
      • mode"100644" 用于文件,"40000" 用于目录(注意目录中缺少前导零)
      • modename 用一个空格隔开,
      • namehash 由单个字节分隔 \0
      • hash 是对象哈希的 20 字节长的二进制表示
      • 条目按name 排序,这似乎不是创建树对象完全必要的,但有助于通过比较它们的哈希值来确定两个目录是否等效 - 不幸的是,我不知道这里应该使用哪种排序算法(在特别是:在非ASCII字符的情况下怎么办)

      另请注意,这种二进制格式与树对象在存储库中的存储方式略有不同,因为它缺少 "tree SIZE\0" 标头。

      显然,您必须从最深的文件开始计算这种自下而上的方法,因为在计算父项的哈希值之前,您需要所有子项的哈希值。

      【讨论】:

        【解决方案6】:

        经过长时间的搜索,我找到了以下命令:

        git write-tree

        来源: http://git-scm.com/docs/git-write-tree

        我用它来恢复丢失的目录:

        git write-tree path/to/missing/folder

        我丢失的树对象被创建了。从这里您可以继续使用:

        git hash-object -w path/to/missing/folder/file.txt

        如中所述: https://git.wiki.kernel.org/index.php/GitFaq#How_to_fix_a_broken_repository.3F

        【讨论】:

          【解决方案7】:

          正如 Mark Longair 所说,mktree 是要走的路。

          我也遇到了同样的问题,我费了很大的力气才能解决它。这就是我所做的:

          git ls-files -s directory_path
          

          这将为您提供目录内容及其哈希值的列表。

          然后您可以在文本编辑器中将此列表转换为 ls-tree 格式,然后

          echo -e "{ls-tree format list}" | git mkdir
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2019-05-31
            • 2011-12-19
            • 1970-01-01
            • 2011-11-05
            • 2010-09-11
            • 2021-12-12
            相关资源
            最近更新 更多