git worktreeの管理ツールが色々出てきている。git-wtはtmux統合やfzfベースのインタラクティブ選択が便利だし、他にもworktreeの管理をいい感じにするツールはいくつかある。
ただ、こういったツールの紹介を見ていると「worktreeへの移動をどう楽にするか」に注目が集まっている気がする。でも、worktreeにcdする必要ってそもそもあるんだろうか。
worktreeでやりたいことはコードを書くかAIに書かせるかのどちらかで、だったらworktreeの中でエディタやAIツールを直接起動すればいい。gtrはそれができる。
gtr editor my-feature # エディタで開く gtr ai my-feature # AIツールを起動
ディレクトリの移動は発生しない。
僕のグローバル設定はこう。
git config --global gtr.ai.default claude git config --global gtr.editor.default vscode git config --global gtr.copy.includedirs .claude
copy.includedirsでworktree作成時に自動コピーするディレクトリを指定できる。.claudeを入れておくとClaude Codeのプロジェクト設定を引き継げるのでめちゃくちゃ便利。
fzfとの組み合わせ
折角なので、zshに定義しているfzf連携も紹介する。worktree一覧をfzfで表示して、キーバインドでエディタやAIを直接起動できるようにしている。
_git_worktree_format() {
local root=$1
local git_cmd=$2
local line path branch mark is_root
local base_branch=$("$git_cmd" symbolic-ref --quiet refs/remotes/origin/HEAD 2>/dev/null)
base_branch=${base_branch#refs/remotes/origin/}
base_branch=${base_branch:-main}
while read -r line; do
path=${line%% *}
branch=${line##*\[}
branch=${branch%\]*}
if ! "$git_cmd" -C "$path" diff --quiet HEAD 2>/dev/null; then
mark="*"
elif [[ "$branch" != "$base_branch" ]] && [ -z "$("$git_cmd" -C "$path" log "origin/${base_branch}...HEAD" --oneline 2>/dev/null)" ]; then
mark="x"
else
mark=""
fi
if [ "$path" = "$root" ]; then
is_root="(root)"
else
is_root=""
fi
print "[${branch}]${mark}\t${path}\t${is_root}"
done
}
_git_worktree_colorize() {
sed -e $'s/\\[\\([^]]*\\)\\]\\*\\(.*\\)(root)/\e[1;36m[\\1]\e[1;31m*\e[0m\\2\e[90m(root)\e[0m/' \
-e $'s/\\[\\([^]]*\\)\\]x\\(.*\\)(root)/\e[1;36m[\\1]\e[1;31mx\e[0m\\2\e[90m(root)\e[0m/' \
-e $'s/\\[\\([^]]*\\)\\] \\(.*\\)(root)/\e[1;36m[\\1]\e[0m \\2\e[90m(root)\e[0m/' \
-e $'s/\\[\\([^]]*\\)\\]\\*/\e[1;33m[\\1]\e[1;31m*\e[0m/' \
-e $'s/\\[\\([^]]*\\)\\]x/\e[1;33m[\\1]\e[1;31mx\e[0m/' \
-e $'s/\\[\\([^]]*\\)\\] /\e[1;33m[\\1]\e[0m /'
}
# alt-w で起動
# enter:cd | C-e:editor | C-a:AI -c | M-a:AI | C-d:delete
git_worktree_list() {
local worktrees=$(git worktree list)
local root=$(echo "$worktrees" | head -1 | awk '{print $1}')
local git_cmd=$(command -v git)
local result=$(
echo "$worktrees" | _git_worktree_format "$root" "$git_cmd" | column -ts $'\t' | _git_worktree_colorize |
fzf --ansi \
--height 50% \
--no-sort \
--header 'enter:cd | C-e:editor | C-a:AI -c | M-a:AI | C-d:delete' \
--expect ctrl-e,ctrl-a,alt-a \
--bind 'ctrl-d:execute-silent(branch=$(echo {1} | tr -d "[]*"); git worktree remove {2}; git branch -D $branch)+abort' \
--preview 'cd {2} && git log --oneline -10 --color=always'
)
local key="${result%%$'\n'*}"
local selection="${result#*$'\n'}"
local branch=$(echo "$selection" | awk '{print $1}' | sed 's/[][]//g; s/[*x]$//')
local path=$(echo "$selection" | awk '{print $2}')
case "$key" in
ctrl-e)
BUFFER="git gtr editor '$branch'"
zle accept-line
return
;;
ctrl-a)
BUFFER="git gtr ai '$branch' -- -c"
zle accept-line
return
;;
alt-a)
BUFFER="git gtr ai '$branch'"
zle accept-line
return
;;
*)
if [ -n "$path" ]; then
BUFFER="cd ${path}"
zle accept-line
return
fi
;;
esac
zle clear-screen
}
zle -N git_worktree_list
bindkey '^[w' git_worktree_list
同じキーバインドをPR一覧(alt-p)とブランチ一覧(alt-b)にも定義していて、どの入口から入っても「選ぶ→エディタ or AI」の流れになっている(cdはあくまでフォールバック)。
# alt-p: PR一覧 → enter:worktree | C-e:editor | C-a:AI bindkey '^[p' fzf-pullreq # alt-b: ブランチ一覧 → enter:switch | C-t:worktree | C-e:editor | C-a:AI bindkey '^[b' fzf-branch
みなさんもworktree管理ツールを選ぶとき、「cdを楽にする」じゃなくて「cdしなくていい」ほうを試してみてください。
追記
いつの間にか git-wt にも editor を開くコマンドが追加されていた https://github.com/toritori0318/git-wt?tab=readme-ov-file#open-in-editor