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

在Git中,如何将当前提交哈希写入同一提交中的文件,git,hook,Git,Hook,我正在尝试用Git钩子做一些奇特的事情,但我真的不知道如何做(或者如果可能的话) 我需要做的是:在每一次提交中,我希望获取它的散列,然后用这个散列更新提交中的一个文件 有什么想法吗?这可以通过使用中的过滤器属性来实现。您需要提供插入提交id的smudge命令,以及删除提交id的clean命令,以便插入的文件不会因为提交id而更改 因此,提交id永远不会存储在文件的blob中;它只是在你的工作副本中展开的。(实际上,将提交id插入blob将成为一项无限递归任务。☺) 克隆此树的任何人都需要为自己设

我正在尝试用Git钩子做一些奇特的事情,但我真的不知道如何做(或者如果可能的话)

我需要做的是:在每一次提交中,我希望获取它的散列,然后用这个散列更新提交中的一个文件


有什么想法吗?

这可以通过使用中的
过滤器
属性来实现。您需要提供插入提交id的
smudge
命令,以及删除提交id的
clean
命令,以便插入的文件不会因为提交id而更改


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

我认为您实际上不想这样做,因为当提交中的文件发生更改时,提交的哈希也会发生更改。

我建议您做一些类似于您所想的事情:将SHA1放在未跟踪的文件中,该文件是t的一部分构建/安装/部署过程。这显然很简单(
git rev parse HEAD>filename
或者可能
git descripe[--tags]>filename
),而且它避免了任何疯狂的操作,比如最终得到一个与git跟踪的文件不同的文件


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

不可能写入当前提交散列:如果您设法预先计算未来的提交散列-它将在您修改任何文件后立即更改

但是,有三种选择:

  • 使用脚本增加“提交id”并将其包含在某个位置。丑
  • .git忽略要将哈希存储到的文件。不是很方便
  • pre-commit
    中,存储上一次提交哈希值(:)在99.99%的情况下,您不会修改/插入提交,因此,这将起作用。在最坏的情况下,您仍然可以识别源版本
  • 我正在编写一个钩子脚本,将在“完成后”将其发布到这里,但仍然——比《杜克核武器永远》发布的时间更早:))

    更新:为
    .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\u commit,branch
    对转换为真正的提交散列:)

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

    有人指给我看ident上的“mangittributes”部分,它有以下内容:

    识别

    当为路径设置属性ident时,git将blob对象中的$Id$替换为$Id:,后跟 40个字符的十六进制blob对象名称,签出时后跟美元符号$。任何 签入时,工作树文件中以$Id开头,以$Id结尾的文件将替换为$Id$


    仔细想想,这也是CVS、Subversion等所做的。如果查看存储库,您将看到存储库中的文件始终包含,例如,$Id$。它从来没有包含过它的扩展。只有在签出时,文本才会被展开。

    让我来探讨一下为什么使用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树的消息执行sha1校验和,这是所有文件及其sha1校验和的列表

    因此,commit sha1校验和取决于树sha1校验和,树sha1校验和直接取决于文件sha1校验和,文件sha1校验和完成循环并取决于commit sha1。因此,对于我自己可用的技术,你有一个循环问题


    使用,可以通过蛮力将文件的校验和写入文件本身;但是,我不知道有哪项工作可以用sha1完成这项任务。这不是不可能的,但以我们目前的理解来说几乎是不可能的(但谁知道也许几年后这将是微不足道的)。但是,由于必须将(树)校验和(blob)校验和的(提交)校验和写入文件中,因此使用暴力更难做到这一点。

    请跳出提交框

    将其弹出到文件挂钩/签出后

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

    该版本将在您使用它的任何地方都可用。

    基本上我有一个web应用程序,我想将该应用程序的已安装版本与该版本关联的确切提交相关联。我最初的想法是用提交散列更新一种about.html文件。但是在研究git的对象模型之后,我意识到这是不可能的=/这是一个非常实际的问题。我也碰到了!至于我,我希望我的程序在日志中写一条这样的消息:“myprog启动,v.56c6bb2”。这样,如果有人提出一个bug并向我发送日志文件,我就可以确切地知道我的程序运行的是什么版本。@Jefromi,实际的用例实际上非常常见,而且对初学者来说非常容易。将真实版本以某种方式“烙印”到基线文件中是一项基本需求,但为什么这会是一个错误的想法还很不明显,例如,因为这几乎是错误的