Sliced bread: git-worktree and bare repo

The git versioning system has two really nice features you might already heard about. One of them is git-worktree and the other are bare git repositories. This makes my life a lot easier working on Samba as often I have several feature branches I’m working on. Some features often take several months to finish. I don’t want to compile them again and again every time I switch branches. So the solution for this are worktrees.

Bare repositories

Lets talk about bare git repositories first. This allows you to clone a git repository and instead of creating a directory and putting the repo in dir/.git it will make the directory the repo and don’t do a checkout of the “main” branch. Lets just do that:

mkdir cmocka
cd cmocka
git clone --bare https://git.cryptomilk.org/projects/cmocka.git .bare

A bare repo by default can’t be used for fetching or checkouts. A lot of git tools like git-fetch or git-checkout etc. need a .git directory. However .git doesn’t have to be a directory, it can also be a a file! The file will tell the git commands where the “.git” directory can be found. Lets do this:

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

The next step is to allow git-fetch to be working. For this we need to fix the .bare/config. Open it with your favorite text editor. Look for the [remote "origin"] and add:

fetch = +refs/heads/*:refs/remotes/origin/*

Run a git fetch.

What you also want is to enable is logAllRefUpdates:

git config --add core.logallrefupdates true

Now we are able to do checkouts, but we don’t use git checkout we will use git worktree instead!

Worktrees

To make life easier we create a bunch of aliases in our ~/.gitconfig to use git-worktree. Open the file with a text editor and either create a section [alias] or add it under the existing section.

wt = worktree
wtl = worktree list
wtb = "!f() { git branch -f $1 $2; git worktree add $1 $1; }; f"
wtbm = "!f() { git branch -f $1 origin/$(git remote show origin | awk '/HEAD branch/ {print $NF}'); git worktree add $1 $1; }; f"
wtr = "!f() { git worktree remove -f $1; git branch -D $1; }; f"

The git wt and git wtl aliases are just shortcuts. The rest to a bit of magic. If we want a main checkout we can do the following now:

git wtb main origin/master

This will do a few steps for us, it will create a local branch main based on origin/main. Then it will create a directory main and o a checkout of the local branch main in there (a worktree). You can now change into the directory and start doing your work. This allows you to have multiple checkouts at the same time and easily work on different feature branches at the same time as a checkout of a branch will be a directory!

git wtbm main2

This will do more the same as above but you don’t have to specify the “origin/main” branch. It will check the remote what is the “main” branch. The branch can have a different name on the remote. So you will end up with a branch named main2, a directory main2 which is tracking origin/main.

Lets have a look what got in git now:

$ git branch
+ main
+ main2
* master

$ git wtl
/home/asn/cmocka/.bare  (bare)
/home/asn/cmocka/main   a79b97c [main]
/home/asn/cmocka/main2  a79b97c [main2]

To get rid of of the main2 worktree and branch, you can do:

git wtr main2

If we check what happend we will see:

$ git branch
+ main
* master

$ git wtl
/home/asn/cmocka/.bare  (bare)
/home/asn/cmocka/main   a79b97c [main]

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *