2013-05-13 72 views
24

我想创建Git钩子,它将在我的源代码中填充我将要创建的文件(基本上是变量替换)的提交ID。这可能与Git?或者事实上,通过将变量解析为git id,我将改变sha 1,从而以“鸡或鸡蛋”问题结束。我如何在提交时将Git提交ID填充到文件中?

+3

由于sha1是校验和,因此不可能将它放在提交的集合中。实现通过压缩提交可能是可能的。你想要做什么?你确定你正在更大规模地解决正确的问题吗? – 2013-05-13 14:21:00

+0

我认为注释不会改变SHA1,所以它们会成为这类信息的完美候选人。那就是:如果我的假设是真的。 – 2013-05-13 15:16:53

+0

这是理想的原因: 我在git中存储的内容不是编译的代码,而是部署到ETL服务器的ETL作业配置。我想要在ETL服务器上部署的内容和Git中的内容之间进行可追溯性。因此,当登录到ETL服务器时,我希望能够查看我创建的名为“git_id”的变量,该变量将包含与在ETL服务器上部署的作业版本关联的提交ID。我当然可以通过其他方式实现可追溯性,但如果可能的话,这将是最简单的。 – BestPractices 2013-05-13 17:24:04

回答

26

我已经使用了类似的情况的解决方法是这样的:

  1. 将字符串$Id$的地方,你希望有标识的文件中(如test.html),可能的评论或其他非功能部分内该文件不会导致问题。
  2. 在您的.gitattributes中,使用ident关键字标记相关文件(例如*.html ident)。

这样做的结果是,当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在这种情况下是实际提交散列,因此它更有用。

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

+0

这会为我们工作 - 谢谢! – BestPractices 2013-05-13 22:07:55

4

你可以用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

+5

这样的'post-commit'挂钩会修改工作目录。每次提交时,都会存储** previous **提交的SHA1,然后修改工作目录以包含上次提交的SHA1。 – Andomar 2013-05-13 14:22:52

+1

@Andomar这个挂钩可能会修改工作目录,但是如果对'.gitignored'文件进行修改(即为了构建目的或某些东西,不要被'git'跟踪),这仍然是有用的。这可能有助于更多地了解来自提问者的确切用例,尽管... – twalberg 2013-05-13 15:15:45

+0

+1此文章是有用的和有帮助的,不知道为什么它downvoted! – Andomar 2013-05-13 18:52:09

7

您可以创建一个过滤器,在提交和结帐时对文件进行替换。这些被称为“污迹”和“清洁”过滤器,其操作通过.gitattributes进行控制。例如:

*.c     filter=yourfilter 

这告诉GIT中运行的所有.c文件yourfilter过滤器。然后,你必须告诉混帐东西yourfilter意味着:

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

你会那么写一个脚本(SED,Perl,Python和或任何)与$LastSha: <sha>$结账(“污点”)来代替像$LastSha$的表达式。另一个脚本在提交之前反转扩展(“clean”)。

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

+0

这不是我想要做的 - 这将允许您在结帐时解析变量,并在签入时解决问题。不过,我需要在签入时专门修改文件,以便它包含文件的哈希ID。 – BestPractices 2013-05-13 16:55:37

+1

@BestPractices根本无法完成,请参阅[kostix的答案](http://stackoverflow.com/a/16525425/1290731) – jthill 2013-05-13 16:59:53

+0

我可能只在特定文件上运行此过滤器。 – jthill 2013-05-13 17:01:10

6

这是不可能做到你想要什么:提交的SHA-1散列在整个仓库的快照,包括各成员文件计算的,所以有鸡和蛋的问题—来计算你需要知道的内容提交的散所有构成它的文件。

+1

不知道为什么你会陷入低谷,你只是在说什么。 – jthill 2013-05-13 16:20:10

+0

@jthill,感谢您的支持!让我们假装在这种情况下我正在玩Jordano Bruno ;-) – kostix 2013-05-13 16:27:16

+1

请不要不必要地拒绝投票。 – BestPractices 2013-05-13 17:25:17

1

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

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

此脚本运行作为我的生成过程的一部分(也有可能是一个post-commit钩子)。在这种情况下,Properties/AssemblyInfo.cs.gitignore中,而Properties/AssemblyInfo.cs.in在版本控制下。该版本使用.cs文件,其中包含最终位于部署的可执行文件中的版本ID。

+1

实际上,我们在编译代码的时候会根据您的建议进行操作,但不幸的是,这不适用于我们的非编译代码。基本上我们在git中使用whats并将其部署到ETL服务器。没有什么可以编译或打包的。 – BestPractices 2013-05-13 22:06:52

+1

编译不是这个的重要部分。无论包含提交ID的文件是'.gitignored'还是作为部署过程的一部分生成。例如,如果部署步骤只是一个“混帐”,你可以把它变成一个“合并后”的钩子。相同的脚本也可以编写部署树的MD5清单。然后给出一个清单文件,你可以(a)检查真正的树匹配和(b)知道它来自哪个版本。 – 2013-05-14 04:37:50

1

正如其他人所提到的,在同一提交期间,您不能将提交的SHA-1本身放入文件中。无论如何,这将是有限的使用,因为看两个文件,你不能立即分辨哪个更新。这就是说,事实上有一种方法可以将版本跟踪信息自动放入提交文件中。我为我目前的项目做了这个工作(FrauBSD;我正在研究FreeBSD的一个分支)。

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

所以我开发了一个pre-commit钩子和提交-MSG挂钩,共同行动,解决问题如何(特别是在FrauBSD情况下)替换提交的文件如下:

$ FrauBSD $

类似下面的内容签入(扩值知难而上别人结账)之前:

$ FrauBSD:文件路径YYYY-MM-DD HH:MM:ZZ GMTOFFSET提交者$

当有人在眉头上在github上播放文件或者执行文件检出或合并,扩展后的信息会一起工作。

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

例如,请参阅以下提交,其中仅删除文件的尾随换行符。该承诺既包含去除尾随换行符的,以及在$ FrauBSD $关键字凹凸的日期/时间:

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

要生成犯,我做了最[混帐]开发者熟悉:

  1. 六许可
  2. 移-G#去文件结尾
  3. DD#删除当前行
  4. ZZ#保存文件并退出
  5. git的差异#差异显示去除换行符 注:DIFF不说明更改$ FrauBSD $值尚未]
  6. 混帐添加许可证
  7. git的差异#无(没有不分阶段的变化)
  8. git的差异--cached#差异显示去除换行符 注:DIFF(仍然)不说明更改$ FrauBSD $值
  9. git的状态#显示修改的许可
  10. git的承诺#$ EDITOR出现
  11. 按Ctrl-Z在后台#放到$ EDITOR,以便我们调查
  12. git的差异--cached#DIFF [现在]显示$ FrauBSD $更新以及去除换行符
  13. fg#resume $编辑者
  14. :q!#退出编辑器没有改变 注:由于您中止犯,$ FrauBSD $被恢复
  15. git的差异--cached#DIFF [再次]可见只有换行符去除
  16. git的承诺#这一次我们不会中止
  17. BumpZZ#插入“凹凸”,保存并退出
  18. 文件致力于为-是

注:没有什么需要做的文件提交后

那是因为我公顷已经在我的项目下列文件:

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

您可以在这里得到初始修订:

“添加钩/过滤器用于预提交弄脏”

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

注:该过滤器由钩(在GIT中的属性不使用)使用。

和更新这里:

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

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

HTTPS - // github上的.com/freebsdfrau/FrauBSD /树/主/ .filters

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

NO TE:结肠改变 - 在上面的网址,以便我可以张贴超过2个链接(因为信誉低)

享受, FreeBSDFrau

0

我一直在寻找类似的东西,因为我想要一个独特的变量我可能会增加的资源文件在我们的前端结束(如CSS/JS),这将允许我们设置很长的缓存时间来减少带宽并提高性能,但容易强制任何提交后他们重新加载。基本上文件版本控制,但完全自动化。我不在乎它是MOST近,只要它是独一无二的,自动化的,一致的我们所有的应用程序服务器。

我们的部署脚本只是用“混帐克隆”到最近的代码副本下拉到我们的应用服务器,但我们通过限制访问的.htaccess对这些文件和目录。

/.git/目录中,有提交ID它的前身叫ORIG_HEAD文件,其任何合并(或任何其他危险操作)后更新。因为我们使用git flow,所以这是完美的,因为每次我们将releasefix推送到主分支和部署时,它都会更新。

你可以做到这一点,我假设在任何脚本语言,但对我们来说,PHP,我做了这样的...

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

你的路径显然已经被调整了自己的目的,但这会产生一个3字符的足够独特的 id,用于我们的目的,它将被追加到我们资源URL的末尾。

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

1

好,受乔恩凯恩斯的回答启发,我想出了这个可以放在Makefile中的小片段。

version.h: 
     git log -n 1 --format=format:"#define GIT_COMMIT \"%h\"%n" HEAD > [email protected] 

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

+0

顺便说一句:我将改进和改进留给用户。特别是,你可能需要一个FORCE标签或其他东西来确保它在任何时候提交id改变时都被重建。 – 2016-06-28 23:32:26

+0

请参阅[Git pretty-formats Docs](https://git-scm.com/docs/pretty-formats)了解如何构建该格式字符串。 – luckydonald 2017-07-25 07:20:00

0

我正在寻找这个问题的答案。提交ID已写入文件,您只需知道在哪里查找。作出承诺的主分支后,你可以找到在 ./.git/refs/heads/master 因此,在我们连续交付解决方案(它下载git的文件夹中的源代码一起)提交的哈希,我们可以简单地 cat ./.git/refs/heads/${BRANCH} ,以目前的关联与我们的版本一起提交散列

相关问题