0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

なぜ .claude/settings.local.json はGit管理してはいけないのか

0
Posted at

はじめに

Claude Code を使っていると、.claude/settings.local.json というファイルが増えていきます。
コマンド実行時の確認ダイアログで「Yes, and don't ask again」を選ぶたびに、許可ルールが自動で追記されていくファイルです。

このファイルは Git の追跡対象に入れてはいけません。名前のとおり「各自のローカル環境固有の設定」だからです。

とはいえ、普段はあまり意識しないはずです。

Claude Code 自身がこのファイルに設定を保存するとき、リポジトリがまだ無視していなければ、グローバルの git excludes ファイルに **/.claude/settings.local.json を自動で追記してくれます。
除外先は、グローバル git 設定の core.excludesFile が絶対パスまたは ~ 始まりで指定されていればそのファイル、そうでなければ $XDG_CONFIG_HOME/git/ignore または ~/.config/git/ignore になります。

問題になるのは、この自動処理が働かないケースです。

  • 手でファイルを作った場合
  • Claude に Write ツールで書かせた場合
  • 既存のリポジトリを引き継いだら、なぜか追跡対象に入っていた場合

公式ドキュメントも、これらの場合は自分で gitignore に追加するよう明記しています。

では、追跡対象に入っていると具体的に何が起きるのか。この記事では2つの理由に整理して解説します。


問題

そもそも2つのファイルがある

Claude Code の権限設定ファイルは、用途によって分かれています。

ファイル 想定用途 Git
.claude/settings.json チームで共有する設定 コミットする
.claude/settings.local.json 自分だけの設定 コミットしない

settings.local.json は、人が手で書くというより、確認ダイアログでの承認操作の結果として Claude Code が自動生成・自動追記していくファイルです。

.claude/settings.local.json
{
  "permissions": {
    "allow": [
      "Bash(npm install *)",
      "PowerShell(npx playwright *)"
    ]
  }
}

一見すると「これをコミットすればチーム全員に配れるのでは?」と思えます。しかし、そうすると次の2つの問題が起きます。


理由1: 自分の設定が「リポジトリが供給した設定」として扱われる

Claude Code にはワークスペース信頼という仕組みがあります。

プロジェクトの .claude/settings.json に書かれた permissions.allow(許可ルール)と permissions.additionalDirectories(作業対象に追加するディレクトリ)は、権限を与える設定なので、起動時に表示される「このフォルダーを信頼しますか」というダイアログを承諾するまで適用されません。ルール自体は読み込まれますが、実際には使われない状態になります。

これは、悪意のあるリポジトリを clone しただけで「危険なコマンドを確認なしに実行してよい」という設定が自動的に有効になってしまうことを防ぐための仕様です。

settings.local.json は本来あなた自身のファイルなので、通常この信頼チェックは適用されません。ところがGit にコミットされていると「リポジトリが供給し得るファイル」と判定され、プロジェクト設定と同じく信頼チェックの対象になります。.claude がシンボリックリンクになっている場合も同様です。

Claude Code から見て「あなたが自分でコミットしたのか」「他人のリポジトリに最初から仕込まれていたのか」は区別できません。git を実行してそのファイルがリポジトリ由来かどうかを確認するだけなので、安全側に倒した判定になります。

追跡対象外でも「常に即有効」ではない

ここは誤解しやすいポイントなので補足します。

Claude Code がこの git チェックを実行するのは、信頼ダイアログをすでに承諾済みのフォルダー(またはその親)に限られます。したがって、まだ信頼していないフォルダーでの対話セッションでは、追跡対象外の settings.local.json であっても、allow ルールと additionalDirectories はプロジェクト設定と同様に信頼チェックを通り、ダイアログを承諾するまで適用されません。

例外は2つです。

  • 自分の設定ホームでセッションを動かしている場合(ホームディレクトリ、または CLAUDE_CONFIG_DIR で指定したディレクトリ)… git チェックを実行する必要がないため、ダイアログ承諾前から適用されます
  • 起動ディレクトリが git リポジトリの外にある場合 … ただし「リポジトリの外である」ことの判定にも同じ git チェックを使うため、こちらはダイアログ承諾後に効き始めます

「追跡対象外にすれば無条件で即有効になる」というのは v2.1.207 より前の挙動です。
現行版では、承諾済みのフォルダーで追跡対象かどうかによって差が出る、という理解が正確です。

deny ルール(禁止ルール)と ask ルール(毎回確認するルール)は制限を加えるだけなので、信頼チェックの影響を受けません。
許可だけが審査対象になり、禁止は常に生き残るという非対称な挙動になります。


理由2: コンフリクトが多発し、意図も伝わらない

Bash や PowerShell のコマンド承認は、リポジトリ単位・コマンド単位で永続的に保存されます。つまり承認するたびにファイルが書き換わります。

しかも保存単位は単純ではありません。複合コマンド(;| でつないだコマンド)を承認した場合、承認が必要なサブコマンドごとに別々のルールが保存され、1つの複合コマンドにつき最大5個まで保存されます。1回の承認で allow 配列が数行増えることもあるわけです。

// Aさんが承認した後
"allow": ["PowerShell(New-Item *)", "PowerShell(git commit *)"]

// Bさんが別のコマンドを承認した後
"allow": ["PowerShell(New-Item *)", "PowerShell(Test-Path *)"]

複数人が同じ配列の近い位置を編集することになるため、マージ時に衝突しやすい形になります。日常的に発生する差分なので、地味にストレスが溜まります。

すべての承認がここに保存されるわけではありません。
ファイル変更(Edit / Write)の「今後確認しない」はファイルに保存されず、セッション終了までしか効きません。永続保存されるのは Bash と PowerShell のコマンド承認です。

さらに、自動生成されたルールには次のような環境固有の文字列が平気で混ざります。

"Bash(python /c/Users/007476/AppData/Local/Temp/claude/.../scratchpad/dump.py)"

ユーザー名や一時フォルダーの UUID がそのまま入っており、他の人の環境では一致しません。共有する価値がないどころか、ノイズにしかならないわけです。

加えて、local という名前は「各自のローカル環境固有のもの」を指す一般的な慣習です。それがコミットされていると、他のメンバーから見て「これはチームの所有物なのか、誰かが間違えて上げたものなのか」が判断できません。


解決方法

手順1: 追跡対象外にする

リポジトリのルートで次を実行します。

echo ".claude/settings.local.json" >> .gitignore
git rm --cached .claude/settings.local.json   # 既にコミット済みの場合のみ
git add .gitignore && git commit -m "chore: untrack local claude settings"

git rm --cached は、ファイルを手元に残したまま Git の管理下から外すコマンドです。
まだ一度もコミットしていない場合は不要です。

これで、信頼ダイアログを承諾済みのフォルダーであれば、あなたの allow ルールはリポジトリ供給扱いにならず、そのまま適用されるようになります。clone した他のメンバーの環境にはこのファイルが作られず、各自が自分の承認を積み上げていく形に戻ります。

グローバルの git excludes に頼らずプロジェクトの .gitignore にも書いておくと、チーム全員の環境で確実に除外されます。


手順2: 共有したいルールは settings.json に書く

チーム全員に配りたいルールは、.claude/settings.json に手で書いてコミットします。

settings.local.json の中身をそのままコピーするのは避けてください。
自動生成されたルールには共有に向かないものが大量に混ざっています。私の環境では 51件中、共有に耐えるのは13件だけでした。

除外すべきものは、おおむね次の4分類です。

  • 一時フォルダーの UUID 付きパス … セッションごとに変わるため二度と一致しない
  • 自分固有の絶対パス … 他メンバーの環境に存在しない
  • 一度きりの具体的なファイル名 … 再利用されない
  • 任意コード実行になるものBash(python -c ' *)Bash(node *) など。共有 allow にすると、他メンバーの環境で任意のスクリプトが確認なしに実行される

残すべきなのは、こういう汎用的なルールです。

.claude/settings.json
{
  "permissions": {
    "allow": [
      "Bash(npm install *)",
      "Bash(npx tsc *)",
      "Bash(npx playwright *)",
      "PowerShell(npx playwright *)",
      "WebSearch"
    ]
  }
}

手順3: 禁止ルールも書いておくと効果的

前述のとおり、deny ルールは信頼ダイアログの承諾を待たずに効きます。clone した直後から保護が効くので、共有ファイルに書く価値が高い部分です。

.claude/settings.json
{
  "permissions": {
    "deny": [
      "Read(**/.env*)",
      "Edit(**/.env*)",
      "Read(~/.ssh/**)",
      "Edit(.claude/**)",
      "PowerShell(Remove-Item *)"
    ]
  }
}

ReadEdit を両方書いているのには理由があります。
Read の deny ルールは同じパスに対する Edit ツールもブロックしますが(v2.1.208以降)、Write と NotebookEdit は対象外です。どのツールからも変更させたくないパスには、Edit の deny ルールを別途追加する必要があります。

ややこしいのですが、ファイルの権限チェックで参照されるのは Edit(path)Read(path) のルールだけです。Write(path)NotebookEdit(path) と書いても受け付けられはするものの、参照されません。Edit ルールがすべてのファイル編集ツールをカバーするので、Edit で書くのが正解です。

また PowerShell では、エイリアス(別名)が照合前に正規化されます。PowerShell(Remove-Item *) と書けば delrm にも一致するので、Bash 側より確実に効きます。

deny ルールは allow ルールより先に評価され、広い deny は狭い allow を含めてすべてブロックします。deny に例外を持たせることはできません。
Bash(git push *) のようなルールを入れる場合は、その操作を Claude に頼めなくなることを承知のうえで追加してください。


手順4: 反映を確認する

.claude/settings.json を配置したら、Claude Code を終了してプロジェクトルートで起動し直します。起動時に表示される信頼ダイアログで「Yes, I trust this folder」を選ぶと、その場で allow ルールと additionalDirectories が適用されます。

反映されたかどうかは /permissions で確認できます。

/permissions

すべての権限ルールと、各ルールがどの settings ファイル由来かが一覧表示されるので、目的のルールの出所が .claude/settings.json になっていれば完了です。


おわりに

.claude/settings.local.json を追跡対象外にすべき理由をまとめます。

  1. 追跡対象に入ると「リポジトリ由来かもしれない」と判定され、自分の allow ルールと additionalDirectories が信頼ダイアログの審査対象になる
  2. 承認のたびに自動追記されるためコンフリクトが多発し、環境固有のパスが混ざって共有する意味がない

通常は Claude Code がグローバルの git excludes に自動追記してくれるので、この問題に遭遇するのは、ファイルを手で作った場合や Write ツールで書かせた場合、あるいは追跡対象に入ったリポジトリを引き継いだ場合に限られます。

「local と付いているファイルはコミットしない」という慣習に従っておけば済む話ではあるのですが、その裏側にワークスペース信頼という仕組みがあることを知っておくと、想定外の挙動に遭遇したときに原因を切り分けやすくなります。

共有すべきものは settings.json に、個人のものは settings.local.json に。この住み分けを最初に決めておくのがおすすめです。


参考


JISOUのメンバー募集中!

プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか?
興味のある方は、ぜひホームページをのぞいてみてください!
▼▼▼
https://projisou.jp

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?