Git 🌙
Chapters â–Ÿ 2nd Edition

8.2 Git のカスタマむズ - Git の属性

Git の属性

蚭定項目の䞭には、パスに察しお指定できるものもありたす。Git はこれらの蚭定を、指定したパスのサブディレクトリやファむルにのみ適甚したす。 これらパス固有の蚭定は、 Git の属性ず呌ばれ、あるディレクトリ 通垞はプロゞェクトのルヌトディレクトリの盎䞋の .gitattributes か、あるいはそのファむルをプロゞェクトずずもにコミットしたくない堎合は .git/info/attributes に蚭定したす。

属性を䜿うず、ファむルやディレクトリ単䜍で個別のマヌゞ戊略を指定したり、テキストファむル以倖の diff を取る方法を指瀺したり、あるいはチェックむンやチェックアりトの前にその内容を Git にフィルタリングさせたりできたす。 このセクションでは、Git プロゞェクトでパスに察しお蚭定できる属性のいく぀かに぀いお孊び、実際にその機胜を䜿う䟋を芋おいきたす。

バむナリファむル

Git の属性を䜿っおできるちょっずした技ずしお、どのファむルがバむナリファむルなのかを (その他の方法で刀別できない堎合のために) 指定した䞊で、 Git に察しおバむナリファむルの扱い方を指瀺するずいうものがありたす。 たずえば、機械で生成したテキストファむルの䞭には diff が取埗できないものがありたすし、バむナリファむルであっおも diff が取埗できるものもありたす。 それを Git に指瀺する方法を玹介したす。

バむナリファむルの特定

テキストファむルのように芋えるファむルであっおも、䜕らかの目的のために意図的にバむナリデヌタずしお扱いたいこずがありたす。 たずえば、Mac の Xcode プロゞェクトの䞭には .pbxproj で終わる名前のファむルがありたす。これは JSON (プレヌンテキスト圢匏の JavaScript のデヌタフォヌマット) のデヌタセットで、IDE がビルドの蚭定などをディスクに曞き出したものです。 このファむルの内容はすべお UTF-8 の文字なので、理論䞊はテキストファむルであるず蚀えたす。しかし、このファむルをテキストファむルずしお扱いたくはありたせん。実際のずころ、このファむルは軜量なデヌタベヌスずしお䜿われおいるからです。他の人が倉曎した内容はマヌゞできたせんし、diff をずっおもあたり意味がありたせん。 このファむルは、基本的に機械が凊理するものなのです。 芁するに、バむナリファむルず同じように扱いたいずいうこずです。

すべおの pbxproj ファむルをバむナリデヌタずしお扱うよう Git に指定するには、次の行を .gitattributes ファむルに远加したす。

*.pbxproj binary

これで、Git が CRLF 問題の察応をするこずもなくなりたすし、git show や git diff を実行したずきにもこのファむルの diff を調べるこずはなくなりたす。

バむナリファむルの差分

バむナリファむルに察しお意味のある差分を取る際にも、Git の属性を䜿うこずができたす。 普通の diff でも比范できるよう、バむナリデヌタをテキストデヌタに倉換する方法をGitに教えればいいのです。

このテクニックを䜿っおたず解決したいこずずいえば、人類にずっお最も厄介な問題のひず぀、Wordで䜜成した文曞のバヌゞョン管理ではないでしょうか。 奇劙なこずに、Wordは最悪の゚ディタだず党おの人が知っおいるにも係わらず、皆がWordを䜿っおいたす。 Word文曞をバヌゞョン管理したいず思ったなら、Gitのリポゞトリにそれらを远加しお、たずめおコミットすればいいのです。しかし、それでいいのでしょうか あなたが git diff をい぀も通りに実行するず、次のように衚瀺されるだけです。

$ git diff
diff --git a/chapter1.docx b/chapter1.docx
index 88839c4..4afcb7c 100644
Binary files a/chapter1.docx and b/chapter1.docx differ

これでは、2぀のバヌゞョンをチェックアりトしお、目芖で芋比べなくおは、比范はできたせんよね Gitの属性を䜿えば、これをうたく解決できたす。 `.gitattributes`に次の行を远加しお䞋さい。

*.docx diff=word

これは、指定したパタヌン (.docx) にマッチした党おのファむルに察しお、差分を衚瀺する時には “word” ずいうフィルタを䜿うよう Git に指瀺しおいるのです。 では、 “word” フィルタずは䜕でしょうか これは自分で甚意しなければなりたせん。 ここでは、 docx2txt を䜿っおWord文曞をテキストファむルに倉換した䞊で、正しく diff が取れるように蚭定しおみたしょう。

たず、 docx2txt をむンストヌルする必芁がありたす。 http://docx2txt.sourceforge.net からダりンロヌドしたら、 INSTALL ファむルの指瀺に埓っお、シェルから芋える堎所にファむルを眮いおください。 次に、出力を Git に合わせお倉換するラッパヌスクリプトを䜜成したす。 パスの通った堎所に、 `docx2txt`ずいう名前のファむルを次の内容で䜜成しおください。

#!/bin/bash
docx2txt.pl $1 -

䜜ったファむルに chmod a+x するのを忘れないでください。 最埌に、Git がこのファむルを䜿うように蚭定したす。

$ git config diff.word.textconv docx2txt

これで、二぀のスナップショットの diff を取る際に、ファむル名の末尟が .docx だったら、 “word” フィルタを通すこの “word” フィルタは docx2txt ずいうプログラムずしお定矩されおいるずいうこずが Git に䌝わりたした。 こうするこずで、Wordファむルの差分を取る際に、より効果的なテキストベヌスでの差分を取るこずができるようになりたす。

䟋を瀺したしょう。この本の第1章をWord圢匏に倉換し、Gitリポゞトリに登録したした。 さらに、新しい段萜を远加したした。 git diff の出力は次のようになりたす。

$ git diff
diff --git a/chapter1.docx b/chapter1.docx
index 0b013ca..ba25db5 100644
--- a/chapter1.docx
+++ b/chapter1.docx
@@ -2,6 +2,7 @@
 This chapter will be about getting started with Git. We will begin at the beginning by explaining some background on version control tools, then move on to how to get Git running on your system and finally how to get it setup to start working with. At the end of this chapter you should understand why Git is around, why you should use it and you should be all setup to do so.
 1.1. About Version Control
 What is "version control", and why should you care? Version control is a system that records changes to a file or set of files over time so that you can recall specific versions later. For the examples in this book you will use software source code as the files being version controlled, though in reality you can do this with nearly any type of file on a computer.
+Testing: 1, 2, 3.
 If you are a graphic or web designer and want to keep every version of an image or layout (which you would most certainly want to), a Version Control System (VCS) is a very wise thing to use. It allows you to revert files back to a previous state, revert the entire project back to a previous state, compare changes over time, see who last modified something that might be causing a problem, who introduced an issue and when, and more. Using a VCS also generally means that if you screw things up or lose files, you can easily recover. In addition, you get all this for very little overhead.
 1.1.1. Local Version Control Systems
 Many people's version-control method of choice is to copy files into another directory (perhaps a time-stamped directory, if they're clever). This approach is very common because it is so simple, but it is also incredibly error prone. It is easy to forget which directory you're in and accidentally write to the wrong file or copy over files you don't mean to.

Gitは、远加した “Testing: 1, 2, 3.” ずいう正しい文字列を銖尟よく、か぀、簡朔に知らせおくれたした。 これだけでは完璧ではありたせん曞匏の倉曎はここでは衚瀺されおいたせんが、確実に動䜜しおいたす。

その他の興味深い問題ずしおは、画像ファむルの差分がありたす。 ひず぀の方法ずしお、EXIF情報倚くのファむル圢匏で䜿甚されおいるメタデヌタを抜出するフィルタを䜿う方法がありたす。 exiftool`をダりンロヌドしおむンストヌルすれば、画像デヌタを、メタデヌタを衚すテキストデヌタぞ倉換できたす。これによっお、 diff では少なくずも、倉曎内容をテキスト圢匏で衚瀺できるようになりたす。 ではここで、以䞋の行を.gitattributes`に远加しおみたしょう。

*.png diff=exif

続いお、さきほどむンストヌルしたツヌルを䜿うようGitの蚭定を倉曎したす。

$ git config diff.exif.textconv exiftool

プロゞェクト䞭の画像デヌタを眮き換えお git diff を実行するず、次のように衚瀺されるでしょう。

diff --git a/image.png b/image.png
index 88839c4..4afcb7c 100644
--- a/image.png
+++ b/image.png
@@ -1,12 +1,12 @@
 ExifTool Version Number         : 7.74
-File Size                       : 70 kB
-File Modification Date/Time     : 2009:04:21 07:02:45-07:00
+File Size                       : 94 kB
+File Modification Date/Time     : 2009:04:21 07:02:43-07:00
 File Type                       : PNG
 MIME Type                       : image/png
-Image Width                     : 1058
-Image Height                    : 889
+Image Width                     : 1056
+Image Height                    : 827
 Bit Depth                       : 8
 Color Type                      : RGB with Alpha

ファむルのサむズず画像のサむズが倉曎されたこずが簡単に芋お取れたす。

キヌワヌド展開

SubversionやCVSを䜿っおいた開発者から、キヌワヌド展開機胜をリク゚ストされるこずがよくありたす。 ここでの䞻な問題は、Git では、コミットの埌に、コミットに関する情報を䜿っおファむルを倉曎するこずはできないずいうこずです。これは、Git がコミットの最初にファむルのチェックサムを生成するためです。 しかし、ファむルをチェックアりトする際にテキストを挿入し、コミットぞ远加する際にそれを削陀するこずは可胜です。 Gitの属性はこれを行うための方法を2぀提䟛したす。

ひず぀めの方法ずしお、ファむルの $Id$ フィヌルドぞ、 blob の SHA-1 チェックサムを自動的に挿入できたす。 あるファむル、もしくはいく぀かのファむルに察しおこの属性を蚭定すれば、次にそのブランチをチェックアりトする時、Gitはこの眮き換えを行うようになりたす。 ただし、挿入されるチェックサムはコミットに察するものではなく、察象ずなるblobのものであるずいう点に泚意しお䞋さい。 ではここで、以䞋の行を`.gitattributes`に远加しおみたしょう。

*.txt ident

続いお、`$Id$`ぞの参照をテスト甚ファむルに远加したす。

$ echo '$Id$' > test.txt

そうするず、次にこのファむルをチェックアりトする時、GitはblobのSHA-1チェックサムを挿入したす。

$ rm test.txt
$ git checkout -- test.txt
$ cat test.txt
$Id: 42812b7653c7b88933f8a9d6cad0ca16714b9bb3 $

しかし、この結果はあたり圹に立ちたせん。 CVSやSubversionのキヌワヌド展開ではタむムスタンプを含めるこずができたす。察しお、SHA-1チェックサムは完党にランダムな倀ですから、2぀の倀の新旧を知るための助けにはなりたせん。

これには、コミットおよびチェックアりトの時にキヌワヌド展開を行うフィルタを曞いおやれば察応できたす。 このフィルタは “clean” および “smudge” フィルタず呌ばれたす。 .gitattributes ファむルで、特定のパスにフィルタを蚭定し、チェックアりトの盎前 “smudge” 、 チェックアりトする時に “smudge” フィルタを実行する を参照およびステヌゞングの盎前 “clean” 、 ステヌゞングする時に “clean” フィルタを実行する を参照に凊理を行うスクリプトを蚭定できたす。 これらのフィルタは、色々ず面癜いこずに䜿えたす。

チェックアりトする時に ``smudge'' フィルタを実行する
図 143. チェックアりトする時に “smudge” フィルタを実行する
ステヌゞングする時に ``clean'' フィルタを実行する
図 144. ステヌゞングする時に “clean” フィルタを実行する

この機胜に察しおオリゞナルのコミットメッセヌゞは簡単な䟋を䞎えおくれおいたす。それはコミット前にCの゜ヌスコヌドを indent プログラムに通すずいうものです。 *.c ファむルに察しおこのフィルタを実行するように、`.gitattributes`ファむルにfilter属性を蚭定できたす。

*.c filter=indent

それから、smudgeずcleanで “indent” フィルタが䜕を行えばいいのかをGitに教えたす。

$ git config --global filter.indent.clean indent
$ git config --global filter.indent.smudge cat

このケヌスでは、 *.c にマッチするファむルをコミットした時、Gitはステヌゞング前にindentプログラムにファむルを通し、チェックアりトする前には cat を通すようにしたす。 cat`は基本的に䜕もしたせん。入力されたデヌタず同じデヌタを吐き出すだけです。 この組み合わせを䜿えば、Cの゜ヌスコヌドのコミット前に、効果的に `indent を通せたす。

もうひず぀の興味深い䟋ずしお、RCSスタむルの $Date$ キヌワヌド展開がありたす。 これを正しく行うには、ファむル名を受け取り、プロゞェクトの最新のコミットの日付を芋お、その日付をファむルに挿入するちょっずしたスクリプトが必芁になりたす。 これを行うRubyスクリプトを以䞋に瀺したす。

#! /usr/bin/env ruby
data = STDIN.read
last_date = `git log --pretty=format:"%ad" -1`
puts data.gsub('$Date$', '$Date: ' + last_date.to_s + '$')

このスクリプトは、git log コマンドの出力から最新のコミットの日付を取埗し、暙準入力䞭のすべおの $Date$ 文字列にその日付を远加し、結果を出力したす。お気に入りのどんな蚀語で曞くにしおも、簡単なスクリプトになるでしょう。 このスクリプトファむルに`expand_date`ず名前を぀け、実行パスのどこかに眮きたす。 次に、Git にフィルタここでは dater`ずしたすを蚭定し、チェックアりト時に smudge で `expand_date フィルタを䜿うように指定したす。 コミット時に日付を削陀するのには、 Perl の正芏衚珟が䜿えたす。

$ git config filter.dater.smudge expand_date
$ git config filter.dater.clean 'perl -pe "s/\\\$Date[^\\\$]*\\\$/\\\$Date\\\$/"'

このPerlのスニペットは、 $Date$ 文字列の内偎にある内容を削陀し、日付を挿入する前の状態に戻したす。 さお、フィルタの準備ができたした。このファむルが新しいフィルタに匕っかかるように Git の属性を蚭定し、ファむルに $Date$ キヌワヌドを远加した䞊で、テストしおみたしょう。

date*.txt filter=dater
$ echo '# $Date$' > date_test.txt

これらの倉曎をコミットしお、再床ファむルをチェックアりトすれば、キヌワヌドが正しく眮き換えられおいるのがわかりたす。

$ git add date_test.txt .gitattributes
$ git commit -m "Testing date expansion in Git"
$ rm date_test.txt
$ git checkout date_test.txt
$ cat date_test.txt
# $Date: Tue Apr 21 07:26:52 2009 -0700$

アプリケヌションのカスタマむズにあたり、このテクニックがどれほど匷力か、おわかりいただけたず思いたす。 しかし、泚意しおほしいのですが、 .gitattributes ファむルはコミットされおプロゞェクト内で共有されたすが、ドラむバこのケヌスで蚀えば、daterそうはそうはいきたせん。そのため、この機胜はどこででも働くわけではありたせん。 フィルタを蚭蚈する時には、たずえフィルタが正垞に動䜜しなかったずしおも、プロゞェクトは適切に動き続けられるようにすべきです。

リポゞトリを゚クスポヌトする

あなたのプロゞェクトのアヌカむブを゚クスポヌトする時には、Gitの属性デヌタを䜿っお興味深いこずができたす。

export-ignore

アヌカむブを生成するずき、特定のファむルやディレクトリを゚クスポヌトしないように蚭定できたす。 プロゞェクトにはチェックむンしたいが、アヌカむブファむルには含めたくないディレクトリやファむルがあるなら、それらに export-ignore 属性を蚭定するこずで、分別が行えたす。

䟋えば、プロゞェクトを゚クスポヌトする際に tarball に含めたくないテストファむルが、 `test/`ディレクトリ以䞋に入っおいるずしたしょう。 その堎合、次の1行をGitの属性ファむルに远加したす。

test/ export-ignore

これで、プロゞェクトのtarballを䜜成するために git archive を実行した時、アヌカむブには test/ ディレクトリが含たれないようになりたす。

export-subst

デプロむ甚にファむルを゚クスポヌトする際に、export-subst 属性の぀いたファむルを指定しお git log のログ曞匏指定機胜ずキヌワヌド展開機胜で生成した内容をファむルに付䞎できたす。 䟋えば、LAST_COMMIT`ずいう名前のファむルをプロゞェクトに远加し、`git archive`を実行した時にそのファむルのメタデヌタを最新コミットず同じ内容に倉換したい堎合、.gitattributes`ファむルず`LAST_COMMIT`ファむルを 次のように蚭定したす。

LAST_COMMIT export-subst
$ echo 'Last commit date: $Format:%cd by %aN$' > LAST_COMMIT
$ git add LAST_COMMIT .gitattributes
$ git commit -am 'adding LAST_COMMIT file for archives'

git archive を実行するず、 LAST_COMMIT は以䞋のような内容になっおいるはずです。

$ git archive HEAD | tar xCf ../deployment-testing -
$ cat ../deployment-testing/LAST_COMMIT
Last commit date: Tue Apr 21 08:38:48 2009 -0700 by Scott Chacon

このような眮換に、コミットメッセヌゞや git note を甚いるこずもできたす。その際、git log コマンドのワヌドラップ凊理が適甚されたす。

$ echo '$Format:Last commit: %h by %aN at %cd%n%+w(76,6,9)%B$' > LAST_COMMIT
$ git commit -am 'export-subst uses git log's custom formatter

git archive uses git log's `pretty=format:` processor
directly, and strips the surrounding `$Format:` and `$`
markup from the output.
'
$ git archive @ | tar xfO - LAST_COMMIT
Last commit: 312ccc8 by Jim Hill at Fri May 8 09:14:04 2015 -0700
       export-subst uses git log's custom formatter

         git archive uses git log's `pretty=format:` processor directly, and
         strips the surrounding `$Format:` and `$` markup from the output.

この結果䜜成されたアヌカむブはデプロむするのにぎったりです。䞀方、いったん゚クスポヌトされおしたったアヌカむブで開発を続けるのはおすすめできたせん。

マヌゞの戊略

Gitの属性を䜿えば、プロゞェクト䞭の特定のファむルに察しお、異なるマヌゞ戊略を䜿うこずもできたす。 非垞に有甚なオプションのひず぀に、指定したファむルで競合が発生した堎合に、マヌゞを行わずに、あなたの倉曎内容で他の誰かの倉曎を䞊曞きするように蚭定するずいうものがありたす。

これはプロゞェクトにおいお、分岐したブランチや、特別版のブランチで䜜業をしおいる時、そのブランチでの倉曎をマヌゞさせたいが、特定のファむルの倉曎はなかったこずにしたいずいうような時に助けになりたす。 䟋えば、 database.xml ずいうデヌタベヌスの蚭定ファむルがあり、ふた぀のブランチでその内容が異なっおいるずしたしょう。そしお、そのデヌタベヌスファむルを台無しにするこずなしに、䞀方のブランチぞずマヌゞしたいずしたす。 これは、次のように属性を蚭定すれば実珟できたす。

database.xml merge=ours

その䞊で、ダミヌのマヌゞ戊略 ours を次のように定矩したす。

$ git config --global merge.ours.driver true

もう䞀方のブランチでマヌゞを実行するず、 database.xml に関する競合は発生せず、次のような結果になりたす。

$ git merge topic
Auto-merging database.xml
Merge made by recursive.

この堎合、 database.xml は元々のバヌゞョンのたた、曞き倉わりたせん。

scroll-to-top