別ブランチを参照しながら作業するために git worktree を使ってみる

別ブランチを参照しながら作業するために git worktree を使ってみる
=========================================================

解決したいこと
-------------

同じリポジトリ内の別のブランチにあるコードを参考にしたい場合、以下のような方法が考えられますが、それぞれ使いにくい部分もあります。

- 別のフォルダに `clone` する
  - 同じリポジトリが複数の場所に存在することになるので、管理が煩雑になる
- ブラウザでGitHubを開いてコードを参照する
  - 検索しにくい
- GitHub Webベースエディタ(github.dev)で参照する
  - 検索もできるし編集もできるが、表示できる件数に制限があったりする
  - すべての拡張機能が使えるわけではない

上記以外に`git worktree` というコマンドを利用する方法もあるということで、使い方を調べてみました。


環境情報
--------

| 項目 | バージョン |
|------|----------|
| OS | macOS 13.6.1 |
| Git | 2.43.0 |


`git worktree` の使い方
-----------------------

基本的な使い方に絞って紹介します。

他のコマンドなど詳しいことは [Git - git-worktree Documentation](https://git-scm.com/docs/git-worktree) などを参照ください。


### worktreeを作る

通常、ブランチはひとつで、他のブランチで作業したい場合は、今のブランチから作業したいブランチに切り替える必要があります。

その際、差分が残っているとブランチの切り替えができないため、作業中状態でコミットするか、 `stash` で退避するなどして切り替えることになると思いますが、 `git worktree` コマンドを利用することで、現在の作業ブランチを残したまま、別のブランチをチェックアウトすることができます。

例えば現在ローカルにあるブランチが以下のような場合に、 `feature/project-hoge` ブランチで開発を進めるのですが、その実装する内容と同等の内容がすでに `feature/project-fuga` ブランチに実装されているので、参照したいとします。

```shell
$ git branch
  develop
* feature/project-hoge
  feature/project-fuga
  master
  staging
```

現在 `feature/project-hoge` ブランチにいるので、worktreeとして `feature/project-fuga` ブランチをチェックアウトします。

このときは `git worktree add <worktree directory> <branch>` というコマンドを実行します。

`<worktree directory>` は、checkoutするブランチのソースコード一式を格納するためのディレクトリです。

例えば以下のように実行すると、ブランチ一覧に `*` が付いた現在のブランチ以外にチェックアウトされている `+` がついたブランチができます。

```shell
$ git worktree add .worktree-fuga feature/project-fuga
$ git branch
  develop
* feature/project-hoge
+ feature/project-fuga
  master
  staging
```

プロジェクトディレクトリ内を見ると、指定したディレクトリが作られており、その中身は `feature/project-fuga` ブランチのソースコード一式が格納されています。

```shell
$ ls -Al
...
drwxr-xr-x@   42 miura-ut  staff    1344 11 17 14:59 .worktree-fuga
...
```

### worktreeへ切り替える

ブランチの切り替えは `git checkout <branch>` を使いますが、worktreeをチェックアウトしようとするとエラーになります。 

```shell
$ git checkout feature/project-fuga
fatal: 'feature/project-fuga' is already checked out at '/Users/miura-ut/workspace/sportsbull/.worktree-fuga'
```

すでに該当ディレクトリに `feature/project-fuga` ブランチが出力された状態なので、そのディレクトリに移動することでworktreeへ切り替わります。

```shell
$ git status
On branch feature/project-hoge
$ cd .worktree-fuga
$ git status
On branch feature/project-fuga
```

### worktreeの一覧

プロジェクト内のworktreeの一覧を表示します。

worktreeがチェックアウトされているディレクトリとブランチ名が確認できます。


```shell
$ git worktree list
/Users/miura-ut/workspace/sportsbull                        4460a16347 [feature/project-hoge]
/Users/miura-ut/workspace/sportsbull/.worktree-fuga  a1bb8eda31 [feature/project-fuga]
```


### worktreeの削除

ブランチを削除するには `git branch -d <branch>` を使いますが、worktreeのブランチを指定した場合、エラーになります。

```shell
$ git branch -d feature/project-fuga
error: Cannot delete branch 'feature/project-fuga' checked out at '/Users/miura-ut/workspace/sportsbull/.worktree-fuga
```

worktreeを削除するには `git worktree remove <worktree directory>` を使います。

```shell
$ git worktree remove .worktree-fuga
$ git worktree list
/Users/miura-ut/workspace/sportsbull  4460a16347 [feature/project-hoge]
$ git branch
  develop
* feature/project-hoge
  feature/project-fuga
  master
  staging
```

worktreeが解除された `feature/project-fuga` ブランチが残りますが、これは `git branch -d` で削除が可能です。


worktreeで開発する
-----------------

worktreeは以下はプロジェクト直下とは分離され、単独でチェックアウトしたブランチの状態になっています。

そのため、そこでコードを編集したり実行することや、Git操作も可能です。

単純に他のブランチを参照するという使い方だけでなく、モノレポ（複数プロジェクトを1リポジトリで管理する）構成の場合に、並行して複数プロジェクトを開発するような場合にも有効だと思いました。

ただ、利用する中で個人的に気になった点がありましたので、記載しておきます。


### worktreeディレクトリが差分になってしまう

worktreeディレクトリは、プロジェクト本体としては管理外のため、 `git status` で差分として認識されてしまいます。

```shell
$ git status
On branch feature/project-hoge
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        .worktree-fuga/

nothing added to commit but untracked files present (use "git add" to track)
```

worktreeのディレクトリ名は自由につけられるので、自分が使う場合の名前を決めておいて、 `$HOME/.gitignore` に追加しておくことで無視させるのが良さそうです。

上記までの例の場合、 `.worktree-<個別>` のような命名規則としていますので、以下のように `.gitignore` に書くことで差分と認識されないようにすることができます。

```
.worktree-*
```


### worktreeディレクトリ内も検索されてしまう

プロジェクト全体を検索した場合に、worktreeディレクトリ内のソースコードもヒットしてしまい、検索結果に同じような結果が出てしまいます。

worktreeディレクトリを検索対象外にする必要があります。

VSCodeなら `files to exclude` を指定することで、worktreeディレクトリを除外することができます。


GUIでworktreeを使いたい
-----------------------

GUIのGitツールでworktreeがサポートされているかをいくつか調べてみました。

| アプリ | 対応状況 | 補足 |
|--------|---------|-----|
| GitHub Desktop | :x: | まだサポートされていないようです。<br> [Add support for treating worktrees like regular repos · Issue #907 · desktop/desktop · GitHub](https://github.com/desktop/desktop/issues/907) |
| Sourcetree | :o: | サポートされているようです。 <br> [[SRCTREE-3204] Add git 2.5 `worktree` command support - Create and track feature requests for Atlassian products.](https://jira.atlassian.com/browse/SRCTREE-3204) |
| VSCode | :o: | Extensionを入れることで使うことができます。 <br> [vscodeでgit worktreeを使う #Git - Qiita](https://qiita.com/K5K/items/a80e1bc3c9e899a37e0b) |


参考にさせていただいた記事
-----------------------

- [git worktreeを使ってみる #Git - Qiita](https://qiita.com/yoichi22/items/8f92110f24690ca8966f)
- [git worktree コマンドを使って複数ブランチを並行して操作する - kakakakakku blog](https://kakakakakku.hatenablog.com/entry/2021/04/15/092256)


運動通信社について
----------------

運動通信社は「日本を世界が憧れるスポーツ大国にする」というビジョンを達成するべく、一緒に働く仲間を募集しています！
PMやモバイルエンジニア、Webエンジニアなど色んな職種を募集しておりカジュアル面談大歓迎なので是非採用フォームよりご連絡ください！
ぜひ一緒に、自分たちも世の中もワクワクするサービスを作りましょう！

https://sportsbull.jp/about/#recruit