Git Workflow¶
This document describes the git branching strategy and deployment flow for the Delta project.
Overview¶
We use a dual-PR workflow for selective production promotion. Features are developed on branches created from main, tested on staging via one PR, and shipped to production via a second PR. This gives per-feature control over what reaches production.
Branching Strategy¶
Branch Naming¶
[type]/[developer-name]/[linear-ticket-id]-[description]
- type:
featureorbug(from Linear issue labels, default tofeature) - developer-name: Your name (lowercase)
- linear-ticket-id: e.g.,
dev-123 - description: Kebab-case summary
Example: feature/pablo/dev-123-add-payments
Always Branch from main¶
git checkout main && git pull origin main
git checkout -b feature/pablo/dev-123-add-payments
Never branch from staging. This ensures your PR to main (production) will always be clean.
The Dual-PR Flow¶
Step 1: Develop¶
git checkout main && git pull origin main
git checkout -b feature/pablo/dev-123-add-payments
# ... develop ...
git push origin feature/pablo/dev-123-add-payments
Step 2: PR #1 to Staging (UAT)¶
Open a pull request targeting staging:
feature/pablo/dev-123-add-payments → staging
What happens automatically:
- PR checks run (lint, typecheck, tests)
- On merge, staging environment deploys
- Linear ticket moves to "Testing" status
- QA is assigned to the ticket
Step 3: UAT¶
QA tests the feature on staging (staging.farmcove.co.uk).
If UAT fails:
- Developer fixes bugs on the same branch
- Push changes — staging redeploys with the fix
- Open a new small PR to staging with the fix, or merge the branch directly
- QA re-tests
If UAT passes: proceed to Step 4.
Step 4: PR #2 to Main (Production)¶
Open a second pull request from the same branch targeting main:
feature/pablo/dev-123-add-payments → main
What happens automatically:
- PR checks run again
- On merge, production environment deploys
- Linear ticket moves to "Done" status
- Feature branch is auto-deleted
Flow Diagram¶
feature/dev-123 ──PR #1──▶ staging (UAT)
│ │
│ (fix bugs if needed) │
│◀──────────────��────────┘
│
└─────────PR #2──▶ main (Production)
Hotfix Flow¶
For urgent production bugs that need to skip UAT:
git checkout main && git pull origin main
git checkout -b bug/pablo/dev-456-fix-login-crash
# ... fix ...
git push origin bug/pablo/dev-456-fix-login-crash
Open a PR directly to main. After merge:
- Production deploys immediately
post-main-merge.ymlauto-syncs the fix intostaging- Feature branch is auto-deleted
Branch Lifecycle¶
| Event | Branch status |
|---|---|
| Developer creates branch | Branch exists, based on main |
| PR #1 merges to staging | Branch survives (auto-delete is disabled) |
| Developer pushes fixes | Branch updated, staging redeploys |
| PR #2 merges to main | Branch auto-deleted by post-main-merge.yml |
Important: Never manually delete a feature branch after it merges to staging. You need it for PR #2.
Staging Hygiene¶
Over time, staging accumulates features — some shipped to production, some abandoned, some still in UAT. The reset-staging.yml workflow cleans this up:
- Resets staging to match
main(removes shipped/abandoned features) - Auto-detects features still in UAT (branches not yet merged to main)
- Re-merges those in-progress features back into staging
To run: Go to GitHub Actions > "Reset Staging Branch" > "Run workflow"
Run this periodically (e.g., after a batch of features ships to production) to keep staging clean.
Automation Workflows¶
| Workflow | Trigger | What it does |
|---|---|---|
pr-checks.yml |
PR to staging or main |
Lint, typecheck, tests |
deploy-app-staging.yml |
Push to staging |
Deploy app to staging, update Linear to "Testing" |
deploy-app-production.yml |
Push to main |
Deploy app to production, update Linear to "Done" |
post-main-merge.yml |
PR merged to main |
Sync main into staging, delete feature branch |
reset-staging.yml |
Manual trigger | Reset staging, re-merge in-progress features |
Edge Cases¶
Merge conflicts on PR #2 to main¶
If other features were merged to main while yours was in UAT:
git checkout feature/pablo/dev-123-add-payments
git fetch origin main
git rebase origin/main
git push --force-with-lease
The PR to main will update automatically.
Feature depends on another feature¶
Both features must be merged to main. Merge the dependency first, then the dependent feature. If they're in staging together, test them together.
Main-to-staging sync conflict¶
After a PR merges to main, the post-main-merge.yml workflow auto-merges main into staging. If this fails due to a conflict, the workflow posts a warning comment on the PR. To resolve manually:
git checkout staging
git pull origin staging
git merge origin/main
# resolve the conflicts in your editor
git add .
git commit
git push origin staging
This is rare — it only happens if the exact same lines were edited differently on staging and main (e.g., two independent hotfixes touching the same code). If conflicts become frequent, run the reset-staging.yml workflow to reset staging to main and start clean.
Branched from staging by mistake¶
If your branch was created from staging instead of main, the PR to main may include unrelated commits. To fix:
git rebase --onto main staging feature/pablo/dev-123-add-payments
git push --force-with-lease
Key Rules¶
- Always branch from
main— never fromstaging - Two PRs per feature — staging for UAT, main for production
- Same branch for both PRs — keeps context, fixes stay together
- Never delete branches after staging merge — needed for PR #2
- Hotfixes go directly to main — auto-synced to staging