Git Gardening
Git’s “branch” terminology captures the nature of divergence from the trunk, but fails to convey any meaning for the convergence (branches don’t “merge” in nature).
Commits are more like vines that splay and wind back around. When they return to the trunk, they may continue to have their own identity (more commits towards an objective) or terminate to make way for new initiatives.
Git histories are unclear on when ideas, initiatives, motivations for change or features start and stop: Maybe a branch was merged because the idea was complete. Or maybe it was needed by another developer in main
, or to be included in preliminary testing. It’s normally difficult to tell.
Maybe a branch contains 1 initiative. Maybe several, stacked on top of each other that depended on the work before it.
Classifying your commits by type can clarify the type of change and its motivation in each commit, but it doesn’t communication the relationship between commits.
By taking the analogy further (along with some botanical liberties), a collection of vines (a vineyard or garden), can be used to quantify common relationships between commits using emojis, that survive the capricious reasons commit histories branch and merge.
- đą đ Seedlings & Mushrooms: Small bugfixes, features, tweaks or any other self-contained execution of small, independent changes. For further differentiation, you can use đ to indicate transferable changes (that can “grow anywhere”), and đą for changes that must “grow from” the changes beneath it.
- đ° Seeds: Foundations, starts of new ideas or motivations. These could be refactors you encounter along the way to achieving a bug fix or feature, or the first step towards realising a goal or epic. There should generally only be one of these at the start of new idea. (Note: we’re actually using a nut here, as there is no seed emoji)
- đ đŋ Stems: Further ground work, or “yak shaving” done in service of a final objective. For further differentiation, you can use a đ to indicate a solid step towards a goal and đŋ to indicate a brief aside. There can be multiple of these “stacked” on top of one another for complex steps.
- đģ đē đš đˇ đŧ đ¸ đĩ Flowers: Fruitions or culmination of the atomic changes that came before it. These are the features or bugfixes you were tasked with doing. You can assign a particular flower to each team member (fruit works too, if you run out), pick them randomly to create a visual distinction between different changes, or always use the same one for consistency. It’s up to you and your team.
- đ đ đĻ Pollinators: Once your “flowers” exist, often they open up the possibility of “cross-pollination”: using new features elsewhere in a system, improving on a foundation by an extra 20% or otherwise taking advantage of the new possibility space.
These are generally used in the reverse order. For example:
1 2 3 4 5 |
|
These are other concepts that extend the analogy and add value to the ecosystem, but don’t usually feature in commit messages unless you need to communicate a commit is the result of these concepts:
đĢ Weeders: Test suites, linters and other pre-commit hooks or tools used to ensure commits are valid.
đ Ascenders: “ascender” branches allow minimising the number of merge commits (which create noise) by targeting the pull request of the base of your “vine” at them. They “ascend” the vine (commits) as each pull request is approved and fast-forwarded.
If there have been no changes on main
since the “root of the vine”, and no pull requests require implementing review suggestions, there is no need for ascenders, and main
can be fast-forwarded up the “stem”, retargeting each pull request as main
points to the commit before it.
If are changes on main
, use an ascender branch as the target of the pull requests. Once the ascender branch is fast-forwarded to the top of the vine, merge it into main
.
If the “vine” has “offshoots” (commits to address pull request suggestions), have the ascender climb (fast-forward) to the first offshoot and merge into main
. Create another ascender branch to do the same again (in effect, creating as few merge commits with main
as possible).