While working with Linux on and off for two decades, I never structurally solved the problem of tweaking a new Linux installation to my liking, over and over again.
Storing dotfiles in git
Lately I stumbled on a blog post where the dotfiles were stored in git. Awesome! But it used symlinks or rsync, not exactly my kind of solution. While the time has come again to install a fresh Linux copy, so I searched for a better solution, and behold! The Atlassian Tutorial provided all I needed. Just plain git! No extra tooling neede, no symlinks. Adding config files directly from the home directory. You could even use different branches for different computers.
The trick is using a bare git repository from a custom folder, while mapping the worktree to my home folder. (Hmmm, worktrees sound familiar…) Using a special alias so commands run against the specific repository and do not interfere with my regular repositories.
Starting from GitHub
I’d like to store my dotfiles on GitHub and retrieve them from there to tweak any Linux installation. Files should be added or changed easily. Oke, lets start!
First create a empty git repository on GitHub. Now checkout the repo “bare”:
git clone --bare git@github.com:jkeuper/dotfiles.git $HOME/.cfg
To work with this repository, add an alias:
alias cfgit='/usr/bin/git --git-dir=$HOME/.cfg/ --work-tree=$HOME'
Now you can work with git and this repo by using the cfgit command:
# Add a file
cfgit add .vimrc
# Commit the file
cfgit commit -m "Initial commit"
# Push to origin
cfgit push origin master
Apply dotfiles to New machine
Now we make a script for getting a new machine configured correctly.
Get the dotfiles from git and make backups if files get overwritten.
#/bin/sh
git clone --bare git@github.com:jkeuper/dotfiles.git $HOME/.cfg
function cfgit {
/usr/bin/git --git-dir=$HOME/.cfg/ --work-tree=$HOME $@
}
echo "alias cfgit='/usr/bin/git --git-dir=$HOME/.cfg/ --work-tree=$HOME'" >> $HOME/.bash_aliases
cfgit config --local status.showUntrackedFiles no
cfgit push --set-upstream origin master
cfgit checkout &> /dev/null
if ! [ $? = 0 ]; then
mkdir -p .cfg-backup
cfgit checkout 2>&1 | egrep "\s+\." | awk {'print $1'} | xargs -I{} mv {} .cfg-backup/{}
echo "Backing up pre-existing dot files to ~/.cfg-backup/";
cfgit checkout
# the .bash_aliases is overwritten here with the cfgit alias already present
fi;
Running the script gives the following output:
~# ./.bin/install.sh
Cloning into bare repository '/root/.cfg'...
remote: Enumerating objects: 7, done.
remote: Counting objects: 100% (7/7), done.
remote: Compressing objects: 100% (7/7), done.
remote: Total 7 (delta 1), reused 6 (delta 0), pack-reused 0
Receiving objects: 100% (7/7), done.
Resolving deltas: 100% (1/1), done.
Branch 'master' set up to track remote branch 'master' from 'origin'.
Everything up-to-date
Backing up pre-existing dot files to ~/.cfg-backup/
~#
Wrap up
Now I should start adding more dotfiles!
You can try it out and find the repository here. I’ve added the install script in the “.bin” directory. Use curl or wget to retrieve the install script and execute it with bash in your home folder. Please note, you need to have git installed.
cd ~
curl -s https://raw.githubusercontent.com/jkeuper/dotfiles/master/.bin/install.sh | sh