Skip to content
Go back

Git Worktrees

Updated:

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:

Setup:

Assuming the repo is already hosted somewhere.

  1. Create a root folder for the project.

    mkdir MyApp && cd MyApp
  2. Clone history of the repo

    git clone --bare --config remote.origin.fetch="+refs/heads/*:refs/remotes/origin/*" git@gh.com:u/repo.git .bare
    • clone --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 to origin/*. We add it back, so our client could see the branches in remote.
    • .bare: We name this folder .bare (usually its .git).
  3. Let tooling know that .bare is the .git directory.

    echo "gitdir: ./.bare" > .git

    This 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/ ...
  4. Add a worktree

    git worktree add main

    syntax is: git worktree add <worktree_path> -b <branch_name>

    The sample command will create a worktree folder in path main and will try to checkout or create a branch named main.

    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
        └── ...
  5. Profit

    Open the worktree folder main in IDE to work on it. Add more worktrees if needed.

  6. 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.



Next Post
KMP Primer