Workarounds to Git worktree using bare repository and cannot fetch remote branches
Posted on
Context
This post echoes to an inefficiency I faced after adding Git worktrees to my workflow in the manner described in How to use git worktree and in a clean way.
The issue
After a while using git worktrees and willing to add a worktree based upon a
remote branch from origin
, I discovered that I just could not.
It was very frustrating.
A bit of googling helped me to identify the root cause.
The root cause
The root cause, does not come down to the use of Git worktrees, but rather to the way I use them.
Indeed, I use Git worktrees in combination of bare repositories.
I discovered, as described in the Git documentation about making a
bare
repository,
that when using git clone
with the --bare
option:
neither remote-tracking branches nor the related configuration variables are created.
That basically means that when you try to git fetch
from your remote (e.g
origin
), the remote branches are not downloaded.
The reason for this is that the configuration of the repository does not get
populated with the remote.origin.fetch
property at the clone operation.
A short-term workaround
In the repository's directory, open up your $GIT_DIR/config
file (e.g.
.git/config
or in my case .bare/config
) and add a new line under [remote "origin"]
:
fetch = +refs/heads/*:refs/remotes/origin/*
In the event you do not fancy editing manually the configuration file you can also run the following command:
git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
Below is an excerpt of the configuration file with the remote.origin.fetch
property correctly configured:
[remote "origin"]
url = …
fetch = +refs/heads/*:refs/remotes/origin/*
Now, any git fetch origin
or git worktree add...
command will, when
necessary, retrieves the remote branches that are missing locally.
My long-term workaround
As much as I was happy with the short-term workaround I wanted to save me the hassle of this manual step when cloning a new repository into a bare one.
Therefore I came up with a script that I use when cloning repositories for use with git worktree.
Actually not only, it does the work of making the $GIT_DIR
how I
want it (i.e in .bare
), it does also the under laying work of setting the
remote.origin.fetch
property into the newly created bare repository and
fetches all remote branches.
#!/usr/bin/env bash
set -e
# Examples of call:
# git-clone-bare-for-worktrees git@github.com:name/repo.git
# => Clones to a /repo directory
#
# git-clone-bare-for-worktrees git@github.com:name/repo.git my-repo
# => Clones to a /my-repo directory
url=$1
basename=${url##*/}
name=${2:-${basename%.*}}
mkdir $name
cd "$name"
# Moves all the administrative git files (a.k.a $GIT_DIR) under .bare directory.
#
# Plan is to create worktrees as siblings of this directory.
# Example targeted structure:
# .bare
# main
# new-awesome-feature
# hotfix-bug-12
# ...
git clone --bare "$url" .bare
echo "gitdir: ./.bare" > .git
# Explicitly sets the remote origin fetch so we can fetch remote branches
git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
# Gets all branches from origin
git fetch origin
I have even been one step further by binding this script to a git alias as
shown in below .gitconfig
file excerpt:
[alias]
clone-for-worktrees = "!sh $HOME/git-clone-bare-for-worktrees.sh"
Thus I can run git clone-for-worktrees git@github.com:name/my-awesome-project.git
and be all set for using the my-awesome-project
with git worktrees.
Conclusion
That's all folks.
No matter which solution you pick, as long as it lets you persist using git
worktrees I'm happy. There are an awesome feature from git!