How i organized my dotfiles

How i organized my dotfiles using git.

It seems appropriate to start this post off with giving an explanation as to why i would want to do this.

Luckily this is simple to explain; I’m a lazy fucker, that’s why. No really, that’s pretty much all there is too it. I simply wanted to make the process of syncing my dotfiles to and from multiple of my systems (most notably my laptop and my desktop) easier.

I used to do this manually, where i had set up a repo where i would manually cp and then mv my config files into them, but this took minutes. Like i said, I’m lazy and had time on my hands.

How i did it

I took some inspiration from atlassian’s blogpost. They also took some inspiration so it’s a https://youtu.be/Lr-KHezBqX0?t=242 typa situation we got on our hands.

With that disclosure out of the way; here’s how i did it.

To get things started i set up a bare git repo in my home dir named .cfg (cfg is short for config). I had actually never even heard of a bare repo, but after learning about it, it really seemed the play to sync and manage my dotfiles. To keep things short, the advantage of a bare repo is that I’m tracking the actual config files themselves, instead of symlinking or manually copying my config files to a working directory.

I did this by doing a simple git init --bare $HOME/.cfg. All this does is create a bare git repo inside $HOME, or in other words home sweet home.

After that i set up the alias config='/usr/bin/git --git-dir=$HOME/.cfg/ --work-tree=$HOME'. We do this so we have a simple command we can use where-ever we are in our system to interact with our config files. This works by executing git and specifying that we are using the $HOME/.cfg repo. We also set the working tree, aka the directory which our git repo is supposed to be tracking. Since we are managing our dotfiles, we are tracking $HOME. If you are a more organized user than i am, you could do all of this inside ~/.config.

I simply put this alias inside my .zshrc, since that’s my preferred shell.

Then we tell our git repo to not show us any untracked files by setting config config --local status.showUntrackedFiles no this flag. All this does is make sure we aren’t bombarded with a huge list of untracked files when doing config status.

That was all when it comes to setting up our local repo. We’ve now successfully set up a git repo to locally sync our files. But you might ask, how do i access this repo from a different machine? And to be honest, that’s a great question. I used github for this, but you can use whatever you want.

If you do decide to use github you need to add the remote repository to you local configuration (something you need to do for any remote repo). I simply ran config remote add origin git@github.com:<your username>/<name of your gh repo>.git

Keep in mind that you do need valid SSH keys for this to work, i had to generate a pair and add them to my github account.

After this you are able to push and pull to your remote github repo using all your regular git commands, but instead of git we are using the config alias that we just setup. Imagine running commands like config commit -am "rewrite nvim config", config status, config push,…

We currently have this git repo setup on one machine, but there are a few steps to get it setup on another machine.

First things first is setting up a safety net on our local machine before pushing it to remote. We don’t want to be encountering any weird recursion scenarios, and to make sure this does not happen is by adding .cfg to our .gitignore. One can do this by running echo ".cfg" >> .gitignore. Then we add this file to our git repo by running config add .gitignore. Make sure to also push this to the remote repo by committing it and pushing doing config commit -am "add .cfg to .gitignore" and config push.

After setting up our safety net, we are safeguarded from any recursion issues and we are ready to clone to another machine.

To clone our repo simply run git clone --bare <git-repo-url> $HOME/.cfg. This command clones the repo to .cfg located in your home directory. After cloning we set up a alias in our current shell scope by running alias config='/usr/bin/git --git-dir=$HOME/.cfg/ --work-tree=$HOME'. We do this in this scope because your freshly pushed dotfiles should contain this alias, so if you haven’t added it already now is the time.

When we have the repo cloned we are ready to checkout our freshly cloned repo. In simple terms, this deploys our dotfiles on our system. To do this, run config checkout. You might get an error about overwriting files. To “fix” this error we are going to be moving the files that are giving us trouble into a different folder named .config-backup. We do this in the off-chance anything goes wrong.

Run

sudo mkdir -p .config-backup && \
config checkout 2>&1 | grep -E "\s+\." | awk {'print $1'} | \
while read -r file; do
    dir=$(dirname ".config-backup/${file}")
    mkdir -p "${dir}"
    mv "${file}" ".config-backup/${file}"
done && config config --local status.showUntrackedFiles no

This is mostly freeloading off the original guides script, but i had an issue where it didn’t create parent directories so i added the while loop with a little bit of help from my buddy ChatGPT. I also added the config config --local status.showUntrackedFiles no line at the end, so we don’t have to run that separately. Like i said, I’m lazy.

Once that has run without any errors you’re done, you can now clone and sync your dotfiles on as many systems as you want.

Related
Linux