Categories
Writing

Making git prose-friendly

I write all of my prose in plain text. The format I use is markdown/multimarkdown for all of the reasons markdown became a thing; it's easy to read as-is and it's easy to parse and render into richer formats like HTML. As an aside, I may switch to ASCIIDOC after reading Scott Chacon's excellent piece on how he used it to revolutionize his technical writing. But that's another post for the future!

Whether I'm using plain text, markdown, or ASCIIDOC, I also use git to store all of this text. If you're not a programmer you may not know what git is. The short story is git is a version control system. It is a program that can keep track of changes I make to my source code, or in this case my prose.

By default, git is a bit onerous to prose. It analyzes your text content line by line. The diff can be quite confusing when you checkin a file to git. Here is a typical example:

Standard git diff

Not only are the exact words that changed not highlighted, but the text is not wrapped. Bleh, we can do better. Git's diff command takes a useful argument called --word-diff. If I do the diff with this option, I get the words highlighted:

$ git diff --word-diff

Git diff with word diff

Great! But we still don't wrap lines. This is because when you perform a diff, git invokes a "pager" program and by default GIT_PAGER is a program called less. less does not wrap lines by default so you're SOL unless you have a very large monitor. Fortunately git is very configurable and you can modify the pager by setting the GIT_PAGER environment variable before invoking diff. less has an option to wrap, -r:

$ GIT_PAGER='less -r' git diff --word-diff

git diff with less -r

Great! Now it's time to add the file to the staging area. I like to use patch mode, where you can see each change before you add it.

$ git add --patch

git add --patch

Oh no! We're back to square one. git add doesn't take a --word-diff option. This is where shit gets real. If you find your git installation, there is a program called git-add--interactive. On my Mac running Lion (don't ask), I use homebrew so that file is located in /usr/local/Cellar/git/1.8.2.1/libexec/git-core. I made a copy of this file and called it git-add--interactive-words. I then edited this file like this diff explains:

$ diff git-add--interactive git-add--interactive-words 
741c741
< @colored = run_cmd_pipe("git", @diff_cmd, qw(--color --), $path);
---
> @colored = run_cmd_pipe("git", @diff_cmd, qw(--color --color-words --), $path);

To invoke this special command, I needed to create an alias for it in my global .gitconfig:

[alias]
    padd = add--interactive-words --patch=stage --

Now I can type git padd and we get what we're looking for, the same functionality we had with git diff --word-diff

git padd

I know this is all pretty crazy. Normal people write their prose in Word or Scrivener or something with fabulous revision marking capabilities. But I'm a bit crazy about keeping my toolset small and doing as much as I can with them. In any case, some of the guts of git explained here can be applied elsewhere if you come across the need.

It's also worth noting that github can now render prose diffs. This is great if you use github for your origin repository, but I use my own git server so I can't use that. Plus, it's mainly targeted at performing differences on revisions that are already checked in. Most of the work I presented here is to see what's changed before checking in.

I am in debt to Google and Stack Overflow for many of the tips you find here.

2 replies on “Making git prose-friendly”

Yes, wrapping will happen automatically. Each paragraph is basically one long line. Sorry for the delayed reply.

Comments are closed.