在 Git 中,如何将当前提交哈希写入同一提交中的文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3442874/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
In Git, how can I write the current commit hash to a file in the same commit
提问by Felipe Kamakura
I'm trying to do a fancy stuff here with Git hooks, but I don't really know how to do it (or if it's possible).
我正在尝试使用 Git 钩子在这里做一些奇特的事情,但我真的不知道该怎么做(或者如果可能的话)。
What I need to do is: in every commit I want to take its hash and then update a file in the commit with this hash.
我需要做的是:在每次提交中,我想获取其哈希值,然后使用此哈希值更新提交中的文件。
Any ideas?
有任何想法吗?
采纳答案by Cascabel
I would recommend doing something similar to what you have in mind: placing the SHA1 in an untrackedfile, generated as part of the build/installation/deployment process. It's obviously easy to do (git rev-parse HEAD > filename
or perhaps git describe [--tags] > filename
), and it avoids doing anything crazy like ending up with a file that's different from what git's tracking.
我建议您做一些与您的想法类似的事情:将 SHA1 放在一个未跟踪的文件中,作为构建/安装/部署过程的一部分生成。这显然很容易做到(git rev-parse HEAD > filename
或者可能git describe [--tags] > filename
),并且它避免了做任何疯狂的事情,比如最终得到一个与 git 跟踪的文件不同的文件。
Your code can then reference this file when it needs the version number, or a build process could incorporate the information into the final product. The latter is actually how git itself gets its version numbers - the build process grabs the version number out of the repo, then builds it into the executable.
然后,您的代码可以在需要版本号时引用此文件,或者构建过程可以将信息合并到最终产品中。后者实际上是 git 本身获取其版本号的方式——构建过程从 repo 中获取版本号,然后将其构建到可执行文件中。
回答by kolypto
It's impossible to write the current commit hash: if you manage to pre-calculate the future commit hash — it will change as soon as you modify any file.
不可能写出当前的提交哈希:如果你设法预先计算未来的提交哈希——只要你修改任何文件,它就会改变。
However, there're three options:
但是,有三种选择:
- Use a script to increment 'commit id' and include it somewhere. Ugly
- .gitignore the file you're going to store the hash into. Not very handy
- In
pre-commit
, store the previous commit hash:) You don't modify/insert commits in 99.99% cases, so, this WILL work. In the worst case you still can identify the source revision.
- 使用脚本增加“提交 ID”并将其包含在某处。丑陋的
- .gitignore 要将散列存储到的文件。不是很方便
- 在 中
pre-commit
,存储之前的提交哈希:) 在 99.99% 的情况下您不会修改/插入提交,因此,这将起作用。在最坏的情况下,您仍然可以识别源版本。
I'm working on a hook script, will post it here 'when it's done', but still — earlier than Duke Nukem Forever is released :))
我正在编写一个钩子脚本,将在“完成后”发布它,但仍然 - 比《永远的毁灭公爵》发布还要早:))
UPD: code for .git/hooks/pre-commit
:
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
Now the only thing we need is a tool that converts prev_commit,branch
pair to a real commit hash :)
现在我们唯一需要的是一个将prev_commit,branch
pair转换为真正的提交哈希的工具:)
I don't know whether this approach can tell merging commits apart. Will check it out soon
我不知道这种方法是否可以区分合并提交。很快就会检查出来
回答by Baron Schwartz
Someone pointed me to "man gitattributes" section on ident, which has this:
有人向我指出了 ident 上的“man gitattributes”部分,其中有:
ident
身份
When the attribute ident is set for a path, git replaces $Id$ in the blob object with $Id:, followed by the 40-character hexadecimal blob object name, followed by a dollar sign $ upon checkout. Any byte sequence that begins with $Id: and ends with $ in the worktree file is replaced with $Id$ upon check-in.
当为路径设置属性 ident 时,git 将 blob 对象中的 $Id$ 替换为 $Id:,后跟 40 个字符的十六进制 blob 对象名称,然后在结帐时使用美元符号 $。在工作树文件中以 $Id: 开头并以 $ 结尾的任何字节序列在签入时将替换为 $Id$。
If you think about it, this is what CVS, Subversion, etc do as well. If you look at the repository, you'll see that the file in the repository always contains, for example, $Id$. It never contains the expansion of that. It's only on checkout that the text is expanded.
如果你仔细想想,这也是 CVS、Subversion 等所做的。如果查看存储库,您将看到存储库中的文件始终包含,例如,$Id$。它从不包含扩展。只有在结帐时才会展开文本。
回答by legoscia
This can be achieved by using the filter
attribute in gitattributes. You'd need to provide a smudge
command that inserts the commit id, and a clean
command that removes it, such that the file it's inserted in wouldn't change just because of the commit id.
这可以通过使用gitattributes 中的filter
属性来实现。您需要提供一个插入提交 id 的命令和一个删除它的命令,这样它插入的文件不会仅仅因为提交 id 而改变。smudge
clean
Thus, the commit id is never stored in the blob of the file; it's just expanded in your working copy. (Actually inserting the commit id into the blob would become an infinitely recursive task. ?) Anyone who clones this tree would need to set up the attributes for herself.
因此,提交 id 永远不会存储在文件的 blob 中;它只是在您的工作副本中展开。(实际上,将提交 id 插入 blob 将成为一个无限递归的任务。?)任何克隆这棵树的人都需要为自己设置属性。
回答by Keith Patrick
Think outside of the commit box!
在提交框之外思考!
pop this into the file hooks/post-checkout
将其弹出到文件挂钩/结帐后
#!/bin/sh
git describe --all --long > config/git-commit-version.txt
The version will be available everywhere you use it.
该版本将在您使用它的任何地方可用。
回答by midtiby
I don't think you actually want to do that, because when a file in the commit is changed, the hash of the commit is also changed.
我认为您实际上不想这样做,因为当提交中的文件发生更改时,提交的哈希值也会更改。
回答by Novice C
Let me explore why this is a challenging problem using the git internals. You can get the sha1 of the current commit by
让我来探讨一下为什么这是一个使用 git 内部结构的具有挑战性的问题。您可以通过以下方式获取当前提交的 sha1
#!/bin/bash
commit=$(git cat-file commit HEAD) #
sha1=($((printf "commit %s##代码##" $(echo "$commit" | wc -c); echo "$commit") | sha1sum))
echo ${sha1[0]}
Essentially you run a sha1 checksum on the message returned by git cat-file commit HEAD
. Two things immediately jump out as a problem when you examine this message. One is the tree sha1 and the second is the commit time.
本质上,您对返回的消息运行 sha1 校验和git cat-file commit HEAD
。当您检查此消息时,有两件事会立即成为问题。一个是树 sha1,第二个是提交时间。
Now the commit time is easily taken care of by altering the message and guessing how long it takes to make a commit or scheduling to commit at a specific time. The true issue is the tree sha1, which you can get from git ls-tree $(git write-tree) | git mktree
. Essentially you are doing a sha1 checksum on the message from ls-tree, which is a list of all the files and their sha1 checksum.
现在可以通过更改消息并猜测在特定时间进行提交或安排提交需要多长时间来轻松处理提交时间。真正的问题是树 sha1,您可以从git ls-tree $(git write-tree) | git mktree
. 本质上,您正在对来自 ls-tree 的消息进行 sha1 校验和,这是所有文件及其 sha1 校验和的列表。
Therefore your commit sha1 checksum depends on your tree sha1 checksum, which directly depends on the files sha1 checksum, which completes the circle and depends on the commit sha1. Thus you have a circular problem with techniques available to myself.
因此,您的提交 sha1 校验和取决于您的树 sha1 校验和,它直接取决于文件 sha1 校验和,它完成了循环并取决于提交 sha1。因此,您对我自己可用的技术存在循环问题。
With less secure checksums, it has been shown possible to write the checksum of the file into the file itself through brute force; however, I do not know of any work that accomplished that task with sha1. This is not impossible, but next to impossible with our current understanding (but who knows maybe in a couple years it will be trivial). However, still this is even harder to brute force since you have to write the (commit) checksum of a (tree) checksum of a (blob) checksum into the file.
使用不太安全的校验和,已经证明可以通过蛮力将文件的校验和写入文件本身;但是,我不知道使用 sha1 完成该任务的任何工作。这并非不可能,但以我们目前的理解几乎不可能(但谁知道也许几年后它会变得微不足道)。但是,这仍然更难以暴力破解,因为您必须将(blob)校验和的(树)校验和的(提交)校验和写入文件。