- Only allow Squash Merges
- ✅ Delete head branches once pull request is merged
- Settings > Actions > Workflow Permissions
- Read and write permissions
- Allow GitHub Actions to create and approve pull requests
master
-> Latest and greatest Dev Tested Code
No other permanent trunks.
feature/<feature_name>
fix/<bug_title>
release/v-<version.major>.<version.minor>
- Temporary branch that lives while a release is being prepared
- No patch number in branch name because patch number is subject to change as fixes are merged after Testing
auto-backmerge/<pr_number>
Used to raise PRs to master for every change pushed to release branches
YYMM.DD.NN
NN
➡️ patch number
Ex: 2301.25.00
, 2302.01.04
🤖 on-merge-master.yml On every merge to master we update the full version. Major, minor versions will be modified if the existing version is of a previous date, otherwise only the patch number will be increased.
Example:
Existing Version: 2301.25.02
If a new commit is pushed on 25th Jan, 2023, the version becomes 2301.25.03
If a new commit is pushed on 26th Jan, 2023, the version becomes 2301.26.00
On every commit we update the patch number on release*
branches
🤖 on-merge-release.yml
Every push to release*
will trigger a corresponding PR to master
via a auto-backmerge/<pr_number>
branch.
The PR will be automatically merged if there are no conflicts
🤖 prepare-a-release.yml Create a release branch from latest master, with the right version in the branch name.
Actions
🤖 create-tagged-release.yml Tag the latest commit in a release branch with the right version tag and release notes
Actions
%%{init: { 'gitGraph': {'mainBranchName': 'master', 'showCommitLabel': true}} }%%
gitGraph
commit id: "🤖 2301.25.00"
branch fix/frames-bug
commit id: "Fix Logic"
commit id: "Fix UI"
checkout master
branch feature/dm
commit id: "Add DB"
commit id: "Add Socket"
checkout master
merge fix/frames-bug id: "PR: Frames Bug"
commit id: "🤖 2301.25.01"
checkout feature/dm
merge master id: "Pull master"
commit id: "Add UI"
checkout master
merge feature/dm id: "PR: Feature DM"
commit id: "🤖 2301.25.02"
- Cut the release branch from latest
master
( Actions▶️ > Prepare a release > Run Workflow ) - Generate Artifact(APK / IPA), and Dev Test
- Distribute Artifact for testing
- Fix bugs in release branch,
master
branch and go to Step 2
%%{init: { 'gitGraph': {'mainBranchName': 'master', 'showCommitLabel': true}} }%%
gitGraph
commit id: "🤖 2301.25.02"
branch release/v-2301.25
checkout master
commit id: "PR: New Feature" type:HIGHLIGHT
commit id: "🤖 2301.26.00"
checkout release/v-2301.25
branch fix/release-bug
commit id: "Fix bug"
checkout release/v-2301.25
merge fix/release-bug id: "PR: Release bug"
checkout release/v-2301.25
branch auto-backmerge/release-bug
merge master id: "Update branch"
checkout release/v-2301.25
commit id: "🤖 2301.25.03" tag: "v-2301.25.03"
checkout master
merge auto-backmerge/release-bug id: "backmerge"
checkout master
commit id: "🤖 2301.26.01"
Actions
Once we are 🟢 on all tests, do the above to tag the latest commit from the release branch and create a Github release with automated release notes. And upload the artifacts to the App Stores
Fixing an issue in current production build (v-2301.16.01
)
- Create a branch from the release tag (tag:
v-2301.16.01
-> branch:release/v-2301.16
)
The rest is same as normal release flow
%%{init: { 'gitGraph': {'mainBranchName': 'release/v-2301.16', 'showCommitLabel': true}} }%%
gitGraph
commit id: "2301.16.04" tag: "v-2301.16.04"
branch hotfix/crash
commit id: "Fix crash"
checkout release/v-2301.16
merge hotfix/crash id: "PR Crash"
commit id: "🤖 2301.16.05"
branch hotfix/bug
commit id: "Fix bug"
checkout release/v-2301.16
merge hotfix/bug id: "PR Bug"
commit id: "🤖 2301.16.06" tag: "v-2301.16.06"
Linear history is desirable for various reasons. All boil down to simplicity again.
Only allowing squash merging with a single trunk is the simplest way to achieve linear history. No one has to think, the right thing happens automatically.
Also in general, people have better discipline with respect to PR titles than commit messages, so your change-logs also look good.
Unlike server apps, mobile app release processes tend to be long. It's common to take 2 or more weeks if we include the gradual roll out to 10% > 20% > 50% > 100% while observing stability and metrics along the way.
Meanwhile, contributors should NOT have ambiguity of whether it is safe to merge to master right now.
Once the release is made and the commit is tagged, they don't have any purpose. That's why we delete them after release.
gantt
title App development and releases
dateFormat YYYY-MM-DD
tickInterval 3day
section Dev 1
Feature 2 ⭐ :a, 2022-01-13, 15d
Merge to master: crit, milestone, after a, 0d
section Dev 2
Feature 1 ⭐ :b, 2022-01-12, 2d
Merge to master: milestone, after b, 0d
Library Upgrade ⬆️ : l, 2022-01-16, 1d
Merge to master :crit, milestone, after l, 0d
Fix Feature 1 🪲: b2, after r1, 2d
Merge to release: milestone, after b2, 0d
Framework Upgrade ⬆️ : f, 2022-01-22, 1d
Merge to master :crit, milestone, after f, 0d
section Release
Prepare Release 2201.14: milestone, after b, 0d
Testing Feature 1 ⭐: r1, after b, 4d
Testing Feature 1 ⭐: r2, after b2, 1d
Rollout 2201.14.1 10% - 100%: r3, after r2, 7d
Prepare Release 2201.31: milestone, 2022-01-31, 0d
Merging to master 🟥 is safe and encouraged even when a release is ongoing
It's a date based versioning scheme that is also
- compatible with
semver
comparisons for which version is greater than the other - compatible with string alphabetical order comparisons (
2301.16.00
>2212.31.07
)
And best of all avoids the question - When did we release this version? forever, from anyone in the whole team
Even if answering the above question is not that important for your team, it's equally good, if not better than semver
. Which, most teams use by default. Semantic Versioning (semver
) makes sense for libraries. Consumers of your library want to know when there are breaking changes and when there aren't. And package managers take advantage of this convention to safely upgrade dependencies. Mobile App Users / App Stores have no such expectations from App Versions. They barely care.
My teams have been using date based versioning schemes for more than a year and it's great!