Fundamentals 11 min read

Master Git Bare Repositories and Advanced Worktree Techniques for Clean Multi‑Branch Development

This tutorial explains how bare Git repositories differ from non‑bare ones, shows how to create and configure a bare repo, and demonstrates an advanced Git worktree workflow that keeps all branch worktrees organized within a single project directory for seamless multi‑branch development.

Programmer DD
Programmer DD
Programmer DD
Master Git Bare Repositories and Advanced Worktree Techniques for Clean Multi‑Branch Development

Introduction

The previous article introduced Git worktree and how it lets you work on multiple branches simultaneously without interference. However, the worktree directories are created outside the current project, which can be inconvenient for users who prefer tidy disk management. This guide presents an advanced method using bare repositories to solve that problem.

Prerequisites

Before using the advanced technique, you need to understand the concept of a bare repo. Start with the familiar commands:

git init
git clone https://github.com/FraserYu/amend-crash-demo.git

These commands create a non-bare repo, which contains your project files and is where you normally add, commit, pull, and push.

To create a bare repo, simply add the --bare flag:

git init --bare
git clone --bare https://github.com/FraserYu/amend-crash-demo.git

Running these clone commands and inspecting the files reveals the differences.

bare repo

contains only Git metadata and no project files such as .java, .js, or .py. In contrast, a non-bare repo holds all source files.

The default name of a bare repo ends with .git, confirming the first point.

A bare repo lacks a working .git directory, so you cannot perform add, commit, pull, or push directly on it.

Although a bare repo may seem empty, its immutability makes it ideal for a centralized private repository, preventing accidental modifications.

You can try the following commands locally to experiment:

user@server:$~  git init --bare name_to_repo.git

user@machine1:$~ git clone user@server:/path/to/repo/name_to_repo.git .
user@machine1:$~ cd name_to_repo
user@machine1:$~ touch README
user@machine1:$~ echo "Hello world" >> README
user@machine1:$~ git add README
user@machine1:$~ git commit -m "Adding a README"
user@machine1:$~ git push origin master

user@server:$~ ls /path/to/repo/name_to_repo.git/
branches/ config description HEAD hooks/ info/ objects/ refs/

user@machine2:$~ git clone user@server:/path/to/repo/name_to_repo.git .
user@machine2:$~ ls name_to_repo.git/
README
user@machine2:$~ cat README
Hello world
The result shows that no matter how many files you push from machine1, the bare repo never stores those files—only Git metadata—while machine2 can see the pushed files after cloning, demonstrating Git's magic.

Now, leveraging the bare repo's properties, we can improve the multi‑branch workflow introduced in the previous Git worktree article.

Advanced Git Worktree Usage

Create a dedicated folder for your project (e.g., amend-crash-demo) and enter it:

mkdir amend-crash-demo
cd amend-crash-demo

Clone the project as a bare repository into a .bare directory:

git clone --bare [email protected]:FraserYu/amend-crash-demo.git .bare

Create a .git file that points to the .bare directory using the gitdir syntax:

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

Edit .bare/config to ensure the remote origin is correctly defined:

vim .bare/config

# -----------------------------------------------
[remote "origin"]
    url = [email protected]:FraserYu/amend-crash-demo.git
    fetch = +refs/heads/*:refs/remotes/origin/*

Add a worktree for the main branch:

git worktree add main
# Preparing worktree (checking out 'main')
HEAD is now at 82b8711 add main file

Then create a feature worktree, for example feature/JIRA234-feature3:

git worktree add -b "feature/JIRA234-feature3" feature3
# Preparing worktree (new branch 'feature/JIRA234-feature3')
HEAD is now at 82b8711 add main file

Listing the directory shows only the visible worktree folders ( main and feature3) while .bare and .git remain hidden, keeping the workspace clean:

ls -l
# total 0
# drwxr-xr-x 10 rgyb staff 320 Nov 23 21:44 feature3
# drwxr-xr-x 10 rgyb staff 320 Nov 23 21:36 main

ls -al
# total 8
# drwxr-xr-x   6 rgyb staff 192 Nov 23 21:44 .
# drwxr-xr-x   3 rgyb staff  96 Nov 23 21:14 ..
# drwxr-xr-x  12 rgyb staff 384 Nov 23 21:36 .bare
# -rw-r--r--   1 rgyb staff  16 Nov 23 21:29 .git
# drwxr-xr-x  10 rgyb staff 320 Nov 23 21:44 feature3
# drwxr-xr-x  10 rgyb staff 320 Nov 23 21:36 main

Now you can work independently on each branch, performing add, commit, pull, and push without interference:

echo "feature3 development" > feature3.yaml
git add feature3.yaml
git commit -m "feat: [JIRA234-feature3] feature3 development"
git push --set-upstream origin feature/JIRA234-feature3

The four core worktree commands from the previous article make multi‑branch collaborative development straightforward:

git worktree add
git worktree list
# /Users/rgyb/Documents/projects/amend-crash-demo/.bare        (bare)
# /Users/rgyb/Documents/projects/amend-crash-demo/feature3   aeaac94 [feature/JIRA234-feature3]
# /Users/rgyb/Documents/projects/amend-crash-demo/main        82b8711 [main]

git worktree remove
git worktree prune

Conclusion

By exploiting the characteristics of a bare repository, you can keep all worktrees neatly managed within the project directory, enabling clean multi‑branch collaborative development.

.
└── amend-crash-demo
    ├── feature3
    │   ├── README.md
    │   ├── config.yaml
    │   ├── feat1.txt
    │   ├── feature3.yaml
    │   ├── file1.yaml
    │   ├── hotfix.yaml
    │   ├── main.properties
    │   └── main.yaml
    └── main
        ├── README.md
        ├── config.yaml
        ├── feat1.txt
        ├── file1.yaml
        ├── hotfix.yaml
        ├── main.properties
        └── main.yaml

3 directories, 15 files

If you are particular about disk organization, this method is an excellent solution.

To fully understand the process, examine the Git‑related files while executing the commands.

References

https://www.blopig.com/blog/2017/06/using-bare-git-repos/

https://lists.mcs.anl.gov/pipermail/petsc-dev/2021-May/027448.html

https://www.saintsjd.com/2011/01/what-is-a-bare-git-repository/

https://infrequently.org/2021/07/worktrees-step-by-step/

https://morgan.cugerone.com/blog/how-to-use-git-worktree-and-in-a-clean-way/

software engineeringVersion ControlGit worktreeBare Repositorymulti-branch development
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.