rcmdnk's blog

20250728_gitworktree_200_200

Git Worktreeの管理方法について、 外部ツールなどを使わずにできる個人的便利設定。

Worktreeを管理する場所

Worktreeはレポジトリルートに.worktreeというディレクトリを作ってその中で管理するようにしています。 レポジトリの中で閉じたいので。

このディレクトリはルートのGit管理からは外したいので .gitignore

1
/.worktree

を追加しておきます。

.gitディレクトリの中に作るという案も出てたりしますが、 gitの内部構造用ディレクトリなので避けた方が無難です。

submoduleのような状態で管理している場合にはそもそも.gitがディレクトリでなくなり、 親の.gitディレクトリを使ったりするとよくわからなくなってくこともあるかもしれないので。

現状この方法で一つ困ってるのが、仮想環境を自動認識してくれるmiseを使った環境設定を行っている際。

.mise.tomlがworktreeとその親のディレクトリでも見つかって重複してしまうわけですが、 Pythonの仮想環境(だけ?かほかもそうかは見てません)を自動認識する際に その際にPATHが親ディレクトリの方の仮想環境が前につけられてしまいます。

その他の設定は例えばenvなどで違う値を指定していればworktreeの方が優先されて設定されます。

基本的には近い.mise.tomlの設定が優先されるようになっているはずですが、 どうもバグっぽい。

Python virtual env is in wrong order in PATH for nested configs · Issue #4515 · jdx/mise

これを避けるためにはやはりレポジトリ外にworktreeを作る必要があるのですが、 管理が煩雑になるので中に作りたい気持ちがあり、 現状では上のバグがそのうち治ることを期待して、 uvを使った仮想環境ではworktreeではuv run ...のようにして仮想環境を使うようにしています。

Worktree関連のalias

以下のようなGitのaliasを設定しておくと便利です。

.gitconfig
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[alias]
  # worktree
  wt = worktree
  wl = worktree list
  wa = "!f () {\
    if [ $# -eq 0 ];then \
      echo 'Usage: git wa <worktree_name>';\
      return 1;\
    fi;\
    git worktree add .worktree/$1; \
  };f"
  wr = "!f() {\
    if [ $# -eq 1 ] && [ \"$1\" != \"--force\" ] && [ \"$1\" != \"-f\" ];then \
      git worktree remove \"$@\";\
      return 1;\
    fi;\
    wt=$(git worktree list|grep '\\.worktree/'|sentaku -s $'\n'|cut -d ' ' -f1);\
    if [ -z \"$wt\" ];then \
      return;\
    fi;\
    git worktree remove \"$wt\";\
  };f"

wtは単に短縮alias。wlもそのまま。

waはworktree名を指定することで、.worktreeの中にその名前でworktreeを追加します。

1
$ git wa my-worktree

レポジトリ下のいずれかの中にいてもalias内のコマンドはレポジトリルートで実行されるので 感ならず**/.worktree/my-worktree**が作成されます。

worktreeの中からgit waを実行してももとのレポジトリルートの中の.worktreeに作成されます。

wrはworktreeを削除するaliasです。

worktree名が直接渡された場合はそのworktreeを削除します。

引数が与えられないか-f/--forceだけが渡された場合は 現在存在するworktreeの中から選択して削除します。

git worktree listではもとのレポジトリルートの位置も表示されるので、 .worktree/の中にあるものだけを選択できるようにしています。

上ではsentakuを使ってますが、 fzfpeco など好きなもので。

Worktreeの切り替え

aliasだとディレクトリ移動はできないので、 worktreeの切り替えに関しては以下のようなシェルの関数を作って .bashrcなどで読み込んで起きます。

.bashrc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  gitcmd="$(type git 2>&1)"
  ret=$?
  if [ $ret -eq 0 ] && ! echo "$gitcmd" | grep -q 'is a function';then
    git-wc () { # worktree change
      selected=$(command git worktree list|sentaku -s $'\n')
      ret=$?
      if [ $ret -ne 0 ];then
        return $ret
      fi
      if [[ ! -n "$selected" ]];then
        return
      fi
      local dir=$(echo "$selected"|cut -d ' ' -f 1);
      if [[ -d "$dir" ]];then
        cd "$dir"
      else
        echo "Directory $dir does not exist."
      fi
    }

    git () {
      if [ "$1" != "wc" ];then
        command git "$@"
        return $?
      fi
      git-wc
    }
  fi

gitコマンドがある場合、まずgit-wcという関数を定義します。

Sponsored Links
Sponsored Links

« .pre-commit-config.yamlがあるレポジトリで自動的にずpre-commit installされた状態にする

}