Worktrees enable having multiple branches checked out at the same time.
You could just clone the whole repo to a new folder to have a different branch checked out.
MyApp/
MyApp-hotfix/
MyApp-featureX/
But with worktrees you can use the existing repo to generate more folders containing different branches.
MyApp/
├── .git
├── main/
├── hotfix/
└── featureX/
Why
In mobile, quickly switching branches for a bugfix/review doesn’t really work. With heavily compiled projects a branch switch can cause a long recompilation. Its more efficient to have multiple variants ready on disk.
With AI, having multiple variants allows parallelizing the work agents and you are doing.
Why worktrees
You’ll have a single shared .git folder:
- All local branches can interact with eachother.
- Remote updates are fetched together - It’s still a single git repo on disk.
- Less wasted storage.
Setup:
Assuming the repo is already hosted somewhere.
-
Create a root folder for the project.
mkdir MyApp && cd MyApp -
Clone history of the repo
git clone --bare --config remote.origin.fetch="+refs/heads/*:refs/remotes/origin/*" git@gh.com:u/repo.git .bareclone --bare: will copy the repository, but will not populate the source files (worktree) on disk. We want the sources to be populated in separate folders later.--config remote.origin.fetch: Because bare is intended for git server, it omits the configuration of mapping remote branches toorigin/*. We add it back, so our client could see the branches in remote..bare: We name this folder .bare (usually its .git).
-
Let tooling know that .bare is the .git directory.
echo "gitdir: ./.bare" > .gitThis allows you to use git commands in the root folder. Having .git as a config file, instead of a folder named .git, results in IDEs etc. understanding that we have a special setup, as opposed to a standard repository.
Repo state now:
MyApp/ ├── .git <-- File that points to .bare └── .bare/ <-- Repo history ├── config ├── HEAD └── objects/ ... -
Add a worktree
git worktree add mainsyntax is:
git worktree add <worktree_path> -b <branch_name>The sample command will create a worktree folder in path
mainand will try to checkout or create a branch namedmain.Repo now:
MyApp/ ├── .git <-- Points to .bare ├── .bare/ <-- Repo history └── main/ <-- Project source files (Worktree) ├── .git <-- Points to the shared .bare git dir at root. ├── app/ ├── build.gradle └── ... -
Profit
Open the worktree folder
mainin IDE to work on it. Add more worktrees if needed. -
Managing worktrees
List them by:
$ git worktree list /Users/me/MyApp (bare) /Users/me/MyApp/main 7ac0703be [main] /Users/me/MyApp/feature aa45c02a1 [feature/fix-123]Delete:
git worktree remove <worktree_path>Note: Renaming/deleting the worktree folders manually (i.e. without git) needs caution, as the shared .git is refering to those folders.
Extra
Why not just open an existing repo and worktree add straight away?
You can, but then that worktree would appear alongside the existing source files. So its messy and you have to .gitignore it. Structure:
MyApp/ <-- Existing repo and worktree
├── .git/
├── app/ <-- Existing files
├── build.gradle <-- Existing files
├── Hotfix-123/ <-- New worktree with new source files
└── ...
Worktrees in practice
It is more beneficial to have persistent worktrees named by the kind of work you are doing. Such as: work, review, side-work. This means that you are just switching branches inside an existing worktree, as opposed to creating new worktree/folder for each branch.
With this you can use your IDE to switch branches. And since you are not opening new folders, you don’t have to do the full new project setup again.