Skip to content

Instantly share code, notes, and snippets.

@litnimax
Created August 19, 2026 16:13
Show Gist options
  • Select an option

  • Save litnimax/4239a85414f4899594d2e5f0a8b0752f to your computer and use it in GitHub Desktop.

Select an option

Save litnimax/4239a85414f4899594d2e5f0a8b0752f to your computer and use it in GitHub Desktop.
Git workflow guide: preventing main/staging divergence

Git Workflow Guide: Preventing main / staging Divergence

What Happened

We recently hit a confusing merge conflict when trying to merge main back into staging. After investigation, the root cause was clear: PR #25 (Staging Changes) was a partial merge of staging into main — most likely a squash-merge or cherry-pick of selected commits rather than a full merge of the branch tip.

This left main with only a subset of staging's work, while staging kept evolving with new features (the POS customer-deposit module, settle-invoice improvements, etc.). The two branches diverged, and any subsequent main → staging merge produced conflicts in files that had been modified independently on both sides.

Expected Workflow

feature/*  ──PR──▶  staging  ──full merge──▶  main
  • Features live in feature/* branches (or dev_vasant, litnimax/connect-…, and other topical branches).
  • Features are merged into staging via PR — either a full merge or a squash, depending on team convention.
  • When staging is ready for release, it is merged into main as a full merge of the current branch state. Never a partial / squash / cherry-pick.

Rules to Prevent This From Happening Again

  1. Merging staging into main is always a full merge (or rebase + fast-forward) of the current tip. No squash, no cherry-picking individual commits.
  2. Protect main on GitHub: enable branch protection to disallow squash merges. Require merge commits when integrating staging into main.
  3. Keep staging in sync after each main release: after merging staging into main, run git checkout staging && git merge --ff-only origin/main (or rebase) so that staging never falls behind. This makes future main → staging merges either fast-forwards or no-ops.

If a Divergence Has Already Happened

A true fast-forward is impossible (both branches have exclusive commits). To resolve:

  • Locally (safe, reversible):
    git branch -f main staging
    git checkout main
    
    main now points to staging's tip. The previous main-only commits remain in the reflog if you need to recover anything.
  • On the remote: do not force-push main unless branch protection allows it and the team is aware. The cleanest long-term fix is to merge staging into main as a single merge commit so that history is preserved.

Optional: Release Branches

If you want named release points, you can additionally create release/v1.0, release/v1.1, etc. from main after each release. This is optional and sits on top of the base workflow above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment