Author

Web系ソフトウェアエンジニアを志望
開発記録や個人的な技術に対する思いを綴ります

FOCUS個人開発/設計
OSArch Linux+Omarchy
STACKTypeScript・Next.js
STATUS学習中 → 就活中

git worktreeの使い方と便利コマンド

tech

3分で読めます・1064文字

はじめに

読者諸君、ぐんも!

この記事では、git worktreeの概要、記述方法、zshで使用可能な便利なコマンドを紹介します。

gitブランチ切り替えが煩雑になってきた方向けに、worktreeで並行作業を快適にする方法を紹介します。

なぜgit worktreeを使うのか?

最初はgit switch -c "branch-name"が私の相棒でした。
ところが、ブログを書くようになると、ブログ記事を書くブランチ、ブログ機能を実装するブランチが混ざって混乱することが増えるようになったのです。

また、claude codeを本格的に使うようになったこともあり、ブランチごとにディレクトリをわけて、ファイルに対する変更を混同しなくてすむようにもしたくなりました。

git worktreeとは

違い

  • git branchは同じディレクトリ上でファイル追跡branchを生成する。
  • git worktreeはブランチを作る際にディレクトリのコピーを作成する。

つまり、ブランチ作成時にディレクトリをコピーするかどうかが分かれ目となります。

例えばチームで1つのリポジトリを管理するとき、それぞれの作業はリモートリポジトリをそれぞれのPCにgit cloneしますよね?

それと同じことを1つのPC内でやってしまうのがgit worktreeなんです。

基本コマンド

追加

  1. 新しいブランチと作業ディレクトリを作成する
    ../"branch-name"のディレクトリが作成されます
git worktree add ../"branch-name"
  1. 既存ブランチを新しい作業ディレクトリに移す
    現在作業中のブランチを"directory-name"に移動します。
git worktree add "directory-name" "existing-branch-name"
  1. ブランチ名と作業ディレクトリ名を指定し、特定のコミットからブランチを作成する
    私の使用例では、"commit-name"は基本的にmainを使用します。
git worktree add -b "branch-name" "directory-name" "commit-name"
  1. ブランチ名と作業ディレクトリ名を指定して現在のコミットからブランチを作成する
git worktree add -b "branch-name" "directory-name"

現在のworktreeの一覧表示

git worktree list

削除

  1. 作業が完了したworktreeを削除します。
git worktree remove "directory-name"
  1. 未保存の変更があっても強制定期に削除します。
git worktree remove --force "directory-name"

zshで使っている便利関数

git worktreeの作成

現在のディレクトリに対し以下をチェックします。

  1. git repositoryか
  2. 初回コミットがあるか

その後、"repository-name"-"branch-name"というディレクトリを作成し、"branch-name"にチェックアウトします。

function git-plant() {
  if ! git rev-parse --git-dir &>/dev/null; then
    echo "not a git directory"
    return
  elif ! git rev-parse HEAD --git-dir &>/dev/null; then
    echo "commitがありません"
    return
  elif [[ -z "$1" ]]; then
    echo "ブランチ名を指定してください"
    return
  fi
  local branchdir="../$(basename $(git rev-parse --show-toplevel))-$1"
  git worktree add -b "$1" "$branchdir" "${2:-main}"
  cd "$branchdir"
}
  • git rev-parse (HEAD) --git-dir &>/dev/null
    現在の(HEAD コミットへの)HEADのコミットハッシュと.git directory``のパスを出力、stdout(標準出力)とstderr`(標準エラー出力)を捨てます。
    true/falseを判定するために使用

  • git rev-parse --show-toplevel
    現在のgit directoryのトップレベルのディレクトリパスを出力

  • basename
    引数のディレクトリ名を出力

git worktreeの削除

mainにmerge済みのworktreeのディレクトリ・ブランチを削除します。

function git-cut() {
  git fetch --prune
  git branch -vv | grep ': gone' | awk '{
    if ($1 == "+") {
      gsub(/[()]/,"",$4); print $2,$4
    } else { print $1,"" }
  }' | while read branch wt_path; do
    [[ -n "$wt_path" ]] && git worktree remove "$wt_path"
    git branch -d "$branch"
  done
  echo
  echo 💫残りのローカルブランチ💫
  echo
  git branch
}
  • git branch -vv | grep ': gone' | awk
    mainにmergeされると、git branch -vvfeature/foo abc1234 [origin/feature/foo: gone]のように表示されます。
    そのため、: goneのブランチに対してawkの処理を実行します。

スコープ外の実装を別ワークツリーに分ける

# まず変更をstashする
git stash -m "stash message"

# ワークツリーを分ける
git worktree add -b "branch-name" "directory-name"

# (stash一覧を表示する)
git stash list
# 変更をstashから戻す
git stash index

さいごに

git branchのみの運用よりもはるかに利便性が高く、AIとのコーディングとも親和性の高いgit worktreeの紹介でした。

ぜひ皆さんの開発フローに取り入れてみてください。