件数が合いません。
同じフォルダーを rg --files と自作の CLI に渡したのに、対象になるファイルの一覧が違う。犯人は .gitignore でした——正確には、こちらがそれを読んでいなかったことです。
「ripgrep と同じ規則にする」とは、どこまで同じにすることなのでしょうか。
先に結論: .ignore・.gitignore に ripgrep 15 と同じ規則で従うようにし、rg --files との突き合わせ 43 項目が Mac・Linux・Windows の3つとも一致(不一致 0 件)。ただし .rgignore は読みません
uvf 'logs/**' ERROR のようにワイルドカードで広げたとき、.gitignore や .ignore に当たるファイルは探しません。読むファイル・強さの順番・! の取り消し・親フォルダーまでさかのぼる範囲まで ripgrep 15 に合わせ、rg --files と一覧が一致することを突き合わせで確かめています。合わせなかったのは .rgignore(ripgrep 専用の名前)だけです。Mac(Apple M4・10コア)・メモリ32GB・外付け USB SSD。
uvf・uvpは私が作っている UwView(v1.7.3.6 “Wide Field”・2026年9月28日公開)の検索コマンドです。uvfは無料版、uvpは有料版 UwView Pro のものです。除外の規則は v1.7.2.5 で入れ、v1.7.2.6 で直し、v1.7.3.6 の統合テスト(2026年9月29日)で3つの OS の結果を確認しています。
先に、合わせなかったところを書きます
.rgignoreは読みません。 ripgrep 専用の名前なので、こちらが読むと「ripgrep 用の設定が UwView にも効く」という分かりにくさが残ります。同じ内容が要るなら.ignoreに書いてもらう形にしました。ここは意図的な非互換です。- 細かい止め方は作っていません。
--no-ignore-vcs・--no-ignore-parentなどは未実装です。要望が出たら足します。 --no-ignoreの仕様を一度間違えました。 詳しくは後述しますが、「ripgrep と同じ」と書いた仕様書のほうが誤りで、外部レビューで指摘されて直しました。- 除外の処理そのものの速さは、単独では測っていません。 除外ファイルが1つも無いフォルダーでは判定を素通りさせる設計ですが、「素通りのときに何秒も変わらない」ことを切り出して計測した数字は持っていません。
除外は「対象を減らす機能」ではなく「相手と一致させる機能」
最初、これを性能の機能だと思っていました。node_modules を読まなければ速いだろう、と。
実際に作ってみると、性質がまるで違いました。除外は、同じコマンドを打ったときに ripgrep と同じ答えを返すための機能です。
理由は単純で、除外が違うと件数が違うからです。件数が違えば、どちらが正しいのか読者にもこちらにも分かりません。ベンチマークの土俵そのものが崩れます。速さを比べるには、先に「同じものを探している」ことを保証しなければならない。
だから完了条件も速さではなく、rg --files と uvf --files '**' の一覧が全パターンで一致することに置きました。
読むファイルと、強さの順番
ripgrep 15 が読むのは .gitignore・.ignore・.rgignore・.git/info/exclude・git の全体設定(core.excludesFile)です。こちらは .rgignore を外した4種類を読みます。
強さは後に書いたほうが勝ち、同じ種類なら深いフォルダーのほうが勝つという二段構えです。弱いほうから並べると、こうなります。
| 順 | 読むもの | 備考 |
|---|---|---|
| 弱 | --ignore-file <path> で足したもの |
何回でも書ける。いちばん弱い(ripgrep と同じ) |
| ↓ | git の全体設定(~/.gitconfig の core.excludesFile) |
無ければ ~/.config/git/ignore |
| ↓ | .git/info/exclude |
|
| ↓ | .gitignore |
git のリポジトリの中だけで効く |
| 強 | .ignore |
リポジトリの外でも効く |
.gitignore が「リポジトリの中だけ」なのも ripgrep に合わせた点です。.git フォルダーごと複製していない写しでは .gitignore は効きません。これは実際にテストで引っかかりました。.git の無い写しに .gitignore を置いても、git ではないので読まれない——ripgrep と同じ挙動です。
書き方は gitignore の書式そのままです。*.log(どの深さでも)・/build(直下だけ)・build/(フォルダーだけ)・**/x・!pattern(取り消し)・行末の空白の扱い・\# のエスケープ。親フォルダーが除外されているときは ! で取り消せないという git の癖まで合わせています。照合は自前で書きました(NativeAOT で動かすため、git も外部ライブラリも呼びません)。
名前を書いたファイルは、除外しない
いちばん間違えやすいのがここです。
# build/ が .gitignore に入っていても、これは探す
uvf 'build/app.log' ERROR
# これはワイルドカードなので、除外が効く
uvf 'build/*.log' ERROR
除外が効くのは、ワイルドカードで広げた結果だけ。名指ししたファイルは外しません。ripgrep も同じです。
理由は使う側の意図です。ファイル名まで打った人は「そのファイルを探せ」と言っています。設定ファイルを理由にそれを黙って無視されたら、0 件の理由が分かりません。
同じ考えで、除外のせいで1件も当たらなくなった指定には、その旨を添えます。「(.gitignore などで除外。--no-ignore で含めます)」と出す。黙って 0 件にしない、というだけの話ですが、これが無いと利用者は自分のパターンを疑い続けることになります。
検索の出力そのものには何も足しません(grep・ripgrep と同じく黙って外す)。知らせるのは --files のときと、全部外れたときだけです。
--no-ignore を「ripgrep と同じ」と書いたのは、こちらの誤りでした
自社に都合のいい話ばかりになるので、間違えた箇所を書きます。
仕様書には「--no-ignore は --ignore-file で足したものも止める。ripgrep と同じ」と書いていました。これが誤りでした。 ripgrep 15.2.0 は --no-ignore を付けても --ignore-file の規則は効いたままで、それを止めるのは --no-ignore-files です。
外部レビューで指摘され、ripgrep のほうに合わせました。--no-ignore は .ignore・.gitignore 類だけを止め、--no-ignore-files を新しく作った。突き合わせのテストにも組み合わせ3通りを足して、ripgrep と一致することを確かめています。
「同じにする」と決めた以上、相手の実装が正解です。仕様書に書いた自分の理解ではなく。
束ねた索引との関係——外れた部品は「残すが、探さない」
uvp は複数ファイルを1本の .uwvz(uvp 用の圧縮形式+索引)に束ねます。ここに除外が加わると、同じコマンドでも対象のファイルが変わることになります。索引を作り直すべきでしょうか。
作り直しません。決め方はこうです。
| 状況 | 動き |
|---|---|
| 除外で新しく外れた(ディスクには有る) | 索引の部品は残すが、探さない |
| 除外が外れて新しく入った | 足す(増えたぶんだけ) |
| ディスクから消えた | そのまま索引から探す(Keep) |
--no-ignore で走らせた |
除外されていたものも足す。次に既定で走らせると「残すが探さない」 |
つまり探す対象は「今回広げた一覧+ディスクから消えた部品」です。索引の中身は増えるだけで、設定を変えるたびに作り直しは起きません。
元ファイルが消えても索引を作り直さない(Keep)という決め方が先にあり、除外はその規則の上に一段乗っている形です。
数字——43 項目、3つの OS
正しさの数字です。速さではありません。
| 段 | 内容 | Mac | Linux | Windows |
|---|---|---|---|---|
| itest | .ignore・.gitignore の突き合わせ |
PASS 43/FAIL 0 | PASS 43/FAIL 0 | PASS 43/FAIL 0 |
- 小さなフォルダーの木(
.gitあり/なし・入れ子の.gitignore・.ignore・!・除外フォルダーの中の!・/固定・フォルダーだけ・**・[a-z]・\#・行末の空白・.git/info/exclude・CRLF と BOM・探し始めより上の.ignore)を作り、rg --filesと一覧が一致するかを見ています。既定・--no-ignore・--ignore-fileの3通りで。 - 単体テストは別にあり、書式の1行ずつを見る
IgnoreRulesTestsが 44 件、uvpの索引との関係が 6 件です。 - 項目数は 36 → 42 → 43 と増えています。最初の 36 は開発版での合格で、そこに
--no-ignoreまわりの組み合わせと、実際の配布物での確認を足していった結果です。
Windows で 15 項目が落ちた話
一度、Windows だけ 15 項目が FAIL になりました。原因はテストスクリプトの側です。
Windows の ripgrep は C:/W11Work/…\1net10-code\… のように、パスの区切りに / と \ が混じった形で返します。突き合わせスクリプトが、区切りをそろえる前に対象フォルダー分のパスを削ろうとしていたので、削れずに全部が「ripgrep にだけ出るファイル」に見えていました。
件数そのものは、その15項目でも ripgrep と一致していました。区切りをそろえてから削る順に直して、3つの OS で 43 項目が通っています。
以前の Windows のテスト機には対象のフォルダーが無くてこの部分を飛ばしていたため、初めて表に出た不具合でした。飛ばしていたテストは、合格していたテストではありません。
確かめ方
- 相手: ripgrep 15.2.0(Mac・Windows)/15.1.0(Linux)
- 突き合わせ:
rg --filesとuvf --files '**'/uvp --files '**'の一覧を比較(既定・--no-ignore・--ignore-file) - 版:
uvf・uvpとも v1.7.3.6 “Wide Field”。2026年9月29日の3 OS 統合テスト - 機械: Mac(Apple M4・10コア・メモリ32GB)/外付け USB SSD。Linux は aarch64 の VM、Windows は別の機械
- 秒数は OS をまたいで比べていません。この記事に速さの数字はありません
持ち帰れる一般論
(1)互換性は、機能ではなく答えの一致で定義する。 「.gitignore に対応した」では何も保証できません。保証できるのは「rg --files と一覧が一致する」という形にしたときです。比較できる相手がいるなら、完了条件を相手の出力に合わせる。
(2)仕様書より、相手の実装が正しい。 --no-ignore の誤りは、相手の man ページを読んだつもりで書いた自分の理解が原因でした。「〜と同じ」と書いた行は、すべて実際に突き合わせるまで仮説です。
(3)意図的な非互換は、明示して1つに絞る。 .rgignore を読まないのは仕様です。ただし「だいたい同じです」で済ませると、利用者はどこが違うか永久に分かりません。違う点を数え上げられる状態にしておくほうが、全部同じだと言い張るより信用されます。
(4)飛ばしたテストを、合格と数えない。 Windows の 15 項目は、テスト機にフォルダーが無くて飛んでいた区間でした。緑色の表は、走った項目についてしか何も言っていません。
正直に書いておくこと
- この記事に速さの数字はありません。除外は正しさの機能なので、
PASS 43/FAIL 0以外に主張できる数字を持っていません - 除外の判定が速さに影響しないことは、単独では測っていません。除外ファイルの無いフォルダーで素通りする設計ですが、切り出した計測はしていません
.rgignoreは読みません。--no-ignore-vcs・--no-ignore-parentなどの細かい止め方も未実装です- git の全体設定は
~/.gitconfigの[core]の1行だけを読みます。includeは追いません(限界として書いておきます) --no-ignoreの仕様は一度間違えていました。外部レビューで指摘されて直したものです- Windows と Linux の結果は、正しさの確認としてだけ持ち込んでいます。秒数は OS をまたいで比べません
- 私は比較の一方の開発者です。その分は割り引いてお読みください
使っている道具
UwView は、巨大なテキストファイル・巨大ログを調べるための CLI/GUI ツールです。v1.7.3.6 “Wide Field” では、複数のファイルと7つの圧縮形式を、外部のコマンドなしで1回で探せます。
uvp ならこう書く
# 除外を効かせて探す(既定。.ignore・.gitignore に従う)
uvf 'logs/**' ERROR
# 何が対象になるか、先に確かめる(除外した本数も出る・無料)
uvf 'logs/**' --files
# 除外をしない
uvf 'logs/**' ERROR --no-ignore
# 除外の規則を足す(何回でも書ける・いちばん弱い)
uvf 'logs/**' ERROR --ignore-file ./my-ignore
# --ignore-file で足したものも止める
uvf 'logs/**' ERROR --no-ignore --no-ignore-files
# 名指しは除外されない(.gitignore に build/ があっても探す)
uvf 'build/app.log' ERROR
# 束ねて探す。除外で外れた部品は索引に残るが探さない(UwView Pro)
uvp 'logs/**' ERROR
終了コードは grep と同じで、0=あり・1=なし・2=エラーまたは結果が不完全です。
無料版は GitHub Releases から。Mac は brew install --cask amru195704/uwview/uwview、Windows は Scoop(scoop bucket add uwview https://github.com/amru195704/scoop-uwview → scoop install uwview)でも入ります。
リンク
- 外部コマンドを呼ばずに7形式を探す: https://uvp.y42u.net/blog/uwview-wf02-seven-formats-no-external/
- 圧縮ログの検索を ugrep・ripgrep・zgrep と比べた: https://uvp.y42u.net/blog/uwview-ugrep-ripgrep-zgrep-compressed-logs/
.uwvzを作って、中を探して、取り出す: https://uvp.y42u.net/blog/uwvz-compressed-archive-search-extract/- ログは圧縮したほうが、速く探せます(形式の選び方): https://uvp.y42u.net/blog/log-compression-format-choice/
- 読む回数だけを減らした13回のまとめ: https://uvp.y42u.net/blog/uwview-fl13-first-light-recap/
- 実測の全データ(ベンチマーク一覧): https://uvp.y42u.net/benchmarks/
- ソースコード(GitHub): https://github.com/amru195704/UwView
そして、ストレージを専有している巨大ログを圧縮して保管し、さらに高速に検索したいなら UwView Pro をどうぞ。永続索引・圧縮キャッシュ検索・約 1/9 保管で、開き直しも検索も一段速くなります(全 OS 対応・買い切り/月額プランあり)。
開発者より: アプリ・Kindle 本・公開プロジェクトの一覧は GitHub: amru195704 にまとめています。

