Postmortem: The Feature Branch from Main Anti-Pattern
Summary
A development team attempted to implement a feature by creating a branch directly from main, merging it to develop, and then merging it again directly to main. This workflow creates branch divergence, deployment inconsistencies, and broken promotion paths. The approach fundamentally violates Git branching best practices and introduces significant risk to production deployments.
Root Cause
The workflow stems from a misunderstanding of proper Git branching strategies:
- Incorrect branch point: Starting from
maininstead ofdevelopcreates a branch with outdated base code - Duplicate merges: Merging the same changes through two different paths causes merge conflicts and commit duplication
- Bypassed promotion flow: Directly merging to
mainskips the intended CI/CD pipeline and code review process - No single source of truth: Changes exist in multiple places with different commit histories
Why This Happens in Real Systems
In practice, this anti-pattern emerges due to:
- Time pressure: Teams rush features and skip proper branching procedures
- Lack of Git expertise: Developers don’t understand the implications of branch topology
- Poor documentation: Unclear branching conventions lead to ad-hoc decisions
- Tooling gaps: Missing pre-commit hooks or branch protection rules allow invalid workflows
- Misunderstood deployment process: Confusion about how code should flow from development to production
Real-World Impact
This workflow creates cascading problems:
- Broken deployments: The
developbranch may contain outdated code not present inmain - Merge conflicts: Future work becomes increasingly difficult due to divergent histories
- Testing gaps: Features tested on
developmay not match what’s deployed to production - Rollback complications: Inconsistent commit history makes rollbacks unreliable
- Team confusion: Multiple sources of truth erode confidence in the deployment process
Example or Code
# Problematic workflow
git checkout main
git checkout -b feature/user-authentication
# ... implement feature ...
git checkout develop
git merge feature/user-authentication # First merge
git checkout main
git merge feature/user-authentication # Second merge - DANGEROUS!
This creates a scenario where commits exist in both branches but with different parent relationships, leading to potential conflicts and deployment inconsistencies.
How Senior Engineers Fix It
Senior engineers prevent and correct this issue by:
- Enforcing branch protection: Require all features to branch from
develop - Implementing pre-commit hooks: Block direct pushes to protected branches
- Using automated tools: Employ Git workflow automation tools like GitHub Flow or GitFlow
- Establishing clear conventions: Document and enforce proper branching strategies
- Regular repository maintenance: Use
git rebaseto keep feature branches current - Code review gates: Ensure all changes go through proper review before merging
# Correct workflow git checkout develop git pull origin develop git checkout -b feature/user-authentication # ... implement feature ... git checkout develop git merge feature/user-authentication git push origin develop # Deploy through proper CI/CD pipeline
Why Juniors Miss It
Junior developers often overlook these critical issues because:
- Lack of mental model: They haven’t internalized how Git tracks history and relationships
- Immediate success bias: The commands appear to work initially, masking long-term problems
- Insufficient code review: Subtle issues in branch topology aren’t caught in reviews
- No ownership of deployment: They don’t see the consequences in production environments
- Missing mentorship: Senior guidance on Git best practices isn’t consistently provided