Claude Code の worktree が古いコードで作られる問題を Hook で解決する

claude code -w で作成される worktree がローカルの古いブランチをベースにしてしまう問題と、SessionStart Hook による自動同期の実装方法

Claude Code の -w(worktree)オプションで並行作業をしていたら、PR でコンフリクトが大量に出た。原因を調べたら、ローカルブランチがリモートより24コミットも遅れていた。

claude code -wgit worktree add でローカルブランチの HEAD から分岐するが、事前に git fetchgit pull は実行しない。なのでローカルが古ければ、そのまま古いコードで worktree が作られる。GitHub Issue #28958 にもなっている既知の制限だ。

毎回手動で git pull してから -w するのは面倒なので、Claude Code の Hooks 機能(公式ドキュメント)で自動化した。

やったこと

~/.claude/hooks/session-start-pull.sh を作成する。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/bin/bash
# SessionStart hook: リモートの最新を自動取得し、ローカルを最新化する

# stdin の JSON を読み捨て(hook プロトコル上送られてくるが不要)
cat > /dev/null

# git リポジトリでなければスキップ
git rev-parse --is-inside-work-tree > /dev/null 2>&1 || exit 0

# リモートの最新 ref を取得
git fetch origin 2>/dev/null || exit 0

# 追跡ブランチがある場合は pull(通常セッション向け)
git pull --ff-only 2>/dev/null

# 追跡ブランチがない場合(worktree 向け):
# HEAD が origin/branch の祖先なら ff-merge で最新化
for branch in develop main master; do
    if git merge-base --is-ancestor HEAD "origin/$branch" 2>/dev/null; then
        git merge "origin/$branch" --ff-only 2>/dev/null
        break
    fi
done

# ローカルのブランチ ref をリモートに追従(次回 worktree 作成時に最新がベースになる)
# +プレフィックスなし = 非強制更新: ローカルに独自コミットがある場合は失敗する(安全)
for branch in develop main master; do
    git fetch origin "$branch:$branch" 2>/dev/null
done

exit 0
1
chmod +x ~/.claude/hooks/session-start-pull.sh

~/.claude/settings.json に Hook を登録する。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "bash /path/to/.claude/hooks/session-start-pull.sh",
            "timeout": 30
          }
        ]
      }
    ]
  }
}

command のパスは環境に合わせて絶対パスで指定する。Windows (Git Bash) なら /c/Users/username/.claude/hooks/session-start-pull.sh のような形式になる。

何をやっているか

セッション開始のたびに以下を実行する。

  1. git fetch origin でリモートの最新 ref を取得
  2. git pull --ff-only で追跡ブランチがあれば更新(通常セッション向け)
  3. worktree ブランチの場合、親ブランチ(develop/main/master)からの ff-merge を試みる
  4. git fetch origin branch:branch でローカルのブランチ ref をリモートに追従させる(次回の worktree 作成に備える)

すべて --ff-only または非強制更新なので、ローカルに独自コミットがある場合は何もしない。エラーは 2>/dev/null で抑制し、exit 0 で終了するため、オフラインやマージ不可でもセッション開始を妨げない。

動作確認

1
2
echo '{"session_id":"test","hook_event_name":"SessionStart","source":"startup"}' \
  | bash ~/.claude/hooks/session-start-pull.sh

worktree が古い場合、以下のような出力が出て最新化される。

1
2
Updating abc1234..def5678
Fast-forward

これで -w 実行前に git pull を忘れる心配がなくなった。

comments powered by Disqus
発言は個人の見解であり、所属組織とは関係ありません。
Hugo で構築されています。
テーマ StackJimmy によって設計されています。