我提交时如何将Git提交ID填充到文件中?

时间:2013-05-13 14:13:45

标签: git

我想创建一个Git hook(s),它将在我的源代码中填充我将要进行的提交的提交ID(基本上是变量替换)。这可能与Git有关吗?或者是通过将变量解析为git id,我将改变sha 1,从而结束了“鸡或鸡蛋”问题。

9 个答案:

答案 0 :(得分:33)

我用于类似情况的解决方案是:

  1. 将字符串$Id$放在您要识别的文件中的某个位置(例如test.html),可能在文件的注释或其他非功能部分中,它不会导致问题。
  2. .gitattributes中,使用ident关键字标记相关文件(例如*.html ident)。
  3. 这样做的结果是当git checkout将文件从对象数据库复制到您的工作目录时,它会将$Id$字符串展开为$Id: <sha-1 of file>$git add当你想要检查它时,它会转换该转换,因此对象数据库中该文件的版本只包含$Id$,而不是扩展的表单。

    这是一个开始,但不幸的是,发现包含具有特定哈希的文件的提交并不那么容易,也不一定是一对一的。因此,此外,我还使用export-subst属性(例如*.html ident export-subst中的.gitattributes)标记这些文件,并在文件中的某处添加一个额外的字符串,如$Format:%ci$ ($Format:%h$)好。

    但是,

    git checkoutgit add不会影响这些标记,因此我的存储库中的版本始终具有该字符串。为了扩展这些标签,你必须使用git archive来创建项目特定版本的tar-ball(或.zip),然后用它来部署该版本 - 你不会能够只复制文件,或make install或其他,因为git archive是唯一可以扩展这些标记的东西。

    我给出的两个标签作为示例扩展为YYYY-MM-DD HH:MM:SS +TZOFFSET (HASH),其中HASH在这种情况下是实际的提交哈希,因此它更有用。

    您可以在$Format:$说明符下的git log帮助页面中找到其他可能有用的--pretty-format说明符。

答案 1 :(得分:7)

您可以创建一个过滤器,在提交和结帐时对文件进行替换。这些被称为“涂抹”和“干净”过滤器,它们的操作通过.gitattributes来控制。例如:

*.c     filter=yourfilter

这告诉git为所有yourfilter个文件运行.c过滤器。然后你必须告诉git yourfilter意味着什么:

git config --global filter.yourfilter.clean script1
git config --global filter.yourfilter.smudge script2

然后你会编写一个脚本(sed,Perl,Python或其他任何东西)来在结帐时用$LastSha$替换$LastSha: <sha>$这样的表达式(“涂抹”)。另一个脚本在提交之前反转扩展(“clean”。)

Search the Pro Git book用于“关键字扩展”的详细示例。

答案 2 :(得分:7)

不可能做你想做的事:提交的SHA-1哈希是在整个存储库快照上计算的,包括每个成员文件,所以有鸡和蛋问题 - 计算提交的哈希你需要知道所有的内容构成它的文件。

答案 3 :(得分:5)

您可以使用post-commit挂钩执行此操作。以下是the git-scm website

的摘录
  

完成整个提交过程后,运行后提交挂钩。它不需要任何参数,但您可以通过运行git log -1 HEAD轻松获得最后一次提交。通常,此脚本用于通知或类似的东西。

获取git log -1 HEAD的输出,然后使用sed之类的工具替换文件中的变量。但是,这会修改您的工作目录,除非您要将这些更改丢弃,否则您最终会得到一个永久修改的工作目录。

如果您只想在代码中的某个变量中使用当前提交哈希,则可以执行git log -1 HEADcat .git/HEAD并将输出存储在变量中

如果您只想要问题标题中的id(哈希),则可以使用--format标志。 git log -1 HEAD --format=%H

答案 4 :(得分:3)

好的,在Jon Cairns的回答的启发下,我想出了你可以放入Makefile的这个小片段。

version.h:
        git log -n 1 --format=format:"#define GIT_COMMIT \"%h\"%n" HEAD > $@

这不是一个完全通用的解决方案,但它可以派上用场。我知道我将使用它的地方。

答案 5 :(得分:1)

这里的关键是将您的修订版ID放入Git不关心的文件中。这是我的一个项目的片段:

.
.
.
AssemblyCS="Properties/AssemblyInfo.cs"
rev="$(git log -n 1 --date=short --format=format:"rev.%ad.%h" HEAD)"
sed  "$AssemblyCS"
.
.
.

此脚本作为构建过程的一部分运行(它也可能是一个提交后挂钩)。在这种情况下,Properties/AssemblyInfo.cs位于.gitignore,而Properties/AssemblyInfo.cs.in处于版本控制之下。构建使用.cs文件,其中包含最终在已部署的可执行文件中的修订ID。

答案 6 :(得分:1)

正如其他人所提到的,在同一次提交期间,您无法将提交的SHA-1本身放入文件中。无论如何,这将是有限的用途,因为查看两个文件,你不能立即告诉哪个更新。

话虽如此,事实上有一种方法可以自动将版本跟踪信息放入提交的文件中。我为我当前的项目做了这个(FrauBSD;我正在研究的FreeBSD的一个分支)。

我没有使用git-attributes过滤器来实现这一点。虽然git-attributes过滤器可以很容易地实现相反的结果(在结账时将信息放入文件中),但我想要的是在提交时扩展某些关键字,以便数据进入存储库(例如,在“git push origin master”之后,github在提交的文件中显示扩展值。使用git-attributes过滤器实现后者非常困难,因为简单的“git diff”将调用filter.clean属性,并且就像我的情况一样,如果你将日期/时间信息放入扩展中,那么每次执行“git diff”时的值更改都是不受欢迎的,也是不可接受的。

所以我开发了一个预提交钩子和一个commit-msg钩子,它们共同起作用,解决了如何(特别是在FrauBSD案例中)替换提交文件中的以下内容的问题:

$ $ FrauBSD

在办理登机手续之前使用类似于以下内容的东西(扩展值上游以供其他人结账):

$ FrauBSD:filepath YYYY-MM-DD HH:MM:ZZ GMTOFFSET提交者$

当有人在github上浏览文件或执行结帐或合并文件时,扩展的信息会随之而来。

注意:扩展值不会改变,除非分别伴随另一个(不相关的)变更。

例如,请参阅以下提交,其中我只删除文件的尾部换行符。提交包含删除尾随换行符以及$ FrauBSD $关键字中日期/时间的碰撞:

https://github.com/freebsdfrau/FrauBSD/commit/060d943d86bb6a79726065aad397723a9c704ea4

为了产生这个提交,我做了大多数[git]开发人员熟悉的事情:

  1. vi LICENSE
  2. Shift-G#转到文件末尾
  3. dd#删除当前行
  4. ZZ#save file并退出
  5. git diff#diff显示删除尾随换行符 注意:diff 显示对$ FrauBSD $ value的更改[尚]
  6. git add LICENSE
  7. git diff#nothing(没有未分期更改)
  8. git diff --cached #diff显示删除尾随换行符 注意:diff [still] 显示对$ FrauBSD $ value的更改
  9. git status#显示已修改的LICENSE
  10. git commit#$ EDITOR出现
  11. Ctrl-Z#将$ EDITOR放入后台,以便我们进行调查
  12. git diff --cached #diff [now]显示$ FrauBSD $ update以及删除尾随换行符
  13. fg#resume $ EDITOR
  14. :Q! #quit编辑器没有变化 注意:因为您中止了提交,$ FrauBSD $被还原
  15. git diff --cached #diff [again]仅显示尾随换行符
  16. git commit#这次我们不会中止
  17. BumpZZ#Insert“Bump”,保存并退出
  18. 文件按原样提交
  19. 注意:无需对提交后文件

    进行任何操作

    那是因为我的项目中有以下文件:

    • .git / hooks / pre-commit(符号链接到../../。hooks / pre-commit)
    • .git / hooks / commit-msg(符号链接到../../。hooks / commit-msg)
    • .hooks /预提交
    • .hooks /提交-MSG
    • .filters / fraubsd的关键字

    您可以在此处获得初步修订:

    “为预先提交污迹添加挂钩/过滤器”

    https://github.com/freebsdfrau/FrauBSD/commit/63fa0edf40fe8f5936673cb9f3e3ed0514d33673

    注意:过滤器由钩子使用(不在git-attributes中使用)。

    此处有更新:

    HTTPS - // github.com/freebsdfrau/FrauBSD/commit/b0a0a6c7b2686db2e8cdfb7253aba7e4d7617432

    或者你可以在这里查看头部修订:

    HTTPS - // github.com/freebsdfrau/FrauBSD/tree/master/.filters

    HTTPS - // github.com/freebsdfrau/FrauBSD/tree/master/.hooks

    注意:冒号更改为 - 在上面的URL中,所以我可以发布超过2个链接(因为声誉很低)

    享受, FreeBSDFrau

答案 7 :(得分:0)

我正在寻找类似的东西,因为我想要一个唯一的变量,我可以在前端添加到资源文件的末尾(比如CSS / JS),这样我们就可以设置很长的缓存时间来减少带宽和提高性能,但很容易强制它们在任何提交后重新加载。基本上是文件版本,但完全自动化。我并不关心它是最近的 MOST ,只要它在所有应用服务器中都是独一无二的,自动化的和一致的。

我们的部署脚本只使用'git clone'将最新代码的副本下载到我们的应用服务器中,但我们通过.htaccess限制访问这些文件和目录。

/.git/目录包含一个名为ORIG_HEAD的文件,该文件在任何合并(或任何其他危险操作)之后使用其前任的提交ID进行更新。由于我们使用git flow,因此每次我们将releasefix推送到分支并进行部署时,它都会更新。

你可以这样做,我假设使用任何脚本语言,但在我们的例子中,PHP,我这样做了......

define("MY_VERSION",substr(file_get_contents(realpath(__DIR__.'/../.git/ORIG_HEAD')),0,3));

您的路径显然必须根据您自己的目的进行调整,但这会产生一个3 char 足够的 id用于我们的目的,现在会附加到资源URL的末尾。

希望能帮助处于相同情况的人。

答案 8 :(得分:0)

我一直在寻找这个问题的答案。提交ID已写入您只需知道查找位置的文件。在master分支上提交后,您可以在以下处找到提交哈希 ./.git/refs/heads/master 因此,在我们的持续交付解决方案(它下载.git文件夹和源代码)中,我们可以简单地进行 cat ./.git/refs/heads/${BRANCH} 以便将当前提交哈希与我们的构建

相关联