Here’s a sequence of git aliases I use to make my editing process, for writing and coding, much quicker and easier.

  1. git patch <file> <temp-output-file>
  2. git cache <temp-output-file>
  3. git staged
  4. git date <date> <time>

Let me explain why, and how each one works.

Knowing why

Creating my Node package diffcraft (though it’s still really a proof of concept) has revolutionised my editing process.

For years now, I’ve been in the habit of typing any prose I write into Markdown format and using Git to track the changes I make over time. This has the added benefit of being able to use commit messages to explain why I’m making changes, so I can not only look back at what the changes were, and when they were made, but also why I made them.

Before my aliases

For a long time, committing edits I’d made was either quite crude or took a lot of time and effort.

I’d either have to:

  1. commit granular changes as I made them,
  2. commit a whole chunk of changes all at once even though each change within that chunk might have different reasons for being, or
  3. laboriously edit hunks when committing.

The first option is a poor experience when it comes to creatively editing.

Imagine it. Every time you make a change, you have to decide if that’s the whole change and then commit it, and explain in a message why you’ve made the change. This is context-switching of an extreme sort. It mixes creative problem-solving with analytical reasoning. It interrupts your flow.

So, if you don’t want to keep stopping what you’re doing to explain why you’re doing it before you’ve even had a chance to think, you have have options 2 and 3 instead.

But the second option is unsatisfactory too, if you want to reason properly about your changes later.

It makes sense to group different changes together for semantic reasons – that is, if the changes are part of the same pattern of thought. But to have them all mixed in with changes made for other reasons somewhat defeats the purpose of trying to lay out that reasoning clearly in the first place.

After

So I was opting for the third choice – doing all my edits first in one creative, fruitful session and then committing just some of those edits in a separate, more reflective session later.

Particularly where the edits appeared on the same line, I would laboriously edit hunks to create patches I could add, so that when I wrote a commit message it could be specific and meaningful. But doing that was prohibitively time-consuming – I dreaded the administrative overhead.

Thankfully, with diffcraft I did away with much of that labour. So now I can have the meaningful history and the reasons behind each edits meaningfully recorded without all that hard administrative work.

How the aliases work

In order to take advantage of these aliases, you will need to have Node JS and NPM installed, and you’ll then need to use NPM to install diffcraft.

This is how the aliases break down.

1. Creating a patch

My alias git patch takes the name of a file I’ve edited and then the name of the patch file I want to create. For the patch file, I just need a temporary name as I can delete once I’m done with my workflow, so let’s just say temp.patch for ease.

But let’s say that the file I’m working on is a Markdown file containing a recipe, which I’m calling my-recipe.md for this example.

Here’s what the alias git patch looks like, in case you want to add it to your own ~/.gitconfig file.

patch = "!f() { \
       git show HEAD:$1 | diffcraft --f2 $1 -o $2; \
    }; f"

When I run git patch my-recipe.md temp.patch it takes the contents of the last commit of the file, and sends it to diffcraft to compared with the current content of the file. I’m then shown changes one by one and asked which I want to include and which I want to leave out of a particular commit.

At the end, the patch with all the changes I wanted to include for a commit is generated at temp.patch. That’s then useful for the next step in my workflow.

2. Applying a patch

The next step is git cache temp.patch.

It will take what’s in temp.patch – those changes I selected – and apply them to the staging area for Git.

My alias git cache is short for git apply --cached, which itself is fairly short as a command already.

3. Checking the patch application

I also have a short alias to tell me whether applying the patch has worked or not.

Here’s how it looks in my ~/.gitconfig file:

staged = diff --word-diff --staged

This show all the changes I selected in the first step as ready to commit.

Conversely if I run git diff --word-diff, I will simply see everything I didn’t include.

4. Committing with a date

As mentioned at the beginning, I tend to use this workflow as part of my typing and editing process for text I’ve written longhand first. When I’m writing that text first of all and then annotating it by hand, I also tend to date my edits.

So I have a small alias to make the dating process easier:

date = "!f() { \
           git commit --date=$1@$2; \
       }; f"

This alias uses the ISO date format.

So when I run git date 2020-06-09 17:59, I’m tell my Git commit history that the edit I made was actually at 17:59 on 9th June 2020, and not the date and time that I’m actually making the commit.

Information about when the commit is made is still stored but under the commit-date – whereas what I’m editing here is what’s called the author-date.

Wrap-up

And that’s it.

Of course if you were to use these commands yourself, you could change the name of the aliases to make them shorter still. But for me it helps to have the alias names roughly describe what I’m doing to make them easier to remember.

I can now happily sit down to an editing session on something I’ve written and do all my commits afterwards, safe in the knowledge that I easily separate little changes from each other and commit them in any way that I want.