2013-05-13 74 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} ,以目前的關聯與我們的版本一起提交散列

相關問題