dbx-merge-release
dbx-merge-release
Automated workflow for merging the main branch back into develop after a release has been cut. Uses the shell scripts in the repository root.
Context
After a release is published (via CircleCI), the main branch has release commits (version bumps, changelog, tag) that need to be merged back into develop.
Important constraint: Main and develop do NOT share linear history — main gets force-merged release commits. This means git rebase origin/main will never work (it tries to replay the entire repo). Always use the merge scripts.
How It Works
The scripts handle two cases automatically:
-
No new commits on develop: Simple merge. Conflicts (if any) are from CI-generated version bumps — resolve with
--theirs. -
New commits on develop after the release: The
start-merge-in-main.shscript detects commits on develop that have a UTC timestamp after the latest commit onorigin/main. It saves them to a temporary branch (temp/develop-new-commits), resets develop back, then does the merge. Afterend-merge-in-main.shcompletes, the agent rebases the saved commits on top of develop so they appear after the new-devtag and will be included in the next release.
Workflow
Step 1: Start the Merge
Ensure you're on develop with a clean working tree, then:
sh start-merge-in-main.sh
This script:
- Checks for uncommitted changes (exits if dirty)
- Fetches and pulls latest
developandmainfrom origin - Compares timestamps: finds any develop commits after the latest main commit
- If found: saves them to
temp/develop-new-commits, resets develop back - Starts a merge of
origin/maininto develop with--no-commit --no-ff
Step 2: Resolve Conflicts
Check for conflicts:
git diff --name-only --diff-filter=U
Since develop has been reset to before any new work, conflicts should only be from CI-generated files. Resolve with:
git checkout --theirs .
git add .
If there are develop-only files that conflict (rare after the reset), keep ours:
git checkout --ours <file>
git add <file>
Step 3: Verify
git status
git diff --cached --stat
Ensure all conflicts are resolved and staged changes look reasonable (mostly package.json version bumps + CHANGELOG).
Step 4: Complete the Merge
sh end-merge-in-main.sh
This script:
- Creates the merge commit with message:
merge(release): merge <tag> release - Runs
make-dev-tag.shto create the new-devtag - Prints a reminder if
temp/develop-new-commitsexists (but does NOT rebase it)
Step 5: Rebase Saved Commits (if applicable)
If start-merge-in-main.sh saved commits to temp/develop-new-commits, rebase them onto develop now:
git rebase develop temp/develop-new-commits
If there are conflicts during the rebase, resolve them per-commit:
- Check conflicts:
git status - For CI-generated files (package.json versions): accept the develop version (which now has the release versions)
- For source code: keep the temp branch's changes (the new development work)
- Continue:
git rebase --continue
After the rebase completes, fast-forward develop to include the rebased commits:
git checkout develop
git merge --ff-only temp/develop-new-commits
git branch -d temp/develop-new-commits
Step 6: Verify Tags
After the merge (and optional rebase), verify tags:
git tag --list "v*" --sort=-v:refname | head -5
Expected output (e.g., after v13.0.6 release):
v13.0.6-dev
v13.0.6
v13.0.5-dev
v13.0.5
...
If the -dev tag is missing: sh make-dev-tag.sh
Step 7: Push
If there were no saved commits (simple merge):
git push origin develop --tags
If saved commits were rebased back onto develop, the branch history was rewritten and a force push is needed. Always confirm with the user before force pushing:
git push origin develop --tags --force-with-lease
How the Tagging System Works
Tag Flow
-
Release on CircleCI: The release script (
tools/scripts/release.mjs) runs on a release branch. It:- Finds the last stable tag (e.g.,
v13.0.5) and its-devcounterpart (v13.0.5-dev) - Uses the
-devtag as the anchor — only commits after the-devtag are considered for the next release - Bumps the version, generates a changelog, commits, and creates a new release tag (e.g.,
v13.0.6)
- Finds the last stable tag (e.g.,
-
Merge back to develop: This workflow. After merging main into develop,
end-merge-in-main.shcreates the new-devtag (e.g.,v13.0.6-dev). -
Next release cycle: The next release looks for
v13.0.6-devas the starting point. Only commits after that tag are included.
Why the -dev Tag Matters
The release script uses this logic:
fromTag = allTags.includes(devTag) ? devTag : lastStableTag
- The
-devtag marks where post-release development begins ondevelop - Without it, the release script would compare from the wrong point and produce incorrect changelogs
- Commits made before the merge (and before the
-devtag) would NOT be included in the next release — this is why the scripts save and rebase new commits to appear after the tag
Tag Naming Convention
| Tag | Created By | Lives On | Purpose |
|---|---|---|---|
v13.0.6 |
CircleCI release | main |
Marks the release commit |
v13.0.6-dev |
make-dev-tag.sh |
develop |
Marks the start of the next dev cycle |
Important Notes
- Always start from a clean working tree — the start script checks for this
- Must be on the develop branch before starting
- Never use
git rebase origin/main— main and develop don't share linear history - The merge commit type is
merge— this is a reserved type (see dbx-commit-messages skill) - The dev tag is required — without it, the next release will analyze the wrong set of commits
- Do not amend the merge commit — the format is generated by the script
- The temp branch
temp/develop-new-commitsis created and cleaned up automatically by the scripts
Error Recovery
- If the start script fails due to dirty state: stash or commit changes first
- If the merge has unresolvable conflicts:
git merge --abortand investigate - If the end script fails: manually create the commit following the
merge(release): merge <tag> releaseformat, then runsh make-dev-tag.sh - If the
-devtag is missing after completion: runsh make-dev-tag.shmanually - If the temp branch exists from a failed previous run: the start script will clean it up automatically
Related Scripts
start-merge-in-main.sh— Detects new commits, saves them, initiates the mergeend-merge-in-main.sh— Commits the merge and creates dev tagmake-dev-tag.sh— Creates the<tag>-devgit tagtools/scripts/release.mjs— Release script that consumes the-devtags