/var/www/yatta47.log

/var/www/yatta47.log

やったのログ置場です。スクラップみたいな短編が多いかと。

git addで "does not have a commit checked out" が出る原因と対策

git adderror: '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 -lafind を使わないと存在を確認できません。

2つ目はエラーメッセージのせい。「does not have a commit checked out」という文言は、コミット履歴やHEADの問題を連想させます。ネストした .git/ が原因とはなかなか結びつかない。

エラーメッセージから検索しても「サブモジュールのHEADが壊れた」系の情報が出てきて、今回の問題とはすれ違うことが多い。

まとめ

git adddoes not have a commit checked out が出たら、対象ディレクトリ内のネストした .git/ を疑う。find path/ -name ".git" で確認できます。

解決策は「分離する(.gitignoreか移動)」「サブモジュール登録」「.git/を削除して取り込む」の3択。手間が少なく明快なのは .gitignore での分離です。

外部リポジトリをクローンしてそのまま作業ディレクトリに置く前に、.git/ の存在をチェックする習慣があると防げます。

参考