在Git中,如何将当前提交哈希写入同一提交中的文件

时间:2010-08-09 18:15:50

标签: git hook

我试图用Git钩子做一些奇特的东西,但我真的不知道该怎么做(或者如果可能的话)。

我需要做的是:在每个提交中,我想要获取其哈希值,然后使用此哈希值更新提交中的文件。

有什么想法吗?

7 个答案:

答案 0 :(得分:74)

我建议您做一些类似于您的想法:将SHA1放在未跟踪文件中,该文件是作为构建/安装/部署过程的一部分生成的。这显然很容易做到(git rev-parse HEAD > filename或者git describe [--tags] > filename),它避免做任何疯狂的事情,比如结束与git跟踪的文件不同的文件。

您的代码可以在需要版本号时引用此文件,或者构建过程可以将信息合并到最终产品中。后者实际上是git本身如何获得其版本号 - 构建过程从repo中获取版本号,然后将其构建到可执行文件中。

答案 1 :(得分:12)

有人向我指出了关于ident的“man gitattributes”部分,其中包含:

IDENT

  

当为路径设置属性ident时,git用$ Id:替换blob对象中的$ Id $,然后是   40个字符的十六进制blob对象名称,结账后跟一个美元符号$。任何字节序列   以$ Id开头:在worktree文件中以$结尾,并在办理登机手续时以$ Id $替换。

如果你考虑一下,这就是CVS,Subversion等也是如此。如果查看存储库,您将看到存储库中的文件总是包含,例如$ Id $。它永远不会包含它的扩展。只有在结账时才会扩展文字。

答案 2 :(得分:10)

编写当前提交哈希值是不可能的:如果您设法预先计算未来的提交哈希值 - 它会在您修改任何文件后立即更改。

但是,有三种选择:

  1. 使用脚本递增“提交ID”并将其包含在某处。丑
  2. .gitignore您要将哈希存储到的文件。不是很方便
  3. pre-commit中,存储以前的提交哈希 :)您不会在99.99%的情况下修改/插入提交,因此,这将有效。在最糟糕的情况下,您仍然可以识别源修订版。
  4. 我正在制作一个钩子脚本,将它发布在'完成后',但仍然 - 比Duke Nukem Forever早发布:))

    UPD .git/hooks/pre-commit的代码:

    #!/usr/bin/env bash
    set -e
    
    #=== 'prev-commit' solution by o_O Tync
    #commit_hash=$(git rev-parse --verify HEAD)
    commit=$(git log -1 --pretty="%H%n%ci") # hash \n date
    commit_hash=$(echo "$commit" | head -1)
    commit_date=$(echo "$commit" | head -2 | tail -1) # 2010-12-28 05:16:23 +0300
    
    branch_name=$(git symbolic-ref -q HEAD) # http://stackoverflow.com/questions/1593051/#1593487
    branch_name=${branch_name##refs/heads/}
    branch_name=${branch_name:-HEAD} # 'HEAD' indicates detached HEAD situation
    
    # Write it
    echo -e "prev_commit='$commit_hash'\ndate='$commit_date'\nbranch='$branch'\n" > gitcommit.py
    

    现在我们唯一需要的是一个将prev_commit,branch对转换为实际提交哈希的工具:)

    我不知道这种方法是否可以区分合并提交。很快就会检查出来

答案 3 :(得分:9)

这可以通过使用gitattributes中的filter属性来实现。您需要提供一个插入提交ID的smudge命令和一个删除它的clean命令,这样它插入的文件不会因为提交ID而改变。 / p>

因此,commit id永远不会存储在文件的blob中;它只是扩展了你的工作副本。 (实际上将提交id插入blob将成为一个无限递归的任务。)任何克隆此树的人都需要为自己设置属性。

答案 4 :(得分:3)

我认为你真的不想这样做,因为当提交中的文件发生更改时,提交的哈希值也会发生变化。

答案 5 :(得分:3)

在提交框之外思考!

将其弹出到文件hooks / post-checkout

#!/bin/sh
git describe --all --long > config/git-commit-version.txt

该版本将随处使用。

答案 6 :(得分:0)

让我探讨为什么使用git内部这是一个具有挑战性的问题。您可以通过

获取当前提交的sha1
#!/bin/bash
commit=$(git cat-file commit HEAD) #
sha1=($((printf "commit %s\0" $(echo "$commit" | wc -c); echo "$commit") | sha1sum))
echo ${sha1[0]}

基本上,您对git cat-file commit HEAD返回的消息运行sha1校验和。当您检查此消息时,有两件事会立即跳出来作为问题。一个是树sha1,第二个是提交时间。

现在,通过更改消息并猜测在特定时间进行提交或调度提交所需的时间,可以轻松地处理提交时间。真正的问题是树sha1,您可以从git ls-tree $(git write-tree) | git mktree获得。从本质上讲,您正在对来自ls-tree的消息执行sha1校验和,该消息是所有文件及其sha1校验和的列表。

因此,你的提交sha1校验和取决于你的树sha1校验和,它直接取决于文件sha1校验和,它完成了圆并依赖于提交sha1。因此,对于我自己可以使用的技术存在循环问题。

使用less secure checksums,已经证明可以通过强力将文件的校验和写入文件本身;但是,我不知道用sha1完成任务的任何工作。这并非不可能,但我们目前的理解几乎不可能实现(但谁知道可能在几年之内就会变得微不足道)。但是,由于你必须将(blob)校验和的(树)校验和写入(blob)校验和到文件中,所以仍然更难以暴力破解。