git add で error: 'path/' does not have a commit checked out が出て fatal: adding files failed になる。犯人はネストした .git/ ディレクトリです。
何が起きたか
外部リポジトリをクローンして、そのまま作業中のリポジトリのディレクトリ内に置いた。ファイルを git add しようとしたら、こんなエラーが出た。
error: 'external-tool/' does not have a commit checked out fatal: adding files failed
エラーメッセージを見ると「コミットがチェックアウトされていない」と言われる。最初、コミット履歴に問題があるのかと思ったんですよね。でも実際は全然違う話でした。
原因
対象ディレクトリに .git/ が入っていることが原因です。
Gitはディレクトリをスキャンするとき、.git/ を見つけると「ここは別のリポジトリの境界」と判断します。別リポジトリはサブモジュールとして登録しない限り、親リポジトリには追加できません。「gitlink」(サブモジュールのポインタ)を作るにはサブモジュール登録が必要で、未登録だとエラーになる。
エラーの言いぶりが「コミットがない」なのでミスリードされやすいですが、本当の問題は.git/の存在です。
親リポジトリ/
├── .git/ ← 親の.git
└── external-tool/ ← ここに.git/が入っている
├── .git/ ← これが原因
└── src/
.git/ は隠しディレクトリなので ls では見えない。git clone した後にそのまま親リポジトリ内に移動すると踏みやすいパターンです。
まず確認コマンドで原因ディレクトリを特定できます。
find path/ -name ".git"
-type d をつけないのがポイントです。git worktree 等では .git がファイルになるケースもあるため、ディレクトリ限定だと検出漏れが起きます。
対策
3つの選択肢があります。
対策1: 別リポジトリとして分離する(推奨)
一番シンプルな解決策。対象ディレクトリを親リポジトリの外に移すか、.gitignore に追加して管理対象から外す。
# .gitignoreに追加 echo "external-tool/" >> .gitignore
「親リポジトリで管理する必要はなく、単に参照したいだけ」ならこれが最速です。
対策2: サブモジュールとして正式に登録する
ネストしたリポジトリをGitのサブモジュールとして管理する方法。
# 未コミットの変更がある場合は先にバックアップしておく cp -r external-tool/ /tmp/external-tool-backup/ # 既存ディレクトリをいったん削除してからサブモジュールとして追加 rm -rf external-tool/ git submodule add <リポジトリURL> external-tool/
サブモジュールは clone 時に --recursive が必要になったり、更新が独立して必要だったりと運用が複雑になります。「明確にバージョンを固定して管理したい」という明確な理由がないならやりすぎです。
対策3: .git/を削除して親リポジトリに取り込む
対象ディレクトリの .git/ を消して、親リポジトリの一部として管理する。
rm -rf external-tool/.git git add external-tool/
履歴はなくなるので注意。「とにかく取り込みたい、履歴は不要」という場面で使う選択肢です。
なぜ気づきにくいか
2つ理由があります。
1つ目は .git/ が隠しディレクトリなこと。ls や Finder では見えない。ls -la か find を使わないと存在を確認できません。
2つ目はエラーメッセージのせい。「does not have a commit checked out」という文言は、コミット履歴やHEADの問題を連想させます。ネストした .git/ が原因とはなかなか結びつかない。
エラーメッセージから検索しても「サブモジュールのHEADが壊れた」系の情報が出てきて、今回の問題とはすれ違うことが多い。
まとめ
git add で does not have a commit checked out が出たら、対象ディレクトリ内のネストした .git/ を疑う。find path/ -name ".git" で確認できます。
解決策は「分離する(.gitignoreか移動)」「サブモジュール登録」「.git/を削除して取り込む」の3択。手間が少なく明快なのは .gitignore での分離です。
外部リポジトリをクローンしてそのまま作業ディレクトリに置く前に、.git/ の存在をチェックする習慣があると防げます。