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

hmae6n7t  于 2023-05-27  发布在  Git
关注(0)|答案(8)|浏览(201)

我正在尝试使用Git钩子来做一件很棒的事情,但我真的不知道如何做到这一点(或者是否可能)。
我需要做的是:在每一次提交中,我想获取它的哈希值,然后用这个哈希值更新提交中的一个文件。
有什么想法吗

of1yzvn4

of1yzvn41#

我建议你做一些类似于你所想的事情:将SHA1放置在一个 untracked 文件中,该文件是在构建/安装/部署过程中生成的。这显然很容易做到(git rev-parse HEAD > filename或者git describe [--tags] > filename),而且它避免了做任何疯狂的事情,比如最终得到一个与git跟踪的文件不同的文件。
然后,当您的代码需要版本号时,可以引用此文件,或者构建过程可以将信息合并到最终产品中。后者实际上是git本身获取版本号的方式--构建过程从repo中获取版本号,然后将其构建到可执行文件中。

fykwrbwg

fykwrbwg2#

不可能写出当前的提交哈希:如果你预先计算了未来的提交哈希值-它会在你修改任何文件时改变。
但是,有三种选择:
1.使用脚本递增'commit id'并将其包含在某处。丑
1..gitignore你要存储哈希的文件。不太顺手
1.在pre-commit中,存储previous commit hash:)在99.99%的情况下,你不会修改/插入commits,所以,这将工作。在最坏的情况下,您仍然可以识别源修订版。
我正在写一个钩子脚本,当它完成的时候,我会把它贴在这里,但是仍然比《永远的毁灭公爵》发布的时间要早:))

更新.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对转换为真实的的提交哈希:)
我不知道这种方法是否可以区分合并提交。很快就会去看看

kcrjzv8t

kcrjzv8t3#

这可以通过使用gitattributes中的filter属性来实现。您需要提供一个smudge命令来插入提交id,以及一个clean命令来删除它,这样插入的文件就不会因为提交id而改变。
因此,提交id从不存储在文件的blob中;它只是在你的工作副本中展开。(实际上,将提交id插入blob将成为一个无限递归的任务。)任何克隆此树的人都需要为自己设置属性。

tpgth1q7

tpgth1q74#

有人向我指出ident上的“man gitattributes”部分,其中有:
识别
当为路径设置了ident属性时,git会将blob对象中的$Id$替换为$Id:,后跟40个字符的十六进制blob对象名称,然后在 checkout 时后跟美元符号$。任何以$Id开头的字节序列:并且在工作树文件中以$结尾,在检入时将替换为$Id$。
如果你仔细想想,这就是CVS,Subversion等所做的。如果查看存储库,您将看到存储库中的文件始终包含,例如,$Id$。它从不包含这种扩张。只有在 checkout 时,文本才会展开。

j91ykkif

j91ykkif5#

在提交框之外思考!
pop this into the file hooks/post-checkout

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

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

lb3vh1jj

lb3vh1jj6#

我不认为你真的想这么做,因为当提交中的文件被更改时,提交的哈希值也会被更改。

zd287kbt

zd287kbt7#

让我来探讨一下为什么这是一个使用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)校验和写入文件。

6pp0gazn

6pp0gazn8#

我更喜欢简单地写确切的日期时间和父提交的哈希,所以在hooks/pre-commit中我写了下面的代码:

#!/bin/bash
ver_file=version.txt
> $ver_file
date +"%Y-%m-%d %T %:z" >> $ver_file
echo -n "Parent: " >> $ver_file
git rev-parse HEAD >> $ver_file
git add $ver_file
echo "Date-time and parent commit added to '$ver_file'"
exit 0

自动生成的version.txt文件示例:

2023-05-24 01:24:12 +03:30
Parent: 35acd10240a55d164b371aa28812e8e988ab0c8d

当你checkout到另一个提交时,这个方法也会继续工作,因为version.txt文件的存储方式与其他文件的存储方式完全相同,并且出于同样的原因,在remote存储库和submodule中也是如此,但是你必须确保在.git/hooks/pre-commit中也存在相同的文件,用于你的子模块或远程存储库。

相关问题