Skip to main content

git worktree コマンドと運用

やりたいこと

  • 複数のブランチを手元に置きたい
  • でもそれぞれ git clone するのは無駄に思う

概念: git worktree を活用する

git worktree コマンドを使えば良い(例はあえて冗長な名前にしてみた)

bash
# repo1 に branch-1 が既に居るとする
git clone <repo-url> repo1
cd repo1
git worktree add ../repo1-branch-1-dir branch-1
cd ../repo1-branch-1-dir

一覧するには

bash
git worktree list

削除するには

bash
git worktree remove ../repo1-branch-1-dir

この通りに作ると以下の構成になりそうだが、どれが依存してるか分かりづらくなりそう(と思ったけど命名次第かも)

txt
repo1/                 ← これが本体。中の .git/ が他で参照されているので、ここを消すと他が壊れる
repo1-branch-1/
repo1-branch-2/

※ ハマりポイントメモ: 同じブランチで別名 worktree を作ったりはできない

応用: トピックブランチも考えた場合

構成

  • チームで開発中の本線のブランチを phase-N としたとして
  • 各開発者が機能追加のために作ったトピックブランチを feature/phase-N/sugoi-henkou とする
  • 紛らわしくなるので phase-N ディレクトリでは switch しないことにする
txt
repo1/                     ← これはただのフォルダ
main/ ← これが本体。(中の .git/ を)消すと他が壊れる
phase-01/
phase-02/ ← チームで開発中の本線ブランチ(リモートが既にある)
phase-02-sugoi-henkou/ ← 機能追加のためのトピックブランチ(リモートは push 時に作る)

コマンド

1. worktree 作成

bash
mkdir repo1
cd repo1

git clone <repo-url> main

# worktree 作成 (リモートの origin/phase-N ブランチを元にローカルに phase-N ブランチを作成している)
cd main
git worktree add ../phase-01 -b phase-01 origin/phase-01
git worktree add ../phase-02 -b phase-02 origin/phase-02

# worktree の upstream 設定 (デフォルトの push, pull 対象を決めている)
cd ../phase-01
git branch --set-upstream-to=origin/phase-01 phase-01
cd ../phase-02
git branch --set-upstream-to=origin/phase-02 phase-02

# トピックブランチ作成
cd ../main
git fetch origin
git worktree add ../phase-02-sugoi-henkou -b feature/phase-02/sugoi-henkou origin/phase-02

※ ちなみに、git fetch は、どの worktree でやっても、最新化される(同じ main の origin を見ているから)

2. 開発

bash
cd ../phase-02-sugoi-henkou
(いろいろ修正する..)
git add -A
git commit -m '...'

3-1. 本線への合流(GitHubの場合)

(1) リモートのトピックブランチを作成(push)

bash
cd ../phase-02-sugoi-henkou
git push origin feature/phase-02/sugoi-henkou
  • 以降を git push だけで済ませたい場合は --set-upstream オプションをつける
  • この例では 1 回プッシュしたら終わりなので、つけないでおく

(2) プルリクエスト (GitHubの場合のみ必要)

bash
gh pr create --base phase-02 --head feature/phase-02/sugoi-henkou --title "sugoi henkou" --body "sugoi henkou wo kuwae mashita"

(3) 取り込み

ここは Web 画面でやるものかも

gh pr list --base phase-02  # ここで変更番号が 15 だったとする
gh pr view 15 # --web 引数をつければ Web 画面で確認可
gh pr merge 15

3-2. 本線への合流(gitの場合)

bash
cd ../phase-02

# 最新化(他の人の変更があったら取り込まれるということ)
git fetch origin
git pull --ff-only origin phase-02

# トピックブランチの変更を取り込む
git merge --no-ff feature/phase-02/sugoi-henkou

# 本線をリモートに適用!
git push origin phase-02 # git push で省略可能だが、事故防止で明示する

余談: 他に考えた案(bare repo 作る版)

この構成もきれいかも、と思ったが、うまく origin/ を見れるように設定できなかったのと、ちょっとトリッキーな気もするので、概念だけ残しておくが、不採用とする。

txt
repo1/            ← これはただのフォルダ(.git/ が存在することでぱっと見リポジトリに見える)
.git/ ← bare repo。 これが本体。消すと他が壊れる
branch-1-dir/
branch-2-dir/
案3のコマンド例
bash
mkdir repo1
cd repo1

git clone --bare <repo-url> .git

git --git-dir=.git fetch --all

git --git-dir=.git worktree add main main

git --git-dir=.git worktree add branch-1-dir branch-1
git --git-dir=.git worktree add branch-2-dir branch-2

以下広告