Workarounds to Git worktree using bare repository and cannot fetch remote branches

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!