ソースコードのファイル (基本的には変数置換) に作成しようとしているコミットのコミット ID を入力する Git フックを作成したいと思います。これはGitで可能ですか?または、変数を git id に解決することで、sha 1 を変更することになり、それによって「ニワトリが先か卵が先か」の問題が発生します。
9 に答える
やりたいことをするのは不可能です: コミットの SHA-1 ハッシュは、各メンバー ファイルを含むリポジトリ スナップショット全体にわたって計算されるため、鶏が先か卵が先かという問題があります。コミットのハッシュを計算するには、すべてのファイルの内容を知る必要があります。それを構成します。
コミットおよびチェックアウト時にファイルを置換するフィルターを作成できます。これらは「汚れ」および「クリーン」フィルターと呼ばれ、その動作は によって制御され.gitattributes
ます。例えば:
*.c filter=yourfilter
yourfilter
これは、すべてのファイルに対してフィルターを実行するように git に指示し.c
ます。次に、git にyourfilter
意味を伝える必要があります。
git config --global filter.yourfilter.clean script1
git config --global filter.yourfilter.smudge script2
次に、スクリプト (sed、Perl、Python など) を記述して、on checkout ("smudge") などの式を置き換え$LastSha$
ます$LastSha: <sha>$
。もう 1 つのスクリプトは、コミット前に展開を逆にします (「クリーン」)。
詳細な例については、Pro Git ブックで「キーワード拡張」を検索してください。
OK、Jon Cairns の回答に触発されて、Makefile に入れることができるこの小さなスニペットを思いつきました。
version.h:
git log -n 1 --format=format:"#define GIT_COMMIT \"%h\"%n" HEAD > $@
これは完全に一般的な解決策ではありませんが、便利になる可能性があります。私はそれを使用する場所を1つか2つ知っています。
他の人が述べたように、同じコミット中にコミット自体のSHA-1をファイルに入れることはできません。2 つのファイルを見ても、どちらが新しいかすぐにはわからないため、これはいずれにしても使用が制限されます。
そうは言っても、実際にはバージョン追跡情報をコミットされたファイルに自動的に入れる方法があります。私は現在のプロジェクト (FrauBSD; 私が取り組んでいる FreeBSD のフォーク) のためにこれを行いました。
git-attributes フィルターを使用するのではなく、これを達成しました。git-attributes フィルターを使用すると、反対のこと (チェックアウト時に情報をファイルに入れる) を簡単に実現できますが、私が望んでいたのは、コミット時に特定のキーワードを展開して、データがリポジトリに入るようにすることでした (たとえば、「git push origin master」の後、github はコミットされたファイルに展開された値を表示します)。単純な「git diff」が filter.clean 属性を呼び出すため、後者を達成することは git-attributes フィルターでは非常に困難であることが判明しました。 「git diff」を実行するたびに値を変更することは望ましくなく、容認できません。
そこで私は pre-commit フックと commit-msg フックを開発しました。これらは連携して動作し、(特に FrauBSD の場合に) コミットされたファイル内の以下をどのように置き換えるかという問題を解決します:
$フラウBSD$
チェックインの前に次のようなものを使用します (展開された値は、他の人がチェックアウトするために上流に移動します)。
$FrauBSD: ファイルパス YYYY-MM-DD HH:MM:ZZ GMTOFFSET コミッター $
だれかが github でファイルを参照している場合、またはファイルのチェックアウトまたはマージを実行している場合、拡張された情報が一緒に移動します。
注: 別の (関連のない) 変更がそれぞれ付随しない限り、拡張された値は変更されません。
たとえば、ファイルの末尾の改行を単純に削除する次のコミットを参照してください。コミットには、末尾の改行の削除と、 $FrauBSD$ キーワードの日付/時刻へのバンプの両方が含まれています。
https://github.com/freebsdfrau/FrauBSD/commit/060d943d86bb6a79726065aad397723a9c704ea4
そのコミットを生成するために、ほとんどの [git] 開発者がよく知っていることを行いました。
- vi ライセンス
- Shift-G # ファイルの最後に移動
- dd # 現在の行を削除
- ZZ # ファイルを保存して終了
- git diff # diff は末尾の改行の削除を示しています 注: diff は$FrauBSD$ 値の変更を示していません[まだ]
- git add ライセンス
- git diff # なし (ステージングされていない変更はありません)
- git diff --cached # diff は末尾の改行の削除を示します 注: diff [まだ] は$FrauBSD$ 値への変更を示しません
- git status # 変更された LICENSE を表示
- git commit # $EDITOR が立ち上がる
- Ctrl-Z # 調査できるように $EDITOR をバックグラウンドに置く
- git diff --cached # diff [現在] は $FrauBSD$ の更新と末尾の改行の削除を示しています
- fg # $EDITOR を再開
- :q! # 変更せずにエディタを終了 注: コミットを中止したため、$FrauBSD$ は元に戻りました
- git diff --cached # diff [再び] 末尾の改行の削除のみを表示
- git commit # 今回は中断しません
- BumpZZ # "Bump" を挿入し、保存して終了
- ファイルはそのままコミットされます
注:コミット後のファイルに対して何もする必要はありません
これは、プロジェクトに次のファイルがあるためです。
- .git/hooks/pre-commit (../../.hooks/pre-commit へのシンボリック リンク)
- .git/hooks/commit-msg (../../.hooks/commit-msg へのシンボリック リンク)
- .hooks/pre-commit
- .hooks/commit-msg
- .filters/fraubsd-キーワード
ここで入手できる最初のリビジョン:
「コミット前のスマッジング用のフック/フィルターを追加する」
https://github.com/freebsdfrau/FrauBSD/commit/63fa0edf40fe8f5936673cb9f3e3ed0514d33673
注: フィルターはフックによって使用されます (git 属性では使用されません)。
そしてここで更新:
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
ここで重要なのは、リビジョン ID を Git が気にしないファイルに入れることです。これは私のプロジェクトの1つからの断片です:
. . . 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 を含むファイルを使用します。
フロントエンドのリソース ファイル (CSS/JS など) の末尾に追加できる一意の変数が必要だったという点で、同様のものを探していました。これにより、非常に長いキャッシュ時間を設定して、帯域幅を削減し、増加させることができます。パフォーマンスを向上させますが、コミット後に強制的に再ロードするのは簡単です。基本的にファイルのバージョン管理ですが、完全に自動化されています。すべてのアプリ サーバーで一意で、自動化され、一貫性がある限り、それが最新であることは気にしませんでした。
私たちのデプロイ スクリプトは、「git clone」を使用して最新のコードのコピーをアプリ サーバーにプルダウンするだけですが、それらのファイルとディレクトリへの .htaccess 経由のアクセスを制限しています。
ディレクトリには、マージ (またはその他の危険な操作) の後に、その前身のコミット ID で更新さ/.git/
れるというファイルが含まれています。git フローを使用しているので、 aまたは aをmasterブランチにプッシュしてデプロイするたびに更新されるため、これは完璧です。ORIG_HEAD
release
fix
これは、どのスクリプト言語でも実行できると思いますが、私たちの場合、PHP では、このように実行しました...
define("MY_VERSION",substr(file_get_contents(realpath(__DIR__.'/../.git/ORIG_HEAD')),0,3));
パスは明らかに独自の目的のために微調整する必要がありますが、これにより、リソース URL の末尾に追加される目的に十分な 3 文字の一意の ID が得られます。
同じ状況の誰かに役立つことを願っています。