Rediscovering Git Worktrees in the AI Era
In the era of AI coding agents, traditional Git workflows (branch switching, rebasing mid-feature, and doing git stash) can quietly become bottlenecks. When you are managing multiple AI agents running in parallel, or simply trying to hotfix production while you are trying to refactor some code, you need true isolation between workspaces.
This article explores Git Worktrees: a built-in Git feature that lets you check out multiple branches simultaneously into separate physical folders, all sharing a single .git database. We walk through the standard worktree setup, then introduce the Bare Clone for cleaner multi-agent organisation. We also compare Worktrees against common alternatives (git stash, multiple clones, and git submodules) and explain why, for AI-driven parallel development, Worktrees probably have the best balance. Whether you are an early adopter of agentic coding tools or just tired of stashing changes, this may improve your workflow.
Lately, we’ve been having discussions with our clients (and internally) about improving the usage of Claude Code (or your preferred Agentic CLI tool). When you integrate AI into your workflow, you want to do a lot of things in parallel. It is not strange to have two terminals open, with an AI CLI making frontend changes in one and handling backend logic in the other. Sometimes you want to explore parallel ideas in the exact same repo, like A/B testing for developers.
How do we handle this? We’ve all used git stash. Were we happy with it? No, we weren’t happy at all.
Probably you faced this situation: You are on a branch. You are making the greatest progress ever. The code is writing itself. You are in an absolute, uninterrupted flow state.
Then, a P0 bug is reported on main, and you need to fix it right now.
What do you do? Typically, we do the whole git add ., throw everything into the stash, switch branches, make the changes, and hope that the stash pops cleanly when we come back. Or worse, we commit halfway-done work just to switch branches without losing our work.
Branch switching like this is tedious. You are leaving the IDE, dependencies, and other things in an unknown state. With the rise of AI coding agents, this isn’t just something you will use from time to time, it is something you will use on a daily basis.
Git Worktrees are not new, but with the new agentic workloads, they are about to become standard practice.
What Actually is a Worktree?
To understand worktrees, we have to unlearn a fundamental misconception about Git. When you run git init or git clone, you create your main working tree. Most developers assume that single folder is the entire repository.
It isn’t.
A linked working tree (what we usually just call a worktree) is simply a branch from your main tree checked out into its own separate, physical folder, with its own state.
Every commit can rebuild the entire repo because Git tracks snapshots, it can just spin up another entry into your repository. You can literally have your feature development in one folder, and your main in another, running side-by-side on your hard drive. They share the same .git database, but they have completely independent working directories.
Alternatives: Why Not Just Use Something Else?
Press enter or click to view image in full size
git stash is the most common alternative. It saves your changes temporarily so you can switch branches. The issue is that it is sequential, error-prone when reverting the stash (stash pop) into modified code, and invisible to your IDE (in IntelliJ IDEA you can use Shelve). It does nothing for true parallel work.
Multiple clones give you full isolation, but they consume significantly more disk space because each clone duplicates the entire .git object store. They also have no awareness of each other, which makes tracking relationships between your branches manual and fragile.
Git submodules solve a different problem: embedding one repository inside another. They are great for modular codebases that share libraries across repos, but they are not designed for running parallel branches of the same codebase.
Git Worktrees hit the sweet spot for AI-era workflows: full branch isolation, a shared Git database (so no object duplication), and fast setup. The trade-off is that dependencies (node_modules, .env files, compiled artifacts) are not shared, since each worktree is a separate physical folder.
Why Now? GenAI Usage
Worktrees have been in Git for years. Why are we talking about them like they are brand new? Because the way we work is changing. We are entering the era of Agentic Coding.
Running multiple tasks in parallel has become completely natural. You aren’t just writing code; you are managing AI agents helping you write code. If you hand a refactoring task to an AI agent, it needs a place to work. It can’t be compiling and changing files in the same directory where you are trying to write a hotfix. They need their own sandboxes.
The tooling ecosystem is finally catching up to this reality with Git worktrees. You can now:
Create a separate worktree for an urgent hotfix.
Hand off another worktree to an AI agent to do a refactor.
Keep working in the main branch.
All at the same time. No interrupted builds. No stashing. Even if you don’t use agents yet, navigating worktrees directly inside IntelliJ will save you massive amounts of time on branch switching, especially in monolithic repositories where indexing takes minutes.
Building Your First Worktree
Architecture
┌──────────────────────────┐
│ awesome-project │
│ (Main Working Tree) │
│ │
│ .git/ (FULL repo) │
│ source code (main) │
└────────────┬─────────────┘
│
┌─────────────────────┼─────────────────────┐
│ │ │
┌────────────────┐ ┌────────────────────┐ ┌────────────────────┐
│ feat-01 │ │ feat-02 │ │ hotfix-01 │
│ Worktree │ │ Worktree │ │ Worktree │
│ │ │ │ │ │
│ .git (pointer) │ │ .git (pointer) │ │ .git (pointer) │
│ → ../.git/... │ │ → ../.git/... │ │ → ../.git/... │
│ source code │ │ source code │ │ source code │
└────────────────┘ └────────────────────┘ └────────────────────┘
Let’s go to the terminal and see this in action. IDE support is great, but using the terminal will work in any place. We are going to create a new worktree for a branch called awesome-project-feat-01.
Just an advice, create the new worktree one folder back from your root repository so you don’t accidentally nest repos inside each other or confuse your linters. This is just advice, all of us have our own way of working, so if this does not align with yours, just do what is best for you.
First, we clone the repo as usual and step inside (let’s think we have an awesome-project in our github):
git clone git@github.com:USER/awesome-project.git
cd awesome-project
From inside your main repo, spawn the worktree:
git worktree add ../awesome-project-feat-01
Preparing worktree (new branch 'awesome-project-feat-01')
HEAD is now at 838d74f Initial commit
The base name of the path (awesome-project-feat-01) will automatically be used as the branch name. Git just prepared a new worktree and checked it out. If you cd ../awesome-project-feat-01, you are standing inside a fully functioning Git repo.
The .git File
If you look around inside your new directory, you’ll notice something is missing. The .git isn't a folder anymore.
cat .git
gitdir: PATH/TO/awesome-project/.git/worktrees/awesome-project-feat-01
It’s just a text file. It simply points a directory path straight back to your main working tree.
Testing the Worktree
Let’s check the worktree is linked to the repository. In your awesome-project-feat-01 folder, make a quick change:
touch test.txt
git add test.txt
git commit -m "chore: adding test in the worktree"
[awesome-project-feat-01 5e35b09] chore: adding test in the worktree
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 test.txt
Now, cd back to your main repository folder (awesome-project) and check the logs for that branch:
git log awesome-project-feat-01
commit 5e35b09db551391731442b37ebb2e7f59fc09c5f (awesome-project-feat-01)
Author: Dionisio Cortés Fernández <yourgithubemail@youremailprovider>
Date: Sat Apr 18 16:13:14 2026 +0200
chore: adding test in the worktree
commit 838d74f2217bfdd7c25c12e2bda93e675f1e6b96 (HEAD -> main, origin/main, origin/HEAD)
Author: Dionisio Cortés Fernández <yourgithubemail@youremailprovider>
Date: Sat Apr 18 16:04:45 2026 +0200
Initial commit
If you check the log for main, the worktree commit isn't there:
git log
commit 838d74f2217bfdd7c25c12e2bda93e675f1e6b96 (HEAD -> main, origin/main, origin/HEAD)
Author: Dionisio Cortés Fernández <yourgithubemail@youremailprovider>
Date: Sat Apr 18 16:04:45 2026 +0200
Initial commit
Here is the folder structure:
├── awesome-project
│ ├── .git
│ ├── .gitignore
│ └── README.md
└── awesome-project-feat-01
├── .git
├── .gitignore
├── README.md
└── test.txt
Your change is right there. It’s the exact same repository, just a different physical directory. You don't have to git stash. You just leave your working tree in whatever state it's in, and simply open the other folder.
Improving the folder organisation
Architecture
┌──────────────────────────┐
│ awesome-project.git │
│ (Bare Repository) │
│ - objects │
│ - refs │
│ - worktrees │
└────────────┬─────────────┘
│
┌────────────────────────┼────────────────────────┐
│ │ │
┌───────────────┐ ┌────────────────┐ ┌────────────────┐
│ main │ │ feature-01 │ │ feature-02 │
│ Worktree │ │ Worktree │ │ Worktree │
│ │ │ │ │ │
│ .git → link │ │ .git → link │ │ .git → link │
│ source code │ │ source code │ │ source code │
└───────────────┘ └────────────────┘ └────────────────┘
The previous approach is good, but it is inconvenient. If you do a standard clone, your root folder is permanently attached to the main branch. If you want to spin up a worktree for main somewhere else, Git won't allow you.
If you are setting up a repository specifically to run multiple AI agents or handle massive parallel refactoring, you may want to try the Bare Clone. It clones the .git database and nothing else. No working files. No checked-out branches. It is purely the database of the repository. In order to achieve that we can follow the following steps:
Step 1: The main Directory
Create a main directory to act as the home base for all your parallel branches.
mkdir awesome-project-workspace
cd awesome-project-workspace
Clone the repo as a BARE repository
git clone --bare git@github.com:USER/awesome-project.git
Step 2: Inform Git Where the Database Is
We need to tell Git that this .git folder is the actual repository database for this entire project.
echo "gitdir: ./awesome-project.git" > .git
Step 3: Spawn Your Worktrees
Because there is no default working tree attached, you can spin up main as its own dedicated folder, right alongside your feature branches inside the workspace folder.
Spawn the main branch:
git worktree add main
Preparing worktree (checking out 'main')
HEAD is now at 838d74f Initial commit
Spawn a feature branch for yourself:
git worktree add feature-01
Preparing worktree (new branch 'feature-01')
HEAD is now at 838d74f Initial commit
Spawn a sandbox for your AI agent:
git worktree add feature-02
Preparing worktree (new branch 'feature-02')
HEAD is now at 838d74f Initial commit
If you run an ls -la in your workspace folder, here is the absolute beauty you will see:
ls -la
total 28
drwxrwxr-x 6 dio dio 4096 abr 18 19:00 .
drwxrwxr-x 4 dio dio 4096 abr 18 16:30 ..
drwxrwxr-x 8 dio dio 4096 abr 18 18:34 awesome-project.git
drwxrwxr-x 2 dio dio 4096 abr 18 18:47 feature-01
drwxrwxr-x 2 dio dio 4096 abr 18 19:00 feature-02
-rw-rw-r-- 1 dio dio 30 abr 18 16:51 .git
drwxrwxr-x 2 dio dio 4096 abr 18 18:34 main
Here is the mental model for the Bare Clone architecture:
├── awesome-project.git
│ ├── branches
│ ├── config
│ ├── description
│ ├── HEAD
│ ├── hooks
│ ├── info
│ ├── objects
│ ├── packed-refs
│ ├── refs
│ └── worktrees
├── feature-01
│ ├── .git
│ ├── .gitignore
│ └── README.md
├── feature-02
│ ├── .git
│ ├── .gitignore
│ └── README.md
├── .git
└── main
├── .git
├── .gitignore
└── README.md
Managing Your Worktrees
To see all the different dimensions you currently have open on your machine, run:
git worktree list
You’ll get a clean output showing your main bare tree, your linked branches, and exactly which commit hash each one is sitting on.
/PATH/TO/YOUR/REPO/awesome-project.git (bare)
/PATH/TO/YOUR/REPO/feature-01 838d74f [feature-01]
/PATH/TO/YOUR/REPO/feature-02 838d74f [feature-02]
/PATH/TO/YOUR/REPO/main 838d74f [main]
How to Remove Them
When you are done with a feature, cleaning up is helpful to have a clean structure. You have two options:
Option 1: The git command
git worktree remove feature-02
git worktree list
/PATH/TO/YOUR/REPO/awesome-project.git (bare)
/PATH/TO/YOUR/REPO/feature-01 838d74f [feature-01]
/PATH/TO/YOUR/REPO/main 838d74f [main]
Option 2: The rm command
You can just remove the folder from your filesystem using standard terminal commands.
Let’s delete feature-01:
rm -rf /PATH/TO/YOUR/REPO/feature-01
If you do this, Git will notice the physical files are gone but will still hold onto the metadata in its internal tracking, marking it as prunable.
git worktree list
/PATH/TO/YOUR/REPO/awesome-project.git (bare)
/PATH/TO/YOUR/REPO/feature-01 838d74f [feature-01] prunable
/PATH/TO/YOUR/REPO/main 838d74f [main]
To clean up the ghost references, just run:
git worktree prune
git worktree list
/PATH/TO/YOUR/REPO/awesome-project.git (bare)
/PATH/TO/YOUR/REPO/main 838d74f [main]
Conclusion
There are trade-offs (as always)
Good things:
Zero context switching: No more waiting for your IDE to re-index your entire project just because you switched branches.
No Stashing: Never lose track of half-baked changes again.
AI agent enabler: Perfect, isolated sandboxes for parallel development and AI tools.
Not that good things:
Dependencies: If you have to npm install heavily, download Maven packages, or compile a massive Rust project from scratch, that takes time for every new worktree. It's a brand new physical folder, so your node_modules or target directories don't come with you.
Environment variables: Your .env files are (hopefully) git-ignored. That means when you create a new worktree, your .env file won't be there. You have to manually copy it over to the new directory to get your app running.
In agentic workflows this approach makes a lot of sense as Git worktrees provide the filesystem isolation necessary to operate in parallel on different branches without interfering with one another.
If your project builds reasonably fast, or if you are leveraging parallel AI workflows, Git worktrees may be helpful.
Resources
Official Git Worktree Documentation
Git 2.5 Release Notes (including multiple worktrees and triangular workflows)


