結論
ripgrep は、.gitignore などに書かれたファイルを黙って探しません。自作の検索 CLI に同じ規則を入れるため、rg --files の一覧と自分の CLI の一覧が一致するかを、43項目のテストで Mac・Linux・Windows の3つとも確かめました(不一致 0 件)。
その途中で分かった、ripgrep の除外の「効き方」を先にまとめます。どれも下の再現手順で確かめられます。
| # | 決まり | 確かめ方 |
|---|---|---|
| 1 | 強さは .ignore > .gitignore > .git/info/exclude > git の全体設定 > --ignore-file。同じ種類なら深いフォルダーが勝つ
|
.ignore の !a.log が .gitignore の a.log に勝つ |
| 2 |
.gitignore は git のリポジトリの中だけで効く(.ignore はどこでも効く) |
.git の無いフォルダーでは無視される。--no-require-git で効く |
| 3 | 名前を書いたファイル・フォルダーは除外しない |
rg --files build/a.log は build/ が除外でも出る |
| 4 |
--no-ignore は --ignore-file を止めない。止めるのは --no-ignore-files
|
--no-ignore だけでは --ignore-file の規則が残る |
| 5 |
除外したフォルダーの中は ! で戻せない(git と同じ) |
e/ と !e/keep/z.log を並べても z.log は出ない |
| 6 |
--ignore-file はいちばん弱い。そこに書いた ! は .gitignore の除外を覆せない |
--ignore-file の !b.log は効かない |
| 7 | 探し始めより上のフォルダーの除外も効く(.gitignore はリポジトリの根まで) |
d/sub で動かしても、根の .gitignore が効く |
なぜそうなっているのかは、rg --files --debug で1件ずつ確かめられます(後述)。
以下、それぞれの中身と、「同じ規則にした」をどう確かめたかを書きます。
前提:除外は「速さ」ではなく「件数」の問題
最初は、除外を性能の機能だと思っていました。node_modules を読まなければ速い、と。
作ってみると、性質が違いました。除外が違うと、件数が違います。 件数が違えば、どちらが正しいのか誰にも分かりません。速さを比べる前に、「同じものを探している」ことを保証しないといけない。
そこで完了条件を、速さではなく rg --files と自分の CLI の --files の一覧が全パターンで一致することに置きました。
1. 読むファイルと、強さの順番
ripgrep が読むのは .rgignore・.ignore・.gitignore・.git/info/exclude・git の全体設定(core.excludesFile、無ければ ~/.config/git/ignore)と、--ignore-file で渡したファイルです。
強さは二段構えです。種類で順番が決まり、同じ種類なら深いフォルダーが勝つ。 弱いほうから並べるとこうなります。
| 順 | 読むもの | 備考 |
|---|---|---|
| 弱 | --ignore-file <path> |
何回でも書ける。いちばん弱い |
| ↓ | git の全体設定 |
~/.gitconfig の core.excludesFile
|
| ↓ | .git/info/exclude |
|
| ↓ | .gitignore |
git のリポジトリの中だけ |
| ↓ | .ignore |
リポジトリの外でも効く |
| 強 | .rgignore |
ripgrep 専用の名前 |
書式は gitignore と同じです。*.log(どの深さでも)・/build(その除外ファイルの直下だけ)・build/(フォルダーだけ)・**・[a-z]・!pattern(取り消し)・\#・行末の空白。
--ignore-file が「いちばん弱い」というのは、そこに !b.log と書いても、.gitignore の b.log を覆せないということです。逆に .ignore の !a.log は .gitignore の a.log に勝ちます。
2. .gitignore は git のリポジトリの中だけで効く
ここは実際にテストで引っかかりました。.git フォルダーごと複製していない写しに .gitignore を置いても、ripgrep は読みません。
mkdir norepo && cd norepo
mkdir build && touch a.log build/b.log
echo 'build/' > .gitignore
rg --files # a.log と build/b.log の両方が出る(git ではないので読まない)
rg --files --no-require-git # a.log だけ
「どこでも効かせたい」なら .ignore に書きます。こちらはリポジトリの外でも効きます。
3. 名前を書いたファイル・フォルダーは除外しない
いちばん間違えやすいところです。除外が効くのは、たどって見つけたファイルだけで、引数で名指ししたものは外しません。
# .gitignore に build/ と *.tmp があっても
rg --files build/a.log x.tmp # build/a.log と x.tmp が出る
rg --files build # build/a.log が出る(名指ししたフォルダーの中は規則で見る)
ファイル名まで打った人は「そのファイルを探せ」と言っています。設定ファイルを理由に黙って無視されたら、0 件の理由が分かりません。
自分の CLI ではワイルドカードを自前で広げるので、「広げた結果には除外を効かせる・名指しのファイルには効かせない・先頭に書いたフォルダー('build/**' の build)は外さない」と決めて、rg に build/ を渡したときと同じ一覧になるようにしました。
4. --no-ignore は --ignore-file を止めない
ここはこちらが一度間違えました。 仕様書に「--no-ignore は --ignore-file で足した規則も止める。ripgrep と同じ」と書いて実装し、外部のレビューで誤りだと指摘されました。
echo extra.log > ../extra.ignore
rg --files --no-ignore --ignore-file ../extra.ignore
# → .gitignore・.ignore の除外は外れるが、extra.log は出ない(--ignore-file は効いたまま)
rg --files --no-ignore --no-ignore-files --ignore-file ../extra.ignore
# → extra.log も出る
--no-ignore が止めるのは .ignore・.gitignore・.git/info/exclude・全体設定の類で、--ignore-file を止めるのは --no-ignore-files です。こちらも ripgrep に合わせて --no-ignore-files を足し、突き合わせのテストに組み合わせ3通り(既定・--no-ignore・--ignore-file)を入れました。
「〜と同じ」と書いた行は、突き合わせるまで仮説です。 man ページを読んだつもりでも、自分の理解のほうが間違っていることがあります。
5. 除外したフォルダーの中は ! で戻せない
e/
!e/keep/z.log
と書いても、e/keep/z.log は出ません。git と同じで、親フォルダーが除外されていると、その中は見に行かないからです。戻したいなら、フォルダーではなく中身を除外する書き方(e/* + !e/keep/ …)にします。
自分で照合を書くと、ここを「! は後勝ち」の一般則で処理してしまい、戻ってしまいがちです。除外したフォルダーは中を見ない、という順番で作るのが確実でした(大きな node_modules を読まずに済むので速くもなります)。
6. 探し始めより上の除外も効く
cd d/sub
rg --files # 根の .gitignore に y.log があれば、d/sub/y.log は出ない
.gitignore はリポジトリの根まで、.ignore はさらに上までさかのぼって読みます。「今のフォルダーの除外ファイルだけ見る」実装だと、ここで一覧がずれます。
理由を1件ずつ見る:rg --files --debug
一覧が合わないとき、いちばん役に立ったのがこれです。
$ rg --files --debug 2>&1 | grep -E 'ignoring|whitelisting'
... ignoring ./b.log: Ignore(IgnoreMatch(Gitignore(Glob { from: Some("./.gitignore"), original: "b.log", ...
... whitelisting ./a.log: Whitelist(IgnoreMatch(Gitignore(Glob { from: Some("./.ignore"), original: "!a.log", ...
どのファイルの、どの行で外れた(戻った)かが出ます。自分の実装とずれた項目は、まずここで ripgrep の判断を確かめてから直しました。
「同じ規則にした」をどう確かめたか
やり方
小さなフォルダーの木をテストごとに作り、rg --files と自分の CLI の --files の一覧を並べ替えて比べるだけです。
#!/usr/bin/env bash
# 使い方: ./cmp-files.sh 比べるフォルダー (MYCLI に自分の CLI を入れておく)
set -u
D=${1:?フォルダーを指定}; MYCLI=${MYCLI:-mycli}
norm() { tr '\\' '/' | sed 's#^\./##' | sort; } # 区切りをそろえてから比べる
for opt in "" "--no-ignore" "--ignore-file ../extra.ignore"; do
a=$(cd "$D" && rg --files $opt | norm)
b=$(cd "$D" && $MYCLI --files '**' $opt | norm)
if [ "$a" = "$b" ]; then echo "PASS [$opt]"
else echo "FAIL [$opt]"; diff <(echo "$a") <(echo "$b"); fi
done
作った木は次のようなものです。.git あり/なし、入れ子の .gitignore、.ignore、!、除外フォルダーの中の !、/ で固定、フォルダーだけ、**、[a-z]、\#、行末の空白、.git/info/exclude、CRLF と BOM の除外ファイル、探し始めより上の .ignore。これに3通りのオプションを掛けて、43項目になりました(項目数は 36 → 42 → 43 と、間違いを見つけるたびに増えています)。
結果
| Mac | Linux | Windows | |
|---|---|---|---|
rg --files との突き合わせ |
PASS 43/FAIL 0 | PASS 43/FAIL 0 | PASS 43/FAIL 0 |
書式の1行ずつを見る単体テストは別に 44 件あります。
Windows だけ 15 項目落ちた
一度、Windows だけ 15 項目が FAIL になりました。原因はテストスクリプトの側でした。
Windows の ripgrep は、C:/W11Work/…\1net10-code\… のように、/ と \ が混じったパスを返すことがありました。スクリプトが区切りをそろえる前に対象フォルダー分のパスを削ろうとしていたので、削れずに、全部が「ripgrep にだけ出るファイル」に見えていました。件数そのものは一致していました。
上のスクリプトの norm で、区切りをそろえてから比べるのはそのためです。もう1つの教訓は、以前の Windows のテスト機にはこのフォルダーが無く、この区間を飛ばしていたことです。飛ばしたテストは、合格したテストではありません。
合わせなかったところ
-
.rgignoreは読みません。 ripgrep 専用の名前なので、自分の CLI が読むと「ripgrep 用の設定が別の道具にも効く」という分かりにくさが残ります。同じ内容が要るなら.ignoreに書いてもらう形にしました。意図的な非互換です。 --no-ignore-vcs・--no-ignore-parentなどの細かい止め方は作っていません。-
git の全体設定は
~/.gitconfigの[core]のexcludesFileだけを読み、includeは追いません。
違うところを数え上げられる状態にしておくほうが、「だいたい同じです」と言うより使う側は困りません。
確認の条件
- ripgrep 15.2.0(Mac・Windows)/15.1.0(Linux)。この記事の各コマンドの出力は、ripgrep 15.1.0(Linux x86_64)で 2026-10-01 に確かめ直したもの
- 自分の CLI は C#(.NET・NativeAOT)。照合は git や外部ライブラリを呼ばずに自前で書いた
- 突き合わせは 2026-09-29 に3つの OS で実施(Mac は Apple M4、Linux は aarch64 の VM、Windows は別の機械)
- この記事に速さの数字はありません。除外の判定そのものの速さは、切り出して測っていません
まとめ
- ripgrep の除外は「種類の強さ」と「深さ」の二段構え。
--ignore-fileがいちばん弱く、.gitignoreはリポジトリの中だけ、名指しは除外しない、除外したフォルダーの中は戻せない。 -
--no-ignoreで--ignore-fileは止まらない。--no-ignore-filesが要る。 - 互換性は「対応した」ではなく、相手の出力と一致したで定義する。ずれたら
rg --files --debugで相手の判断を見る。 - パスの区切りは、比べる前にそろえる。飛ばしたテストを合格と数えない。
題材にした CLI(UwView の uvf・uvp)で同じ除外を使う例と、束ねた索引との関係はこちらに書きました: https://uvp.y42u.net/blog/uwview-wf07-ignore-rules/