Open1

ghq friendly な git worktree 運用

ras0qras0q

Coding Agent に非同期でタスク実行させたくなったので重い腰を上げてgit worktreeを使いたくなった。

ghq っぽい操作感を謳う d-kuro/gwq という CLI もあるが、新しくコマンドを覚える必要があることや、表示がリッチで fzf とかと合わせづらいなどの問題があり自分で作ることにした。

登場人物

Git - git-worktree Documentation

https://git-scm.com/docs/git-worktree

git worktree コマンドのこと。

x-motemen/ghq: Remote repository management made easy

https://github.com/x-motemen/ghq

ghq get レポジトリのURL を実行することでいい感じに管理してくれるツール。
ghq get https://github.com/x-motemen/ghq.git の場合 ~/ghq/github.com/x-motemen/ghq/ に配置される。

junegunn/fzf: :cherry_blossom: A command-line fuzzy finder

https://github.com/junegunn/fzf

曖昧検索ツール。よく ghq とかと併用される。
cd $(ghq list --full-path | fzf) が便利。

本編

まずは worktree を置く場所を決める。候補としては

  1. ../project-foo (兄弟にする)
    • 多くの記事で紹介されている
    • ghq でレポジトリが置かれる場所と同じ場所に置かれるので干渉する
  2. ./worktrees/foo (子にする)
    • メインで管理しているレポジトリの下にできるので散らばらない
  3. ~/worktrees/project-foo (worktree用の隔離されたパスに置く)
    • gwq とかがそれ
    • ghq が ~/ghq/ 以下に配置するのでそれに倣っている

1 はghqの管理下に手動でworktreeを置くことになり干渉するため初めは2か3を考えていたが、以下のポストを見つけ、これならghqと同じ場所に置いても見分けられるだろうと言うことで結局 1 になった。

@yoichi22.bsky.socialによる投稿 — Bluesky

https://bsky.app/profile/yoichi22.bsky.social/post/3lrm7qatqxs2u

  • repo+branchという命名ならパッと worktree であることが分かる
  • 従来使っていた ghq | fzf で移動できるため覚えることが減る
    • 追加用に作ったコマンドを1つだけ覚える
    • list, removeなどその他のコマンドは git worktree をそのまま使う

実演

動画で見せたかったが普通にプライベートレポジトリが見えたので画像で。

コード

ブランチを曖昧検索してworktree 用のディレクトリを作成する。
標準出力にはパスだけが出力されるようにしている。これは gh repo create を真似た挙動 (gh repo create --public new-repo | xargs ghq get を気に入っている) 。

~/.zshrc
git-worktree-add-interactive() {
  local branch=$(git branch --format='%(refname:short)' | fzf --preview 'git log --oneline -20 --color=always {}')
  if [[ -z "$branch" ]]; then
    return 1
  fi

  local repo_base_path="$(git rev-parse --show-toplevel)"
  repo_base_path=${repo_base_path%+*}
  local repo_path="${repo_base_path}+${branch//\//_}"
  if [[ -d "$repo_path" ]]; then
    echo "warning: ${repo_path} already exists" >&2
    echo "${repo_path}"
    return 0
  fi

  git worktree add -q "${repo_path}" "${branch}" || return 1
  echo "${repo_path}"
}

olets/zsh-abbr を使っているので呼びやすいようにしておく。

~/.config/zsh-abbr/user-abbreviations
abbr "gw"="git worktree"
abbr "gwa"="cd $(git-worktree-add-interactive)"

参考資料

d-kuro/gwq: 🌳 Git worktree manager with fuzzy finder - Work on multiple branches simultaneously, perfect for parallel AI coding workflows

https://github.com/d-kuro/gwq

@yoichi22.bsky.socialによる投稿 — Bluesky

https://bsky.app/profile/yoichi22.bsky.social/post/3lrm7qatqxs2u