Gitでは、現在のコミットハッシュを同じコミットのファイルにどのように書き込むことができますか


131

私はここでGitフックを使って空想的なことをやろうとしていますが、どうすればよいのか(あるいはそれが可能かどうか)はわかりません。

私がする必要があるのは、すべてのコミットでそのハッシュを取得し、このハッシュでコミット内のファイルを更新することです。

何か案は?


12
基本的に私はWebアプリケーションを持っているので、そのアプリケーションのインストール済みバージョンを、そのバージョンが関連付けられている正確なコミットに関連付けたいと考えています。私の最初のアイデアは、commitハッシュでabout.htmlファイルのようなものを更新することでした。しかし、gitのオブジェクトモデルを調べた後、これは不可能だと気づきました= /
Felipe Kamakura

29
これは非常に実用的な問題です。私もそれに遭遇しました!
Li Dong

7
私については、プログラムに「myprog starting up、v.56c6bb2」のようなメッセージをログに書き込みたいと思います。そうすれば、誰かがバグを報告してログファイルを送ってくれれば、プログラムのどのバージョンが実行されているかを正確に知ることができます。
エドワードフォーク2016年

5
@Jefromi、実際のユースケースは実際には非常に一般的であり、初心者に非常に簡単にヒットします。実際のバージョンをベースラインファイルに何らかの形で "刻印"することは基本的なニーズであり、それが間違ったアイデアになる理由は明らかではありません。たとえば、それが手動のリビジョン管理ハックを使用する唯一の選択肢であるためです。(初心者を覚えておいてください。)さらに、多くのプロジェクトには、バージョンを取得してライブファイルにスタンプするようなビルド/インストール/デプロイメントの手順がまったくありません。いずれにしても、事前コミットの代わりに、チェックアウト後フックがそのような場合でも役立つ可能性があります。
Sz。

不可能だよ!これを実行できる場合は、SHA-1ハッシュアルゴリズムに違反してい
betontalpfa

回答:


82

私はあなたが心に描いているのと同じようなことをすることをお勧めします:ビルド/インストール/デプロイメントプロセスの一部として生成された追跡されていないファイルにSHA1を配置します。これは明らかに(git rev-parse HEAD > filenameまたはおそらくgit describe [--tags] > filename)簡単で、gitが追跡しているものとは異なるファイルになってしまうなど、おかしなことは何もしません。

コードは、バージョン番号が必要なときにこのファイルを参照できます。または、ビルドプロセスで情報を最終製品に組み込むことができます。後者は、実際にはgit自体がバージョン番号を取得する方法です。ビルドプロセスは、リポジトリからバージョン番号を取得し、実行可能ファイルにビルドします。


3
誰かがこれを行う方法について段階的にさらに説明できますか?または、少なくとも正しい方向に微調整しますか?
Joel Worsham、2014

1
@ジョエルどうやって?ハッシュをファイルに入れる方法について述べました。残りはおそらくあなたのビルドプロセスに関するものですか?その部分について質問しようとしている場合は、おそらく新しい質問です。
Cascabel 2014

1
私の場合、すべてのビルドで「gitversion.h」ファイルを生成するルールをMakefileに追加しました。stackoverflow.com/a/38087913/338479を
Edward Falk

1
「git-checkout」フックでこれを自動化できるかもしれません。問題は、フックを手動でインストールする必要があることです。
エドワードフォーク2016年

14

現在のコミットハッシュを書き込むことは不可能です。将来のコミットハッシュを事前に計算できた場合、ファイルを変更するとすぐに変更されます。

ただし、3つのオプションがあります。

  1. スクリプトを使用して「コミットID」を増分し、どこかに含めます。醜い
  2. ハッシュを保存するファイルを.gitignoreします。あまり便利ではない
  3. ではpre-commit前のコミットハッシュを保存します:) 99.99%の場合、コミットを変更/挿入しないので、これは機能します。最悪の場合でも、ソースリビジョンを特定できます。

私はフックスクリプトに取り組んでいますが、「完了したら」ここに投稿しますが、それでも— Duke Nukem Foreverがリリースされる前に:))

更新:コード.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ペアを実際のコミットハッシュに変換するツールだけです:)

このアプローチでマージコミットを区別できるかどうかはわかりません。すぐにチェックします


13

誰かが私にidentの「man gitattributes」セクションを指摘しました。

アイデンティティ

パスに属性identが設定されている場合、gitはblobオブジェクトの$ Id $を$ Id:に置き換え、チェックアウト時に40文字の16進数のblobオブジェクト名が続き、その後にドル記号$が続きます。ワークツリーファイルで$ Id:で始まり$で終わるバイトシーケンスは、チェックイン時に$ Id $に置き換えられます。

考えてみれば、これはCVSやSubversionなども同様です。リポジトリを見ると、リポジトリ内のファイルには常に、たとえば$ Id $が含まれていることがわかります。それの拡張は含まれません。テキストが展開されるのは、チェックアウト時のみです。


8
identコミットの速さではなく、ファイル自体のハッシュです。git-scm.com/book/en/…から:「ただし、その結果の使用は制限されています。CVSまたはSubversionでキーワード置換を使用している場合は、日付スタンプを含めることができます。SHAはそれほど役に立ちませんが、それはかなりランダムであり、1つのSHAが別のSHAより古いか新しいかを判断できないためです。」filter動作しますが、コミット情報をファイルに(またはファイルから)取得できます。
Zach Young

11

これはgitattributesfilter属性を使用することで実現できます。コミットIDを挿入したコマンドと、それを削除したコマンドを提供する必要があります。これにより、挿入されたファイルがコミットIDだけで変更されないようになります。smudgeclean

したがって、コミットIDがファイルのblobに格納されることはありません。作業コピーで展開されるだけです。(実際には、コミットIDをBLOBに挿入すると、無限に再帰的なタスクになります。☺)このツリーを複製する人は、自分の属性を設定する必要があります。


7
不可能なタスクで、再帰的タスクではありません。コミットハッシュは、ファイルの内容に依存するファイルハッシュに依存するツリーハッシュに依存します。自己矛盾のないようにする必要があります。あなたがSHA-1ハッシュの一種の[一般化された]固定点を見つけない限り。
JakubNarębski、2010

1
@Jakub、結果のハッシュを変更しない追跡されたファイルを作成できるようにするgitのトリックはありますか?おそらく、そのハッシュをオーバーライドするいくつかの方法。それが解決策になります:)
kolypto 2010

@o_O Tync:不可能です。変更されたファイルは、(ファイルの)変更されたハッシュを意味します-これは設計によるものであり、ハッシュ関数の定義によるものです。
JakubNarębski、2011年

2
これはかなり良い解決策ですが、これには、リポジトリを複製するたびに手動でインストールする必要があるフックが含まれることを覚えておいてください。
Edward Falk 2016年

7

コミットボックスの外側で考えてください!

これをファイルhooks / post-checkoutにポップします

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

このバージョンは、どこででも使用できます。


3

コミットしたいファイルが変更されると、コミットのハッシュも変更されるため、実際にそれを実行する必要はないと思います。


1

これがgit internalsを使用して難しい問題である理由を調べてみましょう。あなたは現在のコミットのsha1を取得することができます

#!/bin/bash
commit=$(git cat-file commit HEAD) #
sha1=($((printf "commit %s\0" $(echo "$commit" | wc -c); echo "$commit") | sha1sum))
echo ${sha1[0]}

基本的に、によって返されるメッセージに対してsha1チェックサムを実行しgit cat-file commit HEADます。このメッセージを調べると、2つのことがすぐに問題として飛び出します。1つはツリーsha1で、もう1つはコミット時間です。

これで、コミット時間は、メッセージを変更し、コミットを行うのにかかる時間または特定の時間にコミットするためのスケジューリングにかかる​​時間を推測することで簡単に処理されます。本当の問題はツリーsha1で、これはから取得できますgit ls-tree $(git write-tree) | git mktree。基本的に、すべてのファイルとそのsha1チェックサムのリストであるls-treeからのメッセージに対して、sha1チェックサムを実行しています。

したがって、コミットsha1チェックサムは、ツリーsha1チェックサムに依存します。これは、ファイルsha1チェックサムに直接依存します。これは、円を完成させ、コミットsha1に依存します。したがって、あなたは私自身が利用できる技術に循環的な問題を抱えています。

安全性の低いチェックサムは、ブルートフォースを通じてファイル自体にファイルのチェックサムを書くことができることが示されています。ただし、sha1でそのタスクを実行した作業については知りません。これは不可能ではありませんが、現在の理解では不可能に近いものです(しかし、数年後にはそれは簡単なことだと知っている人はいます)。ただし、ファイルに(ブロブ)チェックサムの(ツリー)チェックサムの(コミット)チェックサムを書き込む必要があるため、これはブルートフォースにさらに困難です。


ファイルをコミットしてからチェックアウトし、最新のコミットハッシュを各ソースコードファイルの先頭にコメントとして配置する方法はありますか?それからビルドして実行しますか?
ジョンウーテン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.