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]