Git from First PrinciplesPost 9 of 16 · 16 of 16 written
- How to use this guide
- 01Why version control exists
- 02Git's data model: a content-addressed object database
- 03References: branches, HEAD and tags are pointers
- 04The three areas: working tree, index, repository
- 05Daily commands, mapped onto the model
- 06Branching and integration: merge, rebase, cherry-pick
- 07Undoing things safely
- 08Remotes and collaboration
- 09Workflows and conventions
- 10Git for AI and ML work
- 11Git with AI coding agents
- 12Power tools
- 13Under the hood: build a commit by hand
- 14Debugging mindset and recovery playbook
- 15Practice path, fluency checklist and glossary
- 16Sources
9. Workflows and conventions
A workflow is an agreement about which branches exist, who writes to them, and how a change reaches main. Git enforces none of it; hosts enforce some of it through branch protection. For solo and small-team AI work, the default to start with is GitHub flow with short-lived branches.
Three common workflows
| Workflow | How it works | Fits |
|---|---|---|
| GitHub flow | main is always working. One short branch per change, a pull request, review and CI, then merge. |
Most web and ML projects, including solo work |
| Trunk-based | Everyone integrates into main at least daily. Branches live hours, not weeks; unfinished features hide behind flags. |
Teams with strong CI and frequent deploys |
| Git flow | Long-lived develop plus feature/*, release/* and hotfix/* branches; main holds releases. |
Versioned products with scheduled releases; heavy for most others |
The common thread: long-lived branches are expensive. The longer two lines diverge, the bigger and riskier the eventual merge.
Branch names
Use lowercase words with hyphens and a short prefix: feat/stratified-split, fix/nan-loss, exp/lora-r16, chore/bump-deps. An exp/ prefix for experiments is especially useful in ML repositories.
Commit messages
Add stratified split to data loader
A random split put only 2% of the minority class in validation,
which made F1 swing widely across seeds. Stratify on the label so
each split keeps the class ratio. Fixes #42.- Subject line: about 50 characters, imperative mood, no full stop. Test it: “If applied, this commit will add stratified split to data loader.”
- A blank line, then a body wrapped near 72 characters that explains why and any trade-offs.
- Reference issues or tickets so the context survives.
Conventional Commits add a type prefix: feat:, fix:, docs:, refactor:, test:, perf:, chore:, with ! marking a breaking change. Tools can then generate changelogs and version bumps automatically. It is optional but widespread.
Atomic commits
Each commit should hold one logical change and leave the project working. Keep refactors apart from behaviour changes, and formatting apart from logic. Small, clean commits make review readable, reverts surgical and bisect precise.
Pull requests and review
- Keep them small. A few hundred changed lines get a real review; a few thousand get a rubber stamp.
- Describe what changed, why, and how you tested it.
- For ML changes, add evidence: metrics before and after, the dataset version, and the config diff.
- Review the diff, not the description. Pull the branch and run it when the change is risky.
- Protect
main: require a pull request, passing CI and a review, and block force-pushes.
Versions and releases
Semantic versioning uses MAJOR.MINOR.PATCH. Bump MAJOR for breaking changes, MINOR for new compatible features, PATCH for fixes. Release by creating an annotated tag such as v1.4.2, pushing it, and publishing a release on your host.
git describe --tags names any commit relative to the nearest tag. v1.4.2-3-gabc1234 means three commits after v1.4.2, at commit abc1234. That makes a precise, human-readable build ID.
For models, keep the code version and the model version separate. Tag the commit that produced each released model, and record that hash and the data version in the model card.
Check yourself
- What does “
mainis always working” demand of every pull request? - Rewrite “fixed stuff” as a proper message for a change you made recently.
- What does
v2.3.1-5-g1a2b3c4tell you about a build?