跪拜 Guibai
← All articles
Git · Workflow · Coding Standards

A Force-Push Disaster at 2 a.m. Produced a Git Workflow That Makes Rollback a Two-Command Job

By JavaDog程序狗 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Teams that lack a mechanical branch discipline discover the cost only during a crisis — a force-push that erases history, a release with no known good commit to roll back to, or a SNAPSHOT dependency that makes a production artifact unreproducible. This spec removes those failure modes with rules simple enough to fit on a single printed sheet.

Summary

The workflow treats master and develop as the only permanent branches; every feature, sprint, release, and hotfix is a temporary branch with a fixed origin and destination. Squash merges keep personal work clean, while `--no-ff` merges leave visible iteration milestones. Version numbers change only when cutting a release or hotfix — never during daily development — and SNAPSHOT dependencies are banned from master and production.

A full walkthrough follows an e-commerce v2.1.0 iteration from sprint creation through QA, RC candidate images, blue-green deployment, and a hotfix for a production payment timeout. The same blue-green setup enables a two-command, zero-downtime rollback by flipping an nginx config line.

Five quick-reference tables and five hard rules — no force-push to shared branches, no direct commits to master or develop, no merges without review, no SNAPSHOTs in master, and mandatory team notification after any rollback — turn the spec into something a team can print and tape to the wall.

Takeaways
Only two branches are permanent: master (production code) and develop (integration mainline); all others are deleted after use.
Feature and bugfix branches use Squash Merge to compress messy commit histories into a single clean commit.
Sprint, release, and hotfix branches use `--no-ff` merges to leave a visible milestone node in the history graph.
Version numbers are set only when cutting a release branch or incrementing PATCH on a hotfix; they stay untouched during daily development.
SNAPSHOT dependencies are forbidden from entering master and production because they make builds unreproducible.
Blue-green deployment keeps two identical environments; rolling back is a two-command nginx config flip with zero downtime.
After any rollback, the entire team must be notified immediately so no one continues working on top of the reverted code.
Five red-line rules: no force-push to shared branches, no direct commits to master/develop, no merges without code review, no SNAPSHOTs in master, and mandatory team notification after rollback.
Conclusions

Most Git disasters are not skill gaps but missing constraints — branch protection, mandatory reviews, and fixed merge strategies remove the degrees of freedom that cause them.

The distinction between Squash and `--no-ff` is a useful heuristic that many teams never articulate: squash individual work to hide noise, preserve merge commits for public milestones to keep history navigable.

Delaying the version number change until the release branch is cut eliminates a common source of confusion where developers change it mid-sprint and lose track of which artifact matches which code.

Banning SNAPSHOT dependencies from master is a reproducibility rule that teams often learn only after a production incident where no one can rebuild the exact deployed artifact.

Concepts & terms
Squash Merge
A merge strategy that compresses all commits from a feature branch into a single commit on the target branch, producing a clean history without intermediate work-in-progress commits.
--no-ff (no fast-forward) merge
A Git merge option that always creates a merge commit, even when a fast-forward is possible, preserving the visual record that a branch was merged as a distinct unit.
Blue-green deployment
A deployment pattern using two identical production environments; traffic runs on one (blue) while the new version is deployed and verified on the other (green), then traffic is switched instantly.
SNAPSHOT dependency
A mutable, in-development version of a library dependency that can be overwritten at any time, making builds that depend on it unreproducible once the SNAPSHOT changes.
RC (Release Candidate)
A pre-release build artifact that is tested for quality; RC tags may be overwritten during the QA cycle, unlike final release tags which are immutable.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗