web-dev-qa-db-ja.com

Cコードを取得してGitバージョンハッシュを自動的に出力するにはどうすればよいですか?

GitバージョンハッシュにアクセスできるCコードを書く簡単な方法はありますか?

実験室で科学データを収集するために、Cでソフトウェアを作成しました。私のコードは、後で分析するために収集したデータを.yamlファイルに記録します。私の実験は日々変化し、コードを修正しなければならないことがよくあります。リビジョンを追跡するために、gitリポジトリを使用します。

.yamlデータファイルにGitリビジョンハッシュをコメントとして含めることができます。そうすれば、.yamlファイルを見て、そのファイルに表示されるデータを生成するためにどのコードが使用されたかを正確に知ることができます。これを自動的に行う簡単な方法はありますか?

75
AndyL

私のプログラムでは、次のようなversion.cと呼ばれる別のファイルにgitバージョン番号とビルドの日付を保持しています。

#include "version.h"
const char * build_date = "2009-11-10 11:09";
const char * build_git_sha = "6b54ea36e92d4907aba8b3fade7f2d58a921b6cd";

次のようなヘッダーファイルもあります。

#ifndef VERSION_H
#define VERSION_H
extern const char * build_date; /* 2009-11-10 11:09 */
extern const char * build_git_sha; /* 6b54ea36e92d4907aba8b3fade7f2d58a921b6cd */
#endif /* VERSION_H */

ヘッダーファイルとCファイルの両方は、次のようなPerlスクリプトによって生成されます。

my $git_sha = `git rev-parse HEAD`;
$git_sha =~ s/\s+//g;
# This contains all the build variables.
my %build;
$build{date} = make_date_time ();
$build{git_sha} = $git_sha;

hash_to_c_file ("version.c", \%build, "build_");

ここで、hash_to_c_fileversion.cversion.hを作成するすべての作業を行い、make_date_timeは示されているように文字列を作成します。

メインプログラムには、ルーチンがあります

#include "version.h"

// The name of this program.
const char * program_name = "magikruiser";
// The version of this program.
const char * version = "0.010";

/* Print an ID stamp for the program. */

static void _program_id_stamp (FILE * output)
{
    fprintf (output, "%s / %s / %s / %s\n",
             program_name, version,
             build_date, build_git_sha);
}

私はgitについてそれほど詳しくないので、もっと良い方法があればコメントを歓迎します。

37
user181548

Makeベースのビルドを使用している場合、これをMakefileに入れることができます。

GIT_VERSION := "$(Shell git describe --abbrev=4 --dirty --always --tags)"

(スイッチの機能については man git describe を参照)

次に、これをCFLAGSに追加します。

-DVERSION=\"$(GIT_VERSION)\"

次に、#defineのようにプログラムで直接バージョンを参照できます。

printf("Version: %s\n", VERSION);

デフォルトでは、これは単にgit commit idを出力しますが、オプションで特定のリリースに次のようなタグを付けることができます:

git tag -a v1.1 -m "Release v1.1"

次に印刷されます:

Version: v1.1-2-g766d

つまり、v1.1を超えて2回コミットし、GitコミットIDが「766d」で始まります。

ツリーにコミットされていない変更がある場合、「-dirty」が追加されます。

依存関係のスキャンは行われないため、バージョンを強制的に更新するには、明示的なmake cleanを実行する必要があります。これ 解決可能 ただし。

利点は、シンプルであり、Perlやawkのような追加のビルド依存関係を必要としないことです。私はこのアプローチをGNU automakeおよびAndroid NDKビルドで使用しました。

145
ndyer

@Kinopikoの答えに非常に似たものを使用することになりましたが、Perlではなくawkを使用しました。これは、mingwの性質によりawkがインストールされているがPerlではないWindowsマシンにこだわっている場合に便利です。仕組みは次のとおりです。

私のメイクファイルには、git、date、awkを呼び出してcファイルを作成する行が含まれています。

$(MyLibs)/version.c: FORCE 
    $(GIT) rev-parse HEAD | awk ' BEGIN {print "#include \"version.h\""} {print "const char * build_git_sha = \"" $$0"\";"} END {}' > $(MyLibs)/version.c
    date | awk 'BEGIN {} {print "const char * build_git_time = \""$$0"\";"} END {} ' >> $(MyLibs)/version.c 

コードをコンパイルするたびに、awkコマンドは次のようなversion.cファイルを生成します。

/* version.c */
#include "version.h"
const char * build_git_sha = "ac5bffc90f0034df9e091a7b3aa12d150df26a0e";
const char * build_git_time = "Thu Dec  3 18:03:58 EST 2009";

次のような静的version.hファイルがあります。

/*version.h*/
#ifndef VERSION_H_
#define VERSION_H_

extern const char * build_git_time;
extern const char * build_git_sha;


#endif /* VERSION_H_ */

残りのコードは、version.hヘッダーを含めるだけでビルド時間とgitハッシュにアクセスできるようになりました。最後に、.gitignoreファイルに行を追加して、version.cを無視するようにgitに指示します。このように、gitは常にマージの競合を与えません。お役に立てれば!

11
AndyL

あなたのプログラムはgit describe、実行時またはビルドプロセスの一部として。

9
bdonlan

できることは2つあります。

  • Gitを作成して、ファイルにバージョン情報を埋め込むことができます。

    より簡単な方法は、identattribute を使用することです。これは、(たとえば)

    *.yaml    ident
    

    .gitattributesファイルに、$Id$に適切な場所に。ファイルの内容のSHA-1識別子に自動的に展開されます(blob id) :これはファイルバージョンでも、最後のコミットでもありません。

    Gitはこの方法で$ Id $キーワードをサポートし、ブランチの切り替え、ブランチの巻き戻しなどの間に変更されなかったファイルに触れないようにします。Gitでファイルにコミット(バージョン)識別子または説明を入れたい場合、(ab)use filter属性。clean/ smudgeフィルターを使用して、チェックアウト時にキーワード(たとえば、$ Revision $)を展開し、コミットのためにクリーンアップします。

  • LinuxカーネルやGit自体が行うように、build processを作成することができます。

    GIT-VERSION-GEN スクリプトとGitでの使用 Makefile をご覧ください。または、たとえば、このMakefileがgitweb/gitweb.cgiの生成/構成中にバージョン情報を埋め込む方法をご覧ください。ファイル。

    GIT-VERSION-GENはgit describeを使用してバージョンの説明を生成します。プロジェクトのリリース/マイルストーンに(署名付き/注釈付きタグを使用して)タグを付けることが、より適切に機能する必要があります。

7
Jakub Narębski

これを行う必要があるときは、RELEASE_1_23のような tag を使用します。 SHA-1を知らなくても、タグが何であるかを判断できます。コミットしてからタグ付けします。とにかく、そのタグをプログラムに保存できます。

4
brian d foy

Njd27による答えに基づいて、コードが異なる方法で構築されたときのデフォルト値を持つversion.hファイルと組み合わせて、依存関係スキャン付きのバージョンを使用しています。 version.hを含むすべてのファイルが再構築されます。

また、個別の定義として改訂日も含まれます。

# Get git commit version and date
GIT_VERSION := $(Shell git --no-pager describe --tags --always --dirty)
GIT_DATE := $(firstword $(Shell git --no-pager show --date=short --format="%ad" --name-only))

# recompile version.h dependants when GIT_VERSION changes, uses temporary file version~
.PHONY: force
version~: force
    @echo '$(GIT_VERSION) $(GIT_DATE)' | cmp -s - $@ || echo '$(GIT_VERSION) $(GIT_DATE)' > $@
version.h: version~
    @touch $@
    @echo Git version $(GIT_VERSION) $(GIT_DATE)
3
PTT

また、科学コードの変更を追跡するためにgitを使用しています。コードの移植性を制限するため、外部プログラムを使用したくありませんでした(誰かがMSVSで変更を加えたい場合など)。

私の解決策は、計算にメインブランチのみを使用し、プリプロセッサマクロを使用してビルド時間を出力することでした__DATE__および__TIME__。そうすれば、gitログで確認して、使用しているバージョンを確認できます。参照: http://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html

問題を解決する別のエレガントな方法は、gitログを実行可能ファイルに含めることです。 gitログからオブジェクトファイルを作成し、コードに含めます。今回は、使用する外部プログラムはobjcopyのみですが、コーディングは少なくなります。参照: http://www.linuxjournal.com/content/embedding-file-executable-aka-hello-world-version-5967 および C++プログラムにデータを埋め込む

2
kirill_igum

必要なことは、次のようなヘッダーファイルを生成することです(たとえば、cmd行からのエコーを使用)。

#define GIT_HASH \
"098709a0b098c098d0e"

生成するには、次のようなものを使用します。

echo #define GIT_HASH \ > file.h
echo " > file.h
echo git status <whatever cmd to get the hash> > file.h
echo " > file.h

引用符とバックスラッシュを少し使用してコンパイルする必要があるかもしれませんが、アイデアは得られます。

2
Igor Zevaka

Makefileとシェルに基づくさらに別のバリエーション

GIT_COMMIT_FILE=git_commit_filename.h

$(GIT_COMMIT_FILE): phony
    $(eval GIT_COMMIT_SHA=$(Shell git describe --abbrev=6 --always 2>/dev/null || echo 'Error'))
    @echo SHA=$(GIT_COMMIT_SHA)
    echo -n "static const char *GIT_COMMIT_SHA = \"$(GIT_COMMIT_SHA)\";" > $(GIT_COMMIT_FILE)

ファイルgit_commit_filename.hは、静的const char * GIT_COMMIT_SHA = "";を含む1行で終わります。

から https://Gist.github.com/larytet/898ec8814dd6b3ceee65532a9916d406

1
Larytet

元のコミット でmemcachedに対してどのように行ったかを確認できます。

基本的に、ときどきタグを付け、配信するものがmake dist または類似。

0
Dustin