.gitignoreに書かずに自分だけ無視するなら.git/info/exclude

  • Git
  • CLI

この記事は、構成と文章の整理にAIを使っています。
あくまで読みやすくするための補助で、内容そのものをAIにすべて任せて書いているわけではありませんが、ところどころ相談しながら整えています。

手元にだけ置いておきたい作業用ディレクトリ(ここでは .example/)を Git に無視させたかった。ただ .gitignore に書くとコミット対象になって、チームの全員に関係ないルールが混ざる。こういうときは .git/info/exclude を使えばいい。

結論

これで済む。

ターミナル
echo ".example/" >> "$(git rev-parse --git-path info/exclude)"

.git/info/exclude は .gitignore と同じ書式で、そのリポジトリのローカルだけに効く。コミットされないので他の人には影響しない。

無視ルールの置き場所

Git の無視ルールは置き場所が複数あって、用途で使い分ける。

置き場所 共有されるか 向いている用途
.gitignore される(コミット対象) ビルド成果物など、プロジェクト全員に共通のもの
.git/info/exclude されない そのリポジトリで自分だけが置くもの
core.excludesFile(既定は ~/.config/git/ignore) されない .DS_Store やエディタ設定など、全リポジトリ共通で自分が無視したいもの

優先順位は次のとおり。上にあるものほど強い。

flowchart TD
    A[コマンドラインで渡したパターン] --> B[.gitignore<br/>対象パスに近いディレクトリほど優先]
    B --> C[.git/info/exclude]
    C --> D[core.excludesFile]

.gitignore 側で ! を使って否定されていると、info/exclude に書いても打ち消されることがある。

なぜ git rev-parse --git-path を使うのか

.git/info/exclude に直接 echo すればいいように見えるけど、これは通常のクローンでしか動かない。

  • worktree(git worktree add で作ったもの)では .git がディレクトリではなく、本体の .git/worktrees/<name> を指すファイルになっている
  • サブモジュールでも .git はファイルで、実体は親リポジトリの .git/modules/<name> にある

この状態で .git/info/exclude に書こうとすると、.git がファイルなのでエラーになる。

git rev-parse --git-path info/exclude は、こういう事情を全部解決したうえで実際のパスを返してくれる。

ターミナル
# 通常のクローン
$ git rev-parse --git-path info/exclude
.git/info/exclude
# worktree の中(info/ は本体と共有なので本体側を指す)
$ git rev-parse --git-path info/exclude
/path/to/main-repo/.git/info/exclude

worktree の場合、info/ は全 worktree で共有されるディレクトリなので、本体側の info/exclude が返る。つまり、ある worktree で追記したルールは他の worktree にも効く。worktree ごとに別々に無視したい用途には使えない。

効かないケース

すでに追跡されているファイル

無視ルールは「まだ追跡されていないファイル」にしか効かない。一度コミットしてしまったものは、インデックスから外す必要がある。

ターミナル
git rm -r --cached .example/

これはインデックスから外すだけで、ファイル自体は消えない。ただしコミット済みのものを外すと、他の人の環境では pull したときに削除として扱われる点に注意。

何度も実行して重複する

>> で追記しているので、実行するたびに同じ行が増える。動作には影響しないけど、スクリプトに組み込むならチェックを入れておく。

ターミナル
f="$(git rev-parse --git-path info/exclude)"
grep -qxF '.example/' "$f" || echo '.example/' >> "$f"

-x で行全体の一致、-F で正規表現ではなく固定文字列として比較している。

既存ファイルの末尾に改行がない

ファイルの最終行が改行で終わっていないと、追記した内容が前の行にくっついて1行になってしまう。git init で作られる info/exclude はコメント行で始まり改行で終わっているので、手で編集していなければ普通は問題ない。

効いているか確認する

git check-ignore -v を使うと、どのファイルの何行目のルールで無視されたかが分かる。

ターミナル
$ git check-ignore -v .example/foo.txt
.git/info/exclude:7:.example/ .example/foo.txt

.gitignore と info/exclude のどちらが効いているのか分からなくなったときにも使える。