Managing your git config using dotbot
Posted 19 June 2022 in dotbot, dotfiles, and gitI'm using both Linux and Windows for work and personal computing, and that has finally pushed me to start tracking my dotfiles in a git repository. I settled on a dotfiles manager named dotbot because it's written in Python and, with some effort, works well on Windows.
Initial setup
My initial attempt to manage my git config was simple: track ~/.gitconfig in a git repo and use dotbot to create a symlink to it.
My dotfiles directory
dotfiles/
│ dotbot.yaml
│
└── shared/
└── git/
gitconfig.ini
dotbot.yaml
link:
~/.gitconfig: shared/git/gitconfig.ini
This configuration meant that dotbot would create a symlink from ~/.gitconfig to the gitconfig.ini file in my dotfiles repository.
This worked well, but I quickly encountered a problem.
Challenge 1: Platform-specific configurations
I wanted to start signing my git commits; my git configuration was mostly shared between both Windows and Linux, but to sign commits on Windows I have to specify the absolute path to the GPG executable. This would break things on Linux, so I could no longer share my git config as a single file.
Luckily, git supports an include.path config option which will include the contents of another file directly into your .gitconfig file.
By splitting my Linux- and Windows-specific git config options into separate files, dotbot can then symlink the correct file to a known location, and my .gitconfig file can include a generically-named platform-specific file.
My dotfiles directory
dotfiles/
│ dotbot-linux.yaml
│ dotbot-windows.yaml
│
└── shared/
└── git/
gitconfig.ini
linux.ini
windows.ini
gitconfig.ini
[include]
path = .gitconfig-platform-specific
dotbot-linux.yaml
link:
~/.gitconfig: shared/git/gitconfig.ini
~/.gitconfig-platform-specific: shared/git/linux.ini
dotbot-windows.yaml
link:
~/.gitconfig: shared/git/gitconfig.ini
~/.gitconfig-platform-specific: shared/git/windows.ini
This setup means that git will include a file named .gitconfig-platform-specific in my home directory on both Windows and Linux. Thanks to dotbot, that file will exist and point to the correct git config file for whichever platform it's running on.
However, I encountered another problem.
Challenge 2: Constant changes to .gitconfig
I use various git tools that store their configuration in .gitconfig. In many cases, that "configuration" is simply a list of recently-opened repositories.
As a result, my git config frequently contains garbage, transient changes. I want the tools to continue showing me useful lists of recent repos, but I don't want my dotfiles repo to have merge conflicts when synchronizing changes.
I tried several ways to deal with this:
Commit a clean gitconfig.ini file, then git-ignore it.
This doesn't work because git can only ignore files that are untracked in the git repo. Once gitconfig.ini is committed, it cannot be ignored.
Run git update-index --skip-worktree <path>.
This could work, but makes it impossible to change branches in my dotfiles repo. This turned out to be a major headache.
In the end, my solution was to move all of the shared git configuration to a common.ini file, then have ~/.gitconfig include that file. dotbot was then used to copy -- NOT symlink -- the .gitignore file.
My dotfiles directory
dotfiles/
│ dotbot-linux.yaml
│ dotbot-windows.yaml
│
└── shared/
└── git/
gitconfig.ini
linux.ini
shared.ini
windows.ini
gitconfig.ini
[include]
path = .gitconfig-common
path = .gitconfig-platform-specific
dotbot-linux.yaml
- shell:
- description: "Copy shared/git/gitconfig.ini to ~/.gitconfig (if needed)"
command: >
if [ ! -e ~/.gitconfig ]; then
cp shared/git/gitconfig.ini ~/.gitconfig;
fi
link:
~/.gitconfig-common: shared/git/common.ini
~/.gitconfig-platform-specific: shared/git/linux.ini
dotbot-windows.yaml
- shell:
- description: "Copy shared/git/gitconfig.ini to ~/.gitconfig (if needed)"
command: >
pwsh -c "
if (! (test-path ~/.gitconfig)) {
copy-item shared/git/gitconfig.ini ~/.gitconfig
}
"
link:
~/.gitconfig-common: shared/git/common.ini
~/.gitconfig-platform-specific: shared/git/windows.ini
My home directory
~/
.gitconfig
.gitconfig-common -> shared/git/common.ini
.gitconfig-platform-specific -> shared/git/windows.ini
Thus, ~/.gitconfig is relegated to being a transient file that I categorically ignore. All of my real configuration is stored in included files!
What this means for you
First, if you're not using a dotfiles manager, I recommend doing so.
Second, if you're a software author, please consider splitting the transient configuration -- like lists of recent files -- into a separate configuration file. That'll allow people like me to store valuable settings in a git repo without constant updates. Thanks!