Claude Code などの AI セッションを、同じリポジトリで複数並べて動かしている方は多いかなと思います。会話はセッションごとに分かれていても、同じ作業ツリーを開いているかぎり、Git の index と、今いるブランチを指す HEAD は全員で 1 つを共有しています。

2026 年 9 月 12 日に、個人のノートを管理しているリポジトリでこれを踏みました。片方のセッションの git commit が別セッションのステージ分だけを拾い、メッセージと中身が食い違うコミットができました。食い違いには当日気づいて revert しましたが、10 月 16 日に当時のコミットを見直したところ、revert で消えた別セッションの追記が、今のノートにも戻っていなかったことが分かりました。

この記事の持ち帰りは次の 4 つです。

  • git add と git commit を同じシェル呼び出しにまとめる
  • コミットの中身は、ハッシュを指定して git show --stat <hash> で確かめる
  • 食い違ったコミットを revert する前に、相手の変更がどこにあるかを確かめる(事故のあとに考えた手順です)
  • 並行作業やブランチを切る作業は git worktree で作業ツリーごと分ける(混線を再現しての確認はしていません)

メッセージは CI の機能追加なのに、中身は別セッションのノート 2 件だった

9 月 12 日の夕方、同じ作業ツリーで 2 つの Claude Code のセッションが動いていました。

  • こちら: SKILL.md の本文行数が推奨上限の 90%(450 行)に達したら PR を落とすチェック(スクリプトと workflow の追加、ファイル名 1 件の変更)を作り、feature/check-skill-size ブランチで PR を出そうとしていた
  • 別セッション: タスクのノート 2 件に完了の記録を追記し、アーカイブへ移そうとしていた

16:33:17(JST、以下同じ)に、こちらがコミット 3cc1c949 を作り、16:33:39 には PR #233 を作成しています(この時点で push 済みです)。メッセージは feat: SKILL.md が推奨上限の 90% に達したら PR を落とす ですが、中身を見ると別物でした。

git show --stat -M 3cc1c949

入っていたのは別セッションのノート 2 件の移動と更新(差分全体で +115/-9)だけで、こちらの 3 ファイルは未追跡のまま残っていました。

git commit は index の中身からコミットを作ります。

Create a new commit containing the current contents of the index

参考: Git - git-commit Documentation

index は作業ツリーに 1 つなので、別セッションがステージした変更があれば、こちらの commit にもそのまま入ります。一方、こちらの 3 ファイルがなぜ index に入っていなかったのかは、当時のセッション記録が残っておらず分かりません。

HEAD も共有されていて、別セッションのコミットも同じブランチに 2 回乗っていた

3cc1c949 は push 済みだったので、revert してから本来の変更を入れ直しました。git log、git reflog、gh pr view 233 から復元した時系列です。

時刻コミット / 操作内容
16:32:58checkoutmaster から feature/check-skill-size へ切り替え(3cc1c949 の 19 秒前。PR 用にこちらが切ったと見ています)
16:33:173cc1c949中身は別セッションのノート 2 件だけ
16:41:1838dbee22こちらが 3cc1c949 を revert
16:41:4314df371b別セッションのアーカイブのコミット。ノート 2 件の移動だけ(R100)
16:43:31615a74fcこちらが本来の 3 ファイルを入れ直し
16:52:26b9e27deb別セッションの別のノートのコミットも同じブランチに乗る
17:00:26〜17:01:18cherry-pick と resetb9e27deb を master へ cherry-pick し、ブランチからは reset で外す
17:05:2141771389PR #233 をマージ(PR に入ったのは 3cc1c949〜615a74fc の 4 コミット。b9e27deb は外したあと)

HEAD も作業ツリーに 1 つなので、片方がブランチを切り替えれば、もう片方のコミットもそのブランチに乗りえます。この夕方は、別セッションの作業のコミットが 2 回このブランチに乗っていて、git reflog にもどちらもこのブランチの上の commit として残っています。1 回目の 14df371b はそのまま PR #233 に入り、2 回目の b9e27deb は reflog の上では cherry-pick と reset で master へ移されています。当時のセッション記録は無いので、HEAD の共有のほかに理由が無かったかまでは確かめられていません。

revert で追記が消え、別セッションのアーカイブのコミットでも戻らなかった

9 月 12 日の時点では、revert と入れ直しで復旧できたと思っていました。10 月 16 日に差分を 1 つずつ見直して分かったのは、次の 3 点です。履歴と、今のファイルとの差分で確かめています。

  • 38dbee22(revert)の差分で、追記が削除されている。 同じ差分で 2 件の status: done が next に戻り、completed も消えている
  • 14df371b(別セッションのアーカイブのコミット)は R100。 revert 後の追記の無い版を、中身を変えずに移動しただけだった
  • 今のノートにも追記は無い

追記が後のコミットで戻っていないかは、git log -S でも確かめました。-S は文字列の出現数が変わったコミットを探すオプションです。

Look for differences that change the number of occurrences of the specified <string>

参考: Git - git-log Documentation

# 検索文字列は置き換えています
git log -S'<追記に含まれていた見出し>'

見つかったのは追加の 3cc1c949 と削除の 38dbee22 の 2 コミットだけでした。見出し 1 つでの検索なので、本文だけを戻したようなケースまでは拾えませんが、今のノートと比べても追記は戻っていません。

git revert は、打ち消す変更を作業ツリーと index に当て、通常はそのままコミットまで作ります(--no-commit の説明に「applies the changes necessary to revert the named commits to your working tree and the index」とあります)。仕様のとおりなら、共有している作業ツリーで revert すると、別セッションが開いているファイルもその場で書き換わるはずです。

参考: Git - git-revert Documentation

ここから先は推測です。別セッションは、revert で追記前に戻ったノートを、そうとは気づかずに移動したのだと見ています。当時の記録が無いので、別セッションが何を見て操作したのかは確かめられていません。

追記は今のファイルからは消えていますが、履歴の 3cc1c949 には残っていて取り出せます。

git show 3cc1c949:<path>

必要になったら履歴から取り出せるので、今回は戻さずにそのままにしました。

食い違いには当日気づいたが、追記が戻っていないことには 1 か月気づかなかった

食い違ったコミットのことは、当日のうちに把握していました。revert のコミットメッセージにも「commit した時点で別セッションがステージしていたぶんだけが拾われ」と書いています。

気づかなかったのは、その後も追記が戻っていないことのほうです。当日書いた ~/.claude/CLAUDE.md の「なぜ」も、「push 済みだったので revert + 入れ直しの 2 コミットで復旧することになり、別セッションの作業も止めてしまった」とあるだけで、記録が消えたことには触れていません。10 月 16 日の時点でも同じ文のままでした。

ノートのほうは、status が next に戻っていたので、マージ直後に走った整理の処理で 2 件とも未完了の置き場所へ戻っていました。その後、1 件は当日の夜に短い記録つきで、もう 1 件は 9 月 24 日に、あらためて完了扱いになっています。どちらも、消えた追記の代わりになる記録ではありません。

対策: add と commit をまとめ、ハッシュを指定して中身を見る

同じ 9 月 12 日の 17:12 には、~/.claude/CLAUDE.md に次の 2 つのルールが入っていました(個人の dotfiles リポジトリのコミット ede32c5)。「なぜ」の欄にはこの事故が書いてあります。

1. git add と git commit を同じシェル呼び出しにまとめる

git add <file1> <file2> && git commit -m "..."

add と commit のあいだに別セッションが index を書き換える隙間を減らせます。ただ、今回の事故がこの隙間で起きたのかは分かりません。それに、add より前から index に別セッションのステージ分が残っていれば、まとめても一緒に入ってしまいます。次の確認とセットで使います。

2. コミットの中身はハッシュを指定して見る

当時のルールは「commit 後に git show --stat で中身を見る」でした。ただ、引数なしの git show は HEAD を表示します。

参考: Git - git-show Documentation

同じ作業ツリーで別セッションが直後に commit すると、HEAD は相手のコミットを指していて、自分のコミットを確かめたつもりで別のものを見ることになります。git commit の出力に出るハッシュを指定して見るのが確実です。

git show --stat -M <hash>

この記事のレビューでこの穴を指摘されたので、10 月 16 日にルールのほうも、ハッシュを指定して見る形に直しました。

3. revert の前に、相手の変更がどこにあるかを確かめる

これは 10 月 16 日に気づいた点です。今回、別セッションの追記は 3cc1c949 に入った状態で revert しています。

食い違ったコミットを見つけたら、まず git show --stat <hash> で自分のものでないファイルを確かめます。そのうえで、相手のセッションにそのファイルを触らないよう伝えてから扱いを決めると安全そうです。revert したあとは、git diff <hash> HEAD -- <path> で相手のファイルがどう変わったかを見ておくと、今回のように追記が消えたまま進んでいることに気づけそうです。消えていても、git show <hash>:<path> で元の版を取り出せます(今回の事故のあとに考えた手順で、試してはいません)。

並行作業は git worktree で作業ツリーごと分ける

ここまでの対策は、index と HEAD を共有したまま事故を減らすものです。共有そのものをやめるなら git worktree を使います。

sharing everything except per-worktree files such as HEAD, index, etc.

参考: Git - git-worktree Documentation

worktree ごとに HEAD と index を持つので、セッションごとに worktree を分ければ、今回のような「相手のステージ分を拾う」「相手のコミットが自分のブランチに乗る」は起きないはずです。ブランチそのものやリモートは共有なので、同じブランチを 2 つのセッションで触るなら、そこは別に気を付ける必要がありそうです。

10 月 16 日には、同じリポジトリで PR 用のブランチを worktree で切りました。

git worktree add -q -b feature/neta-html-sources <worktree-path> origin/master

08:52 に worktree を作り、09:05 にマージして削除するまでのあいだに、元の作業ツリーでは master に 4 件のコミットが入っていました。元の作業ツリーの git reflog には、このブランチへの checkout はありません。PR のブランチには worktree 側のコミットだけが乗っていました。

これは 10 月 16 日の普段の作業での例で、混線をわざと再現して確かめたわけではありません。

まとめ

  • 同じ作業ツリーでは、index と HEAD を全セッションで共有しています。9 月 12 日は、別セッションのステージ分だけを拾ったコミットが 1 回、別セッションのコミットが自分のブランチに乗ったことが 2 回ありました(HEAD の共有が原因とみていますが、当時の記録が無く確定はできません)
  • 食い違ったコミットを revert したら、その差分で別セッションの追記も消え、直後のアーカイブのコミットでも戻りませんでした。今のノートにも追記は無く、それまで約 1 か月気づいていませんでした。元のコミット 3cc1c949 からは取り出せます
  • 同じ作業ツリーで動かすなら、add と commit を 1 回の呼び出しにまとめ、中身はハッシュを指定した git show --stat <hash> で確かめると、混線に気づきやすくなりそうです
  • 食い違ったコミットを revert する前には、相手の変更がどこにあるかを確かめておくと、今回のように消えたまま進むことは避けやすそうです
  • セッションごとに git worktree を分ければ HEAD と index が分かれるので、今回のような混線は避けられそうです(再現しての確認はしていません)