This is a short description of a workflow I apply in git repositories that I “own”; it mostly gets applied to Calamares, the Linux installer framework, because I spend most of my development hours on that. But it also goes into ARPA2 projects and home experiments.
It’s a variation on “always summer in master”, and I call it the Git Alligator because when you draw the resulting tree in ASCII-art, horizontally (I realise that’s a pretty niche artform), you get something like this:
/-o-o-\ /-o-o-o-\ /-o-\
To me, that looks like the bumps on an alligator’s back. If I were a bigger fan of Antoine de Saint-Exupéry, I would probably see it as a python that has eaten multiple elephants.
Anyway, the idea is twofold:
- master is always in a good state
- I work on (roughly) one thing at a time
For each thing that I work on, I make a branch; if it’s attached to a Calamares issue, I’ll name it after the issue number. If it’s a different bit of work, I’ll name it more creatively. The branch is branched off of master (which is always in a good state). Then I go and work on the branch – commit early, commit often – until the issue is resolved or the feature implemented or whatever.
In a codebase where I’m the only contributor, or the gatekeeper for it so that I know that master remains unchanged, I know a merge can go in painlessly. In a codebase with more contributors, I might merge upstream master into my branch right at the end as a sanity check (right at the end because most of these branches are short-lived, a day or two at most for any given issue).
The alligator effect comes in when merging back to master:
I always use
--no-ff and I try to write an additional
summary description of the branch in the merge commit.
Here’s a screenshot of Calamares history, from qgit, turned on its side like an alligator crawling to the right, (cropped a little so you don’t see where I don’t follow my own precepts and annotated with branch names).
Aside from the twofold ideas of “always summer in master” and “focus on one thing” I see a couple of other benefits:
- History if desired; this approach preserves history (all the little steps, although I do rebase and fixup and amend stuff as I go along, I don’t materially squash things).
- Conciseness when needed; having all the history is nice, but if you follow the “alligator’s tummy branch” (that is, master, along the bottom of the diagrams) you get only merge nodes with a completed bugfix or feature and a little summary: in other words, following that line of commits gives you a squashed view of what happened.
- Visual progress; each “bump” on the alligator’s back is a unit
of progress. If I were to merge without
--no-ffthe whole thing would be smooth like a garter snake, and then it’s much harder to see the “things” that I’ve done. Instead I’d need to look at the log and untangle commit messages to see what I was working on. This has a “positivity” benefit: I can point and say “I did a thing!”
I won’t claim this approach works for everybody, or for larger teams, but it keeps me happy most days of the week, and as a side benefit I get to think about ol’ Albert the Alligator.