Atomic Habit in Emacs - Keep Git Repos Clean14 Jan 2024
Table of Contents
I am having a hard time keeping my git repositories clean: there are just too many repositories, I counted 31 in total, and I have 5 computers where I work on them.
The consequence is that sometimes I get surprised at seeing a lot of seemingly useful changes that are not committed to the git repo. I had to stop whatever I was doing to just think about what to do with those changes. It breaks the flow!
There are other occasions where I thought I fixed some bugs, but I don’t have the patches on my laptop. It turned out I didn’t check in to the cloud, so I have to log back to the right server to run a couple of git commands, or if I don’t have access to the servers, I have to fix the bugs from scratch again. It is inefficient!
It can happen a lot in active projects where I work on multiple systems and multiple git repos or when I travel. I plan to revisit my filesystem (which is inspired by Stephen Wolfram 1) and tech setup to reduce the number of repos by merging them and keeping only 1 laptop, 1 workstation and 1 server. This is something for summer, it can reduce the severity of the problem but can not eliminate it.
At the moment, I just have to become more disciplined in managing files, e.g. to have an atomic habit of checking my git repo regularly, or at least do it once at the end of the day, or as part of the shutdown ritual after finishing a task2.
Emacs Lisp Helper
The 3rd Law of Behavior Change is make it easy.
James Clear, Atomic Habit
To facilitate the forming of this habit, I implemented a utility
function in Lisp to list the dirty git repo, and provide a clickable
link to the
magit-status buffer of the git repo. With one click on
the hyperlink, I can start to run git commands via the mighty
package. I bind this action to keystroke
The workhorse is the
git status --porcelain command: If the git repo
is clean, it returns nothing, otherwise, it outputs the file names
whose changes are not checked in, e.g. the first file is modified (M),
and the second file is not untracked (??).
The rest of the code is for parsing the outputs and turning them into a user-friendly format in Org-mode. What’s interesting is that The org-mode provides a kind of hyperlink that evaluates Lisp expressions, using the example below,
The description of the hyperlink is “Git Status of Repo /foo” , after
I click it, it runs the expression
(magit-status "/foo") which shows
the git status of /foo repo in a dedicated buffer.
Before executing it will ask for a confirmation. It can be a bit
annoying and inconvenienced at first which naturally leads to the
temptation of removing this behaviour by setting
org-link-elisp-confirm-function to nil. I discourage you from doing
so in case someone embeds funny codes, (for example
rm -rf ~/) in
a hyperlink, so make sure to check that variable’s documentation
before changing it3!
It was fun to write the lisp functions. I learnt how to use the
optional function argument and
interactive so that the function can
be used both interactively and pragmatically. I’m very much wanting to
spend more time in coding, to enhance it with some ideas I got from
reading Xu Chunyang’s
However, the effectiveness of those functions has little to do with the extra features I had in mind but really depends on how I use them. Solving the problems requires deliberate practise and changing my behaviours so that cleaning git repos becomes a habit of mine, which is always the hardest part.
One key indicator for this habit5 can be the number of check-ins and see if there’s a substantial increase from today.