Branching workflow (FCR dashboard repo)
A short protocol for collaborating on this repo without stepping on each other's toes. Use this when you're starting a piece of work that isn't a one-line hotfix.
Mental model
mainis the canonical line of commits — what we treat as "live".scripts/deploy-worker.shdeploys from whatever HEAD is, so by convention prod should always matchmain.- A branch is just a moveable label pointing at a commit. Cheap — no file copy, just a pointer. You can have unlimited branches.
- Working on a branch means your commits don't touch
mainuntil a Pull Request is reviewed and merged. Multiple branches can run in parallel.
Everyday workflow
1. Start from the latest main
git fetch origin
git checkout main
git pull --ff-only origin main
--ff-only refuses to silently merge if your local main has diverged —
you want this. If it errors, something on your local main isn't yet on
origin; sort that first before continuing.
2. Make a branch
git checkout -b graham/partial-onboarding
Convention: <your-name>/<short-feature-name>. Lowercase, hyphens.
Examples: cathal/lrc-insights, graham/gp-listing-api,
cathal/fix-pleper-timeout.
3. Work and commit
Commit as often as you like on the branch. Small commits are easier to review than one giant one.
git add worker/src/handlers/partial-onboarding.js
git commit -m "feat: scaffold partial-onboarding endpoint"
git add worker/src/handlers/partial-onboarding.js
git commit -m "feat: claude listing-draft prompt"
Commit-message style in this repo: lowercase prefix
(feat: / fix: / perf: / tweak: / spike: / chore:) plus a
short imperative sentence. Match the git log you see when you run
git log --oneline -20.
4. Push the branch
First push needs -u to set upstream tracking; after that just
git push.
git push -u origin graham/partial-onboarding
5. Open a Pull Request
Easiest from the terminal:
gh pr create --title "Partial onboarding: GP listing automation" --body "$(cat <<'EOF'
## Summary
- New module worker/src/handlers/partial-onboarding.js
- Adds /dashboard-partial-onboarding-run endpoint
- New BQ table fcr_operations.partial_onboarding_log
## Test plan
- [ ] Manual: POST /dashboard-partial-onboarding-run with a known dealId
- [ ] Verify HubSpot task is created with draft body + preview URL
- [ ] Verify BQ log row is written
EOF
)"
Or use the web UI on GitHub — it'll detect the pushed branch and offer "Compare & pull request".
Title: short, under 70 characters. Detail goes in the description.
6. Review
The PR shows a side-by-side diff. The reviewer can:
- Leave comments on specific lines (click the
+in the gutter next to a line) - Click Files changed → Review changes → choose Comment / Approve / Request changes
- Iterate by pushing more commits to the same branch — they appear in the PR automatically
7. Merge
Once approved, click Merge pull request on GitHub. You'll see three options — pick Squash and merge by default in this repo (see below).
After merge, delete the branch (GitHub button does it for you). Locally:
git checkout main
git pull --ff-only origin main # bring the merged commit down
git branch -d graham/partial-onboarding # delete the local branch
Merge strategies — when to pick which
GitHub gives you three options when you click Merge. Pick per-PR:
| Strategy | What it does | When |
|---|---|---|
| Squash and merge | Collapses every commit on the branch into one clean commit on main | Default for most PRs. Keeps main history readable. |
| Rebase and merge | Replays each branch commit linearly onto main | Only when each individual commit is meaningful on its own. |
| Create merge commit | Adds a merge commit joining the branch into main | Rare. Avoid — clutters history. |
For this repo: default to Squash. Looking at our existing git log it's already roughly one-commit-per-feature.
Deploy implications
scripts/deploy-worker.sh deploys from whatever HEAD currently is —
it doesn't care about branches. The discipline is:
- PR opened from a branch
- Reviewed and merged into
main - Pull
mainlocally - Run
scripts/deploy-worker.shfrommain
Don't deploy from a feature branch unless it's a deliberate emergency
hotfix — and even then, follow up with a PR + merge so prod state is
reachable from main.
Three safety rules
Never
--forcepush tomain. It would wipe other people's commits and thedeploy/worker/*rollback tags. If git ever suggests--forceon main, that's a stop sign — pause and ask before doing it.Always
git pull --ff-onlywhen pulling main. The--ff-onlyflag refuses to silently merge, so if your local has diverged you see an error instead of a surprise merge commit.Branch before working on anything substantial. It's much easier to throw a branch away than to untangle a mistake on main.
Common situations
"I started work on main and now I want it on a branch"
# You have uncommitted changes on main, none of them pushed
git checkout -b graham/my-work # branch keeps your changes
# now commit on the branch instead
"I already committed to main locally, didn't push, want to move it to a branch"
git branch graham/my-work # branch label points at your commits
git reset --hard origin/main # rewind local main to remote
git checkout graham/my-work # work continues on the branch
"I pushed to main by accident, can I undo?"
Don't undo. Open a revert PR if the commit needs reverting, otherwise just leave it — main history is append-only for everyone's sanity.
"My branch has fallen behind main while I was working"
# On your branch
git fetch origin
git rebase origin/main # replays your commits on top of latest main
# resolve any conflicts, git add, git rebase --continue
git push --force-with-lease # safer than --force; refuses if remote moved unexpectedly
--force-with-lease is the one place forcing IS okay — but only on
your own branch, never on main.
"Two people working on the same file"
Open both PRs. Whoever merges first wins by default. Whoever merges second has to rebase their branch on top of the now-updated main and resolve the conflicts. Talk to each other if it's going to be ugly.
Branch protection (recommended setup)
On GitHub: Settings → Branches → Add rule for main. Recommended
settings:
- Require a pull request before merging — enforces the workflow
- Require approvals: 1 — at least one reviewer signs off
- Require status checks — if you add CI later
- Do not allow bypassing the above settings — including for admins
Once this is on, "no direct push to main" becomes an enforced rule rather than just a habit.
Quick reference card
# Start a branch
git fetch origin && git checkout main && git pull --ff-only
git checkout -b you/your-feature
# Mid-work
git add … && git commit -m "feat: ..."
git push -u origin you/your-feature # first push only
git push # subsequent pushes
# Open PR
gh pr create --title "..." --body "..."
# After review, GitHub web UI: Squash and merge
# Clean up
git checkout main && git pull --ff-only
git branch -d you/your-feature
# Branch falls behind main mid-work
git fetch origin && git rebase origin/main
git push --force-with-lease
# Deploy after merge
scripts/deploy-worker.sh
FCR Dashboard documentation · generated from docs/ · keep counts verified, not guessed.