The Last Git Branching Model You'll Ever Need
- Opinionated
- Simplifies CI/CD
- Supports Hotfixes
- Good Tooling Support
- Works with all sizes of teams
- Improves Collaboration
We have one main branch in our Git-Repository called develop
. This is our current development version, which is always deployed to our staging environment. All other branches are started off of this default branch.
We also have a production
branch. This is the code that is currently running in production.
Generally, new code is written in new, short-living branches, however this model does allow for small and concise changes to be pushed directly into the develop
branch. This is only acceptable if the changes are small or cosmetic, have already been tested and don't require a code review.
For all other code, you should create a new branch off of develop. These have a naming convention:
<type>/<branch-name>
(e.g feat/user-info-api
)
$ git checkout develop
$ git checkout -b feat/my-new-feature
While working, track your progress in a draft (github) or Work In Progress Pull-Request (gitlab) and request a review from at least one teammate when you have finished your feature. When all checks pass (assuming you have set up CI/CD) you squash and merge the branch into develop (It's recommended to require a linear history and disable other merge types on your respective git host).
When commiting your code to these branches or develop
, you also need to follow a naming convention (based on Conventional Commits):
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
$ git commit -m "feat: add database user model" \
-m "BREAKING: This changes some names in our rest-api"
Before releasing a version to production, it is recommended to sanitize-check your current staging environment — even if all tests pass. If you are confident, the next step is to (optionally) commit a version bump to develop
:
$ git checkout develop
$ # bump your version to v0.1.0
$ git commit -m "chore: bump version to v0.1.0"
$ git tag v0.1.0
$ git push --tags
The final step then is merging this to your production
branch:
$ git checkout production
$ git merge develop --ff-only
$ git push
Pre-Releases are just tagged development versions. To for example automate pushing your library to npm or similar, you need to add a release step to your CI/CD system that runs on every tag *-{alpha,beta}.*
$ git checkout develop
$ # bump your version to v0.1.0-beta.0
$ git commit -m "chore: bump version to v0.1.0-beta.0"
$ git tag v0.1.0-beta.0
$ git push --tags
Hotfixes should be created as pull-request from a fix-branch directly to production. These can then be reviewed and squash-merged like normal branches.
$ git checkout production
$ git checkout -b "hotfix/fix-password-hash"
After a hotfix lands in production, a more elaborate fix can be created for develop or the fix can be cherry-picked:
$ git checkout develop
$ git cherry-pick 3af9286 # the commit sha of the hotfix
Continuous Integration and Continuous Delivery are crucial parts of YAGS. Depending on your setup, this can look very different, but the general recommendation is:
on every commit, anywhere
: Run all tests and try to buildon every commit to develop
: Deploy to your staging environmenton every commit to production
: Deploy to your production environment
These add human machine-readable meaning to your commit messages and branches (based on the Angular Commit Convention / Conventional Commits)
feat
- A new featurefix
- A bug fixchore
- Changes that don't affect any code, e.g. releasesbuild
- changes in the build systemdocs
- Documentationstyle
- Cosmetic code changesrefactor
- A code change that doesn't fix/add anything newperf
- A code change that improves performancetest
- Adding or correcting tests
While this git strategy will work with any combination of build/test tools, these can serve as a good starting point for new projects
- Pre-Commit Hooks with Husky
- one hook running your tests
- one hook running commitlint
- ESLint for linting TypeScript/JavaScript code (optionally with my eslint preset)
- release-it with @release-it/conventional-changelog and github releases enabled
These are some recommendations specifically for opensource-projects. They don't really have a lot to do with this strategy but could be helpful.
- Add a Code of Conduct to your project
- Choose a simple Open-Source License
I've been heavily inspired by Trunk Based Development, the GitHub Flow and the GitLab Flow. With YAGS, I've aimed to take the best Parts of all of these and create a lightweight, opinionated and very practical alternative.