gitで差分のエクスポート

差分抽出にはgitは欠かせません。手動でやるなんてもってのほか。間違いが起こりやすい上に面倒です。

今回ちょっと悩むところがあったのですが、この機会によく使う部分をまとめておきます。

基本の使い方

まず定番の、最新コミットの差分抽出。

git archive --format=zip --prefix=_diff/ HEAD `git diff --name-only HEAD HEAD^` -o _diff.zip

コマンドを説明すると、

・git archive
-> archiveコマンド命令

・–format=zip
->
zipに固めてね、という事

・–prefix=_diff/
-> エクスポート先のディレクトリ名

・HEAD
->
抽出元となるコミット

・`git diff –name-only HEAD HEAD^`
-> HEAD と HEAD^ の差分のファイル一覧を返して、ということ。

※補足
特定のコミットを指定するときは、^n と、~n というように指定します
^n -> n番目の親
~n -> n世代目の親
ということですが、普通に使う分には~nで良さそう。

なので、例えば4つ前のコミットと3つ前のコミットの差分が欲しい時は、
git archive –format=zip –prefix=_diff/ HEAD `git diff –name-only HEAD~2 HEAD~4` -o _diff.zip

-o _diff.zip
-> アウトプットのzip名

今回困ったこと

そして今回困った点ですが、コミット差分が大きすぎて、git archiveする時に “Argument list too long” なるエラーが出てしまいました。
このエラーは、コマンドに渡すパラメータには制限があって、それを超えると発生するエラーとのことです。
ちなみに、制限数は以下で確認出来ます。

getconf ARG_MAX

調べた所、この場合の回避策は”xargs”というコマンドが使えるよう。
xargs = extra argumentの意であるコマンド実行後に追加でコマンドを実行出来る。また、(これが重要)制限を超えた場合には適度に分割して複数実行を行ってくれるらしいです。

例)10個前のコミットから現在までのデータ量が多く、かつ差分の抽出の必要があったとする。

git diff --name-only HEAD HEAD~10 | xargs git archive --format=zip --prefix=_diff/ HEAD  -o _diff.zip 

そしてさらに、抽出時に問題となる特定のディレクトリを除外することも出来ます。

“export-ignore” を使います。

使い方は、

1.プロジェクトのルートディレクトリに、gitの設定ファイル「.gitattributes」を設置します。

2.その中に、例えば「hoge/」というディレクトリを除外したい場合は下記の様に追記。

hoge/ export-ignore

するとgit archive後のファイルには、これが含まれなくなるという仕様のようです。

これで晴れて、差分抽出が簡単に出来ました!

※追記

ファイルが削除されている場合などで、

# git fatal: pathspec archive

が出る場合、

--diff-filter=AMCR

というオプションを付けてやると良いそうです。

この場合例えば、

# git diff --name-only --diff-filter=AMCR HEAD HEAD~2 | xargs git archive --format=zip --prefix=_diff/ HEAD  -o _diff.zip

のような感じで、差分を取ることができます。

———————————————
参考ソース

http://git-scm.com/book/ja/v1/
http://qiita.com/ktaro/items/1d8c8ae698a88b1d6f0f
http://qiita.com/scalper/items/1905b47209989dda5648
http://qiita.com/takoba/items/bcda4c796778ecabe3b1
http://hydrocul.github.io/wiki/commands/xargs.html

ありがとうございました。