How code moves from an idea to production — explained visually for everyone.
We use three environment branches. Think of them as checkpoints your code passes through before going live:
YOU WRITE CODE TESTING FINAL CHECK LIVE!
────────────── ───────── ───────────── ──────
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ │ │ │ │ │ │ │
│ Your │ ──> │ test │ ──> │ staging │ ──> │ main │
│ Branch │ │ │ │ │ │ │
│ │ │ "Does it │ │ "Does it │ │ "It's │
│ Write and │ │ work?" │ │ work with │ │ live!" │
│ experiment │ │ │ │ everything │ │ │
│ freely │ │ QA checks │ │ else?" │ │ Production │
│ │ │ here │ │ │ │ users see │
│ │ │ │ │ Pre-release │ │ this │
│ │ │ │ │ review │ │ │
└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
feature/ Protected Protected Protected
fix/ branch branch branch
docs/ PR required PR + approval
etc. required
| Branch | Purpose | Who Uses It | Protection Level |
|---|---|---|---|
| main | Production — the live version | Everyone sees the result | Highest — requires PR + 1 approval |
| staging | Pre-production — final check before going live | Team leads review here | Medium — requires PR |
| test | Quality assurance — make sure nothing is broken | Developers test here | Light — open for merges |
| feature/xxx | Your working branch — where you make changes | Individual developer | None — your sandbox |
Start from test and name it using our branch naming convention:
# Make sure you have the latest code
git fetch origin test
git checkout test
git pull origin test
# Create your branch
git checkout -b feature/add-new-leadsMake your changes, commit as you go:
# Stage your changes
git add scripts/add-leads.py data/new-leads.csv
# Commit with a clear message
git commit -m "Add 15 new Florida leads with contact info"
# Push your branch
git push -u origin feature/add-new-leads# Using the GitHub helper script:
python scripts/github_ops.py create-pr \
--title "Add 15 new Florida leads" \
--body "Added leads FL-031 through FL-045 with full contact details" \
--head feature/add-new-leads \
--base testOr do it on GitHub.com — click "New Pull Request".
Once the PR is approved (or you're confident), merge it into test. This is where QA happens:
Your branch ──> test
│
Does everything
still work?
│
┌───┴───┐
│ │
YES NO
│ │
Move to Fix it first,
staging then try again
Create a PR from test → staging:
python scripts/github_ops.py create-pr \
--title "Release: Florida leads + email fixes" \
--body "Batch of changes ready for final review" \
--head test \
--base stagingAfter final review on staging, create a PR from staging → main:
python scripts/github_ops.py create-pr \
--title "Release v1.3: Florida expansion" \
--body "Tested and reviewed. Ready for production." \
--head staging \
--base mainThis requires 1 approval from a team member.
When something is broken in production and can't wait:
NORMAL FLOW
feature/ ──> test ──> staging ──> main
HOTFIX FLOW (emergency only!)
hotfix/fix-crash ──────────────> main
│
Also merge back to
test and staging
so they stay in sync
# Create hotfix from main
git checkout main
git pull origin main
git checkout -b hotfix/fix-production-crash
# Fix the issue, commit, push
git add .
git commit -m "Fix production crash in route planner"
git push -u origin hotfix/fix-production-crash
# Create PR directly to main (mark as urgent)
python scripts/github_ops.py create-pr \
--title "HOTFIX: Fix route planner crash" \
--head hotfix/fix-production-crash \
--base mainAfter the hotfix is merged to main, merge main back into staging and test:
git checkout staging && git merge main && git push origin staging
git checkout test && git merge main && git push origin testAfter your branch is merged, clean it up:
We have auto-delete enabled — branches are automatically deleted after their PR is merged on GitHub.
To enable this:
python scripts/github_ops.py auto-delete# Delete the remote branch
git push origin --delete feature/add-new-leads
# Delete your local copy
git branch -d feature/add-new-leads
# Clean up stale remote references
git fetch --prune# See which local branches are already merged into test
git branch --merged test
# Delete all merged local branches (except main, staging, test)
git branch --merged test | grep -v "main\|staging\|test" | xargs git branch -d ┌─────────────────────────────────────────────────────────────────────┐
│ SALES OPS — GIT WORKFLOW │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ Developer creates branch feature/add-leads │
│ │ fix/map-bug │
│ │ docs/update-guide │
│ ▼ │
│ ┌──────────────┐ │
│ │ test │ QA / Testing environment │
│ │ │ - Merge feature branches here first │
│ │ │ - Verify nothing is broken │
│ └──────┬───────┘ │
│ │ PR │
│ ▼ │
│ ┌──────────────┐ │
│ │ staging │ Pre-production environment │
│ │ │ - Final review before going live │
│ │ │ - Requires a Pull Request │
│ └──────┬───────┘ │
│ │ PR + Approval │
│ ▼ │
│ ┌──────────────┐ │
│ │ main │ Production — THE LIVE VERSION │
│ │ │ - Requires Pull Request + 1 approval │
│ │ │ - What users and customers see │
│ └──────────────┘ │
│ │
│ Branch auto-deleted after merge ✓ │
└─────────────────────────────────────────────────────────────────────┘
- Branch Naming Guide — How to name your branches
- Contributing Guide — Full guide for contributing
- GitHub Ops Script — CLI tool for GitHub operations