Skip to content

Branching Workflow

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.

  • main is the canonical line of commits — what we treat as “live”. scripts/deploy-worker.sh deploys from whatever HEAD is, so by convention prod should always match main.
  • 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 main until a Pull Request is reviewed and merged. Multiple branches can run in parallel.
Terminal window
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.

Terminal window
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.

Commit as often as you like on the branch. Small commits are easier to review than one giant one.

Terminal window
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.

First push needs -u to set upstream tracking; after that just git push.

Terminal window
git push -u origin graham/partial-onboarding

Easiest from the terminal:

Terminal window
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.

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 changedReview changes → choose Comment / Approve / Request changes
  • Iterate by pushing more commits to the same branch — they appear in the PR automatically

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:

Terminal window
git checkout main
git pull --ff-only origin main # bring the merged commit down
git branch -d graham/partial-onboarding # delete the local branch

GitHub gives you three options when you click Merge. Pick per-PR:

StrategyWhat it doesWhen
Squash and mergeCollapses every commit on the branch into one clean commit on mainDefault for most PRs. Keeps main history readable.
Rebase and mergeReplays each branch commit linearly onto mainOnly when each individual commit is meaningful on its own.
Create merge commitAdds a merge commit joining the branch into mainRare. Avoid — clutters history.

For this repo: default to Squash. Looking at our existing git log it’s already roughly one-commit-per-feature.

scripts/deploy-worker.sh deploys from whatever HEAD currently is — it doesn’t care about branches. The discipline is:

  1. PR opened from a branch
  2. Reviewed and merged into main
  3. Pull main locally
  4. Run scripts/deploy-worker.sh from main

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.

  1. Never --force push to main. It would wipe other people’s commits and the deploy/worker/* rollback tags. If git ever suggests --force on main, that’s a stop sign — pause and ask before doing it.

  2. Always git pull --ff-only when pulling main. The --ff-only flag refuses to silently merge, so if your local has diverged you see an error instead of a surprise merge commit.

  3. Branch before working on anything substantial. It’s much easier to throw a branch away than to untangle a mistake on main.

”I started work on main and now I want it on a branch"

Section titled “”I started work on main and now I want it on a branch"”
Terminal window
# 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"

Section titled “"I already committed to main locally, didn’t push, want to move it to a branch"”
Terminal window
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?”

Section titled “"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”

Section titled “”My branch has fallen behind main while I was working””
Terminal window
# 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.

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.

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.

Terminal window
# 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
Ask the docsRAG over this site
Ask anything about the FCR Dashboard platform — architecture, BigQuery, the worker routes, billing rules, the LRC stack, scoring… Answers are grounded in this documentation, with source links.
How does the deal-brief refresh work? Which routes are Worker vs n8n? How is account health scored?