Gitのsafe.directoryで「fatal: detected dubious ownership in repository」エラーを根本解決する

Git tutorial - IT technology blog
Git tutorial - IT technology blog

背景と根本的な原因

ホストマシンのコードディレクトリをDockerコンテナにマウントし、いざ git status を実行したところ、次のような冷や水を浴びせられた経験はないでしょうか。

fatal: detected dubious ownership in repository at '/workspace/my-app'
To add an exception for this directory, call:

	git config --global --add safe.directory /workspace/my-app

この状況は、複数人の開発者が共同利用するステージングサーバーにSSH接続した際にもよく遭遇します。

リポジトリが壊れているわけでも、Gitのバグでもありません。これはCVE-2022-24765のセキュリティパッチ(2022年4月)で追加された防衛メカニズムです。

このパッチ以前のGitは、親ディレクトリを順次遡って .git ディレクトリを探索していました。そのため、マルチユーザーサーバーにおいて、悪意のあるユーザーが /tmp や /var/www などの共有ディレクトリに細工された偽のリポジトリを配置できてしまう脆弱性がありました。その .git/config 内に悪意のあるhookや危険なスクリプトを指す core.fsmonitor 設定を埋め込まれると、配下のサブディレクトリで任意のGitコマンドを実行しただけで、あなたの権限でマルウェアが即座に実行されてしまう危険性があったのです。

この脆弱性を塞ぐため、Gitは新たなルールを設けました。それは、「コマンドを実行するユーザー自身が、そのリポジトリディレクトリの所有者でなければならない」というものです。

問題はDockerを利用したときに生じます。ホスト上のソースコードは一般ユーザー(通常はUID 1000)が所有していますが、コンテナ内はデフォルトで root(UID 0)として動作します。この両者のUIDの不一致を検知し、Gitがリスク回避のために操作を即座にブロックするのです。

Gitのバージョン確認

safe.directory の仕組みは、Git 2.35.2以降で利用可能です。まずは、ホストまたはコンテナ内のバージョンを確認しましょう。

git --version

バージョンが古い場合は、パッケージをアップグレードする必要があります。Ubuntu/Debianの場合:

sudo apt update && sudo apt install -y git

Alpine Linux(Dockerでよく使われるイメージ)の場合:

apk update && apk add --no-cache git

安全策から根本対策までの4つのアプローチ

ネット上のコマンドをやみくもにコピー&ペーストしてはいけません。実際の運用環境に適した解決策を選びましょう。

1. 特定のディレクトリをホワイトリストに追加する(推奨)

最も手軽なのは、対象のディレクトリが完全に安全であることをGitに明示的に伝える方法です。

git config --global --add safe.directory /workspace/my-app

このコマンドを実行すると、現在のユーザーの ~/.gitconfig に1行追記されます。root権限で動作しているコンテナ内の場合は、/root/.gitconfig に書き込まれます。

2. DockerfileやComposeで事前設定する

開発用コンテナ(dev-container)やCI/CDランナー(GitLab CI、Jenkinsなど)を構築する場合、コンテナを再作成するたびに設定が失われてしまいます。そのため、Dockerfile 内に直接記述しておくのがスマートです。

FROM node:20-alpine

WORKDIR /app

# gitをインストールし、作業ディレクトリをホワイトリストに登録
RUN apk add --no-cache git \
    && git config --global --add safe.directory /app

CMD ["npm", "run", "dev"]

ローカル開発環境で docker-compose.yml を使用している場合は、entrypoint または command で次のように実行することも可能です。

version: '3.8'
services:
  api:
    image: python:3.11-slim
    working_dir: /code
    volumes:
      - .:/code
    command: >
      sh -c "git config --global --add safe.directory /code &&
             python main.py"

3. ホストとコンテナのUIDを同期させる(開発におけるベストプラクティス)

エラーの本質は、UIDの不一致(1000 vs 0)にあります。したがって、ホスト側のUID/GIDでコンテナを動かすのが最も根本的かつクリーンな解決策です。

docker run -it --rm \
  -u $(id -u):$(id -g) \
  -v $(pwd):/workspace \
  -w /workspace \
  node:20-alpine sh

この方法には一石二鳥のメリットがあります。Gitのdubious ownershipエラーが解消されるだけでなく、コンテナ内で生成されたファイル(node_modules やキャッシュなど)がホスト上でroot所有者になってしまう問題も防げます。

4. Linux上でディレクトリの所有権を修正する

共有サーバーでこのエラーが発生する場合、多くは誰かが誤って sudo git clone や sudo git pull を実行したことが原因です。所有権を自身のユーザーアカウントに戻すだけで解決します。

sudo chown -R $USER:$USER /var/www/my-app

警告:ワイルドカード「*」の使用は避ける

Stack Overflowなどの回答では、手軽さから次のようなコマンドが推奨されていることがあります。

# 危険:実環境では絶対に避けること
git config --global --add safe.directory '*'

ワイルドカード * を指定すると、システム全体のすべてのディレクトリでCVE-2022-24765による保護が無効化されてしまいます。この設定が許容されるのは、即座に破棄される一時的なCI/CDコンテナ(エフェメラルランナー)内部程度です。個人の作業マシンや本番サーバーでは決して適用しないでください。

確認とお手入れ

設定後は、Gitに正しく反映されているか確認しましょう。

現在設定されているsafe.directoryの一覧表示

git config --global --get-all safe.directory

設定が保存されているファイルパス(system、global、localのいずれか)を確認したい場合は、--show-origin フラグを追加します。

git config --list --show-origin | grep safe.directory

ステータスの確認

プロジェクトディレクトリでいつものコマンドを叩いてみましょう。

git status

エラーや警告が出ず、通常通りブランチ情報やコミット状況が表示されれば完了です。

不要になったパスの削除

使い終わった古いプロジェクトを削除した際は、~/.gitconfig を整理しておくのが理想的です。

git config --global --unset-all safe.directory /workspace/my-app

UIDの仕組みと safe.directory を正しく理解すれば、システムのセキュリティを犠牲にすることなく、権限エラーをわずか30秒でスマートに解決できます。

Share: