1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

あるブランチで開発を進めている最中に、別ブランチの不具合を今すぐ直してほしいと頼まれることがあります。
いったんgit stashで退避し、git switchでブランチを移り、依存を入れ直してビルドし直す。
用が済んだら元のブランチへ戻ってgit stash pop
この切り替えを挟むたびに、作業が止まります。

git worktreeを使うと、この往復そのものが要らなくなります。
1つのリポジトリを、ブランチごとに別々のディレクトリへ同時に開けるからです。
いま触っているブランチはそのままに、隣のディレクトリでもう1つのブランチを進められます。

以下、実際にコマンドを動かしながら、基本の使い方と、後始末での注意点を確認していきます。
出力はすべて筆者の環境(macOS / Git 2.55.0)で実行した結果です。

git worktreeとは

git worktreeとは、1つのローカルリポジトリから、複数のブランチをそれぞれ別のディレクトリに同時にチェックアウトする仕組みです。

履歴(.git)は1つを共有したまま、作業ツリーだけを増やします。
git cloneとの違いはここです。
cloneはリポジトリまるごとを複製するので、履歴もリモート設定も二重に持ちます。
worktreeは履歴を共有するため、ディスクを余分に食わず、git fetchも一度で全ディレクトリに反映されます。

同じリポジトリのブランチAとBを、並べて同時に触りたい。
そんなときに向いている機能です。

動作環境(macOS / Git 2.55.0)

  • macOS (Apple Silicon)
  • Git 2.55.0

git worktree自体はGit 2.5、git worktree removeはGit 2.17以降で使えます。
お使いのバージョンはgit --versionで確認してください。
Gitを一度でも触ったことがあれば読み進められます。

git worktree addでブランチを別ディレクトリに開く

新しいブランチhotfixを、隣のmyapp-hotfixディレクトリに作って開きます。

# -b hotfix で新規ブランチを作り、../myapp-hotfix に作業ツリーを展開する
git worktree add -b hotfix ../myapp-hotfix
Preparing worktree (new branch 'hotfix')
HEAD is now at 145e590 init

これでリポジトリの隣にmyapp-hotfixができました。
そこへ入れば、中はhotfixブランチの作業ツリーです。
元のmyappディレクトリはmainのまま、何も変わりません。

いま何がどこに開いているかはgit worktree listで分かります。

git worktree list
/private/tmp/wt-demo/myapp        145e590 [main]
/private/tmp/wt-demo/myapp-hotfix 145e590 [hotfix]

左からパス、コミット、ブランチ名です。
1つのリポジトリが、2つのディレクトリに別々のブランチで開いています。

ブランチを切り替えずに並行作業する

worktreeの利点は、ブランチを移らずに済むことです。
hotfix側で作業してコミットしても、main側の作業ツリーは汚れません。

# myapp-hotfix 側でファイルを足してコミットする
cd ../myapp-hotfix
echo fix > fix.txt
git add fix.txt
git commit -m "hotfix: add fix.txt"
[hotfix 8c87e9f] hotfix: add fix.txt
 1 file changed, 1 insertion(+)
 create mode 100644 fix.txt

main側と状態を見比べます。

# それぞれの先頭コミットと、main の変更状況を確認する
git -C ../myapp-hotfix log --oneline -1
git -C ../myapp log --oneline -1
git -C ../myapp status -sb
8c87e9f hotfix: add fix.txt
145e590 init
## main

hotfixは新しいコミットを持ち、maininitのまま。
git status## mainだけで未コミットの変更が並ばないので、main側は手つかずだと分かります。
git stashgit switchも挟まずに、2つのブランチを本当に同時に進められました。

使うときの注意点と後始末

同じブランチは2か所に出せない

すでにどこかの作業ツリーで開いているブランチは、別の作業ツリーにもう一度出せません。
試すとfatalで止まります。

# main はすでに myapp で開いている
git worktree add ../myapp-2 main
Preparing worktree (checking out 'main')
fatal: 'main' is already used by worktree at '/private/tmp/wt-demo/myapp'

同じブランチを2つの作業ツリーで開くと、両方が同じブランチの先頭を動かそうとして食い違います。
これはGitが衝突を防ぐための仕様です。
別ディレクトリで欲しいときは、-bで新しいブランチを切るか、そのブランチを開いている作業ツリーを先に片づけます。

git worktree removeで作業ツリーを消す

worktreeは作りっぱなしにせず、用が済んだらgit worktree removeで消します。

# 作業ツリーを1つ片づける
git worktree remove ../myapp-hotfix
git worktree list
/private/tmp/wt-demo/myapp 145e590 [main]

一覧がmyappだけに戻りました。
ただしgit worktree removeが消すのは作業ツリーだけで、hotfixブランチ自体は残ります。
ブランチも消したいときはgit branch -d hotfixを別に実行します。

なお、いま自分が入っている作業ツリーは remove できません。
消す前に別のディレクトリへcdしておきます。

rmで消しても残る管理情報をgit worktree pruneで掃除する

git worktree removeではなく、ディレクトリをrmで直接消すと、作業ツリーの実体は消えても、Gitの管理情報は残ります。

# 実験用にもう1つ作り、あえて rm でディレクトリごと消す
git worktree add -b exp ../myapp-exp
rm -rf ../myapp-exp
git worktree list
/private/tmp/wt-demo/myapp     145e590 [main]
/private/tmp/wt-demo/myapp-exp 145e590 [exp] prunable

消したはずのmyapp-expが一覧に残り、末尾にprunable(掃除できる)と付きます。
この後始末はgit worktree pruneが担当します。

# 実体の無くなった作業ツリーの管理情報を掃除する
git worktree prune -v
git worktree list
Removing worktrees/myapp-exp: gitdir file points to non-existent location
/private/tmp/wt-demo/myapp 145e590 [main]

pruneで管理情報が消え、一覧がきれいになりました。
最初からrmではなくgit worktree removeで消していれば、この掃除は要りません。

git worktreegit cloneの違いと使い分け

worktreeは履歴を共有するので、次のような場面で効率よく使えます。

  • レビュー中のブランチを開いたまま、別のPRを隣で動かして確かめたい
  • CIだけで再現するバグを、本流の作業を止めずに別ブランチで追いたい
  • 長く走らせるブランチ(大きめの改修)を、日々の小さな修正と並行させたい

一方で、リモートやフックの設定まで含めて2つの環境を完全に切り離したいときは、素直にgit cloneで別リポジトリにするほうが安全です。
worktreeは.gitを共有するため、片方でリポジトリ設定を大きくいじると、もう片方にも影響します。
履歴を共有したまま作業ツリーだけ足すのがworktree、環境ごと切り離すのがcloneと考えると選びやすいでしょう。

まとめ

  • git worktree add <パス>で、1つのリポジトリを複数のブランチとして別ディレクトリに同時に開ける
  • ブランチを移らないので、git stashとブランチ切り替えの往復が要らなくなる
  • 開いているブランチはgit worktree listで確認できる。同じブランチは2か所に出せない
  • 用が済んだらgit worktree removeで消す。rmでディレクトリだけ消したらgit worktree pruneで後始末する
  • 履歴を共有したまま作業ツリーだけ足すのがworktree、環境ごと分けたいならgit clone

参考


(宣伝)RareTECHについて

RareTECH(レアテック) は、量産型で終わらない、働き方を選べる希少型エンジニア®を育てるITスクールです。
git worktreeが役に立つのは、レビューや並行開発が日常になるチーム開発の現場です。
RareTECHでは、複数人でGitを使いながら開発を進めるチーム開発を学べます。

サービスの詳細は公式サイトに載せています。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?