ファイル属性
.gitattributes は、git の中で最も価値が高いのにほとんど誰も書かないファイルです。
これはリポジトリが git に自分自身の中身を教える 手段です。どのファイルが
バイナリなのか、どれはコンフリクトさせずに連結すべきなのか、どれはアーカイブに
含めてはいけないのか、全員がどの改行コードを受け取るのか。
肝心なのは、これがコミットされることです。ここに追加したルールは、クローンする すべての人の、あらゆる OS 上の問題を、永久に解決します。自分の設定ファイルに 書いた設定とは違います。あちらは自分だけを救い、同僚には痛い目を見て気づいて もらうことになります。
⌘K → ファイル属性。

ルールが何をするか
| 属性 | 直すもの |
|---|---|
text=auto eol=lf |
誰がチェックアウトしたかで揺れる改行コード |
binary |
git が PSD や DOCX、コンパイル済みアセットを差分表示したり3方向マージしようとすること |
merge=union |
全員が追記し、全員がコンフリクトする変更履歴ファイル |
-merge |
3方向マージが無意味な結果を生むファイル — ロックファイル、生成コード |
export-ignore |
リリース用の tarball に同梱されてしまう CI 設定やフィクスチャ |
diff=<driver> |
コンバータさえあれば 読める 形式なのに、読めない差分 |
filter=lfs |
LFS 経由で保存される大きなファイル |
linguist-vendored |
言語統計で自分のコードとして数えられてしまうベンダリング済みコード |
binary は -diff -merge -text の省略形で、「このファイルについて推測するのは
やめてくれ」への3つの答えを1語にまとめたものです。
編集
プリセットはパターンとその属性を埋めてくれます。追加する前にパターンは編集して
ください — CHANGELOG.md は提案であって、あなたのプロジェクトについての決まりでは
ありません。
編集は外科的です。 すでにルールがあるパターンにルールを追加すると、あとに 書かれたほうが勝つ2つ目のルールを末尾に足すのではなく、その行をその場で書き換え ます。ファイル内のコメントはそのまま残ります。ルールの隣にある「なぜ」は、 たいていルールそのものより価値があるからです。
保存はすべて通常の Gitcito のアクションです。トーストが出て、取り消し で ファイルは元のとおりに復元されます。
リポジトリは複数の属性ファイルを持てます。 ルートに1つ、任意のサブ
ディレクトリに1つ、そして決してコミットされず自分のマシンでだけ効く
.git/info/attributes — プロジェクトではなく自分についてのルールを置くべき場所
です。Gitcito はそのすべてを一覧し、どれがどれかを示します。
このパスには何が適用されるのか
ルールは複数のファイルから来て、より具体的なほうが勝ち、それを読んで答えを
割り出すのは当て推量です。このパスには何が適用されるのか は git check-attr
を実行し、git 自身の結論を表示します — 意味を持つ唯一の答えです。
差分ドライバ: Word 文書を読めるようにする
.docx は zip です。.pdf は圧縮されたオブジェクトグラフです。git はそれらを
そのままのもの — ノイズ — として差分表示するので、文書自体は読めるのに、その
履歴は読めません。
差分ドライバ は textconv でこれを解決します。差分表示のためだけに
ファイルをテキストへ変換するコマンドです。作業ツリーのファイルには手を触れず、
git は変換後のテキストを比較するだけです。
半分が2つあり、両方が必要です。
- git config の
diff.<name>.textconv— 変換コマンド。 .gitattributesの*.docx diff=<name>— どのファイルに適用するか。
ここのボタンは両方を一度に行います。Word・Excel・JSON・.strings については、Gitcito が
コンバータ自体を同梱しています — プレビューが使うのと同じドキュメント解析
を、アプリ内の小さな gitcito-textconv コマンドとして公開したもので、この
4 つは何もインストールせずに動きます。残りは引き続き PATH 上の本物のツールが
必要です。Gitcito はそれを確認し、最初の差分で失敗するドライバを書く代わりに、
足りないものをグレーアウトします。
| ドライバ | 必要なもの | 得られるもの |
|---|---|---|
word |
なし — Gitcito に同梱 | .docx の文章としての差分 |
excel |
なし — Gitcito に同梱 | .xlsx/.xls の行単位の差分(シートごとの CSV) |
json |
なし — Gitcito に同梱 | キー順に並んだ、安定した JSON の差分 |
strings |
不要 — Gitcito に同梱 | git がバイナリと呼ぶ UTF-16 の .strings を行単位で差分表示 |
pdf |
pdftotext(poppler) |
.pdf のテキスト差分 |
exif |
exiftool |
ピクセルが不透明なとき、画像の何が変わったか |
iOS プロジェクトで実際に噛みつくもの
Localizable.strings は Xcode の歴史のほとんどで UTF-16 であり、UTF-16 は NUL
バイトだらけです。そのため git はこれをバイナリと呼び、何も表示しません。
diff --git a/Localizable.strings b/Localizable.strings
Binary files a/Localizable.strings and b/Localizable.strings differ
誰がどの文字列を動かしたかを見たい度合いが最も高いのは、まさにこのファイルです。
strings ドライバは差分のためだけにデコードします — バイト順マークを決めつけず
に読むので、最近の UTF-8 の .strings は文字化けせずそのまま通ります。
String Catalog(.xcstrings、Xcode 15 以降)は JSON なので json ドライバが
カバーします。キーを並べ替えるため、先頭に追加した翻訳が差分でファイル全体を
書き換えたように見えることがなくなります。
同梱コンバータの限界を率直に述べておきます。.doc(旧来のバイナリ Word 形式)
は理解できず、.docx のみです。PDF は対象外です — Gitcito は PDF をブラウザの
ビューアでプレビューしており、流用できるテキスト抽出器を持ちません。また、
ドキュメントの差分のたびにコンバータの短い起動コストがかかります。
git config diff.<name>.cachetextconv true を設定すると、git は出力を blob
ごとにキャッシュします。
コンバータ側は あなたの 設定に置かれ、リポジトリには入りません。git は
クローンが渡してくるコマンドを実行しません。これは保っておく価値のあるセキュリティ
上の性質です。また、同梱ドライバは あなたの Gitcito のインストールパスを
指しています。したがってクローンした同僚は diff=word のルールを受け取り、
自分のコンバータ(Gitcito でも他のものでも)をつなぐまでは相変わらず読めない
差分を見ることになります。README にそう書いておきましょう。
clean/smudge フィルタ — まずドライランを
フィルタ は、リポジトリに出入りする内容をその途中で書き換えます。clean
はステージング時(作業ツリー → リポジトリ)に、smudge はチェックアウト時
(リポジトリ → 作業ツリー)に走ります。git-lfs はこの仕組みで動いており、
チームが認証情報や生成されたノイズをコミット内容から取り除くのもこの方法です。
同時に、これは .gitattributes が指し示せるもののうち最も危険なものでも
あります。フィルタは 一致するすべてのファイルの、あらゆるチェックアウトの
たびに 走り、間違ったフィルタは作業ツリーを黙って壊します。だから Gitcito
はここをただのテキストボックスにはしません。フィルタの設定は、リポジトリ内の
実際に一致するファイルに対する ドライラン を通ります。
cleanコマンドは、一致する各ファイル(最大 5 つ)のコピーに対して実行 されます — リポジトリにもその設定にも、何も手は触れません。smudgeコマンドが与えられていれば、clean済みの出力に対して実行され、 その結果が元のファイルとバイト単位で比較されます — ラウンドトリップ検査 です。ラウンドトリップしないフィルタは、チェックアウトしても元にあったもの が戻らないということです。- 保存ボタンが有効になるのは、まさに保存しようとしている値そのもので ドライランを済ませたあとだけです。失敗したドライラン — コマンドのエラー、 一致なし、ラウンドトリップの不一致 — でも保存はできますが、何が失われうるか を述べた明示的な警告を通ってのみです。
保存すると filter.<name>.clean/smudge が ローカル の git 設定に、
filter=<name> のルールが属性ファイルに書き込まれ、設定が以前保持していた
内容を復元する取り消しエントリが残ります。required トグルは
filter.<name>.required を設定します。フィルタが壊れたとき、git はファイルを
黙って素通しにする代わりに操作を失敗させるようになります。
限界を率直に述べておきます。ドライランは一致するファイルを最大 5 つ、各
5 MB までサンプリングし、コマンドごとに 10 秒のタイムアウトがあります —
サンプルでは行儀のよいフィルタも、サンプルから漏れたファイルでは暴れる
ことがあります。コマンドは あなたの 設定に置かれるので、クローンした同僚は
filter=<name> のルールは受け取りますが、コマンドは受け取りません。コマンド
がなければ(そして required がなければ)、その人のファイルはそのまま素通し
になります。
知っておくべき制限
text=autoはコミットされる内容を変えます。入るときに改行コードを正規化 するからです。既存のリポジトリでは、追加したうえでgit add --renormalize .を意図的に、それだけの単独のコミットとして実行して ください。- 属性はさかのぼって適用されません。 今日あるファイルを
binaryにしても、 過去の差分の保存され方は変わりません。変わるのは、これ以降 git がそれをどう 扱うかです。 - ルールはそのファイルから見える範囲でしか効きません。
design/.gitattributesのルールはsrc/について何も言っていません。 - Gitcito はファイル全体を書き出すので、手で整形したファイルはその整形のまま
戻ってきます — ただし Gitcito が書き換えたルールは、git の正規形である
pattern attr attrの間隔に整形し直されます。
関連項目: LFS とスパースチェックアウト · バンドルとアーカイブ · マージオプション · フック