Rob O'Hare

Git, organised

As part of setting up this here website I thought I should also make an attempt to properly organise my code repositories. I've had quite a few (online) repositories over the years — I started with Github, then moved to Gitlab, then got a Bitbucket repo for my (then) daytime job and eventually added a Codeberg repo to the list. It's all become a bit of mess and the plan is to consolidate things.

I now have two separate Codeberg repositories; one for a new business I haven't launched yet and another for personal projects. My personal repo is pretty much empty at the moment. I didn't want to just blindly move my fancy shell scripts to the new Codeberg repo. Most of them haven't had any love for quite some time — it are mainly shell scripts I wrote and then forgot about. I want to take some time to decide which scripts are worth keeping and then actively maintain the survivors.

Local configuration

I've also reorganised the repos on my workstation. Both Codeberg repos now have their own directory and I use conditional includes to load configuration settings for specific directories. In other words, specific git settings are loaded depending on whether I'm in my rohare directory, the directory for my secretive new business venture or any other directory. This is what my local git configuration looks like:

[init]
    defaultBranch = main

[user]
    name = Rob O'Hare
    email = mail@example.com

[includeIf "gitdir:~/git/codeberg/rohare/"]
   path = ~/git/_identities/codeberg-rohare.gitconfig

[includeIf "gitdir:~/git/codeberg/censored/"]
    path = ~/git/_identities/codeberg-censored.gitconfig

The init and user tables define the default settings and the two includeIf tables define the configuration files that should be used for the included directories. The reason I defined default settings is two-fold: I always use "main" as the name of the initial branch (so I don't have to repeat that in the directory-specific config files) and I mostly use git for ad hoc version control. When I have a brilliant idea for, say, the Hugo theme of this website I typically use git to quickly make a backup of the theme, so that I can revert everything should my idea turn out to be not so brilliant. Either way, I can then delete the .git directory and move on with my life.

Another thing worth noting is that the included configuration is inherited by subdirectories. So, ~/git/_identities/codeberg-rohare.gitconfig is automatically used when I work in say, ~/git/codeberg/rohare/snippets. The "conditional includes" are quite flexible and really handy. They are also very well documented in man 1 git-config.

SSH configuration

In the included configuration files I use insteadOf variables to rewrite URLs. Here's an example:

[url "ssh://git@codeberg-rohare"]
    insteadOf = ssh://git@codeberg.org

The above rule tells git to automatically rewrite ssh://git@codeberg.org to ssh://git@codeberg-rohare. The hostname codeberg-rohare is defined in my SSH configuration, which among others specifies which IdentityFile (i.e. SSH key) to use when talking to the remote repository. In other words, git automatically tells SSH how to connect to a repo when I run a command like git push.

Another way to do the exact same thing is to use the sshCommand variable in the configuration file:

[core]
    sshCommand = 'ssh -i /path/to/public_key'

I gather there are some pros and cons to either approach. For people with simple git needs either will do the job just fine.

Documentation (and don't forget about the manual)

While organising the git repos I noticed I had made a half-hearted attempt to do so a while back. I was reminded of that because of this configuration file in my .bashrc.d directory:

# This breaks everything
#export GIT_CONFIG=~/.config/git/gitconfig

At the time my aim was to move configuration files in my home directory to the ~.config directory (yes, I'm that kind of person). As the comment suggests, setting $GIT_CONFIG had some funny results. Commands such as git config list would show the correct settings but those same settings were ignore when using commands like git init or git commit.

I clearly didn't manage to solve that puzzle at the time. Nowadays, I have a best friend (called Chatbot) but he couldn't figure out the issue either. However… a quick search in the above-mentioned git-config man page did give me the answer. There are two problems with the configuration:

  1. The config file should have been ~/.config/git/config instead of ~/.config/git/gitconfig. That works out of the box, provided $XDG_CONFIG_HOME is set to ~/.config.
  2. The $GIT_CONFIG environment variable is used when no --file option is provided to git config. That's all the environment variable does, so that explains why git config commands showed the correct settings and why other git command ignored the settings. In effect, the configuration file didn't exist.

Of course, I will have forgotten all this in no time whatsoever. So, I've also added a README file in my ~/git directory with a brief summary of how everything is configured. That's something I've started doing for lots of stuff (SSH, Ansible, website projects etc.). Writing the documentation is often enough to internalise how things are configured, and if it doesn't then I can quickly remind my ageing brain cells.