Skip to content

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: feature or bug (from Linear issue labels, default to feature)
  • 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.yml auto-syncs the fix into staging
  • 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:

  1. Resets staging to match main (removes shipped/abandoned features)
  2. Auto-detects features still in UAT (branches not yet merged to main)
  3. 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

  1. Always branch from main — never from staging
  2. Two PRs per feature — staging for UAT, main for production
  3. Same branch for both PRs — keeps context, fixes stay together
  4. Never delete branches after staging merge — needed for PR #2
  5. Hotfixes go directly to main — auto-synced to staging