A Feature-Branch Workflow, Start to Finish
· Jerwin Arnado ·
Having picked GitHub Flow — short
branches off main, reviewed by PR — the daily question becomes muscle memory: what are
the actual commands from “I’m about to start a task” to “it’s merged and cleaned up”?
This is that loop, end to end, with the gh CLI shortcuts that cut the browser out of it.
1. Start from a fresh main
Always branch off the current main, not whatever stale state your local copy is in:
git checkout main
git pull # get the latest
git checkout -b feat/passkey-login
git checkout -b creates the branch and switches to it in one step. Name it for the work
— a feat/, fix/, or chore/ prefix mirroring your
commit types keeps branches self-describing.
2. Do the work in small commits
Commit as you go, each one a coherent unit with a conventional-commit message:
git add app/Auth/Passkey.php
git commit -m "feat(auth): add passkey registration endpoint"
git add tests/
git commit -m "test(auth): cover passkey registration"
Small commits give you clean revert points and a reviewable story. If the branch gets messy, clean it up with an interactive rebase before you push.
3. Push the branch
git push -u origin feat/passkey-login
-u (--set-upstream) links your local branch to the remote one, so future git push
and git pull on this branch need no arguments. You only pass -u the first time.
4. Open a pull request
From the browser, or — faster — straight from the terminal with the GitHub CLI:
gh pr create --title "feat(auth): add passkey login" --fill
--fill populates the PR body from your commit messages (another payoff of writing them
well). Add reviewers and labels inline:
gh pr create --title "feat(auth): add passkey login" \
--body "Adds WebAuthn passkey registration + login. Closes #214." \
--reviewer teammate --label feature
Referencing Closes #214 auto-closes the linked issue when the PR merges.
5. Review, CI, and iteration
The PR is the checkpoint where CI runs and a human reads the diff. Watch the checks without leaving the terminal:
gh pr checks --watch # live CI status
gh pr view --web # open it in the browser when you need the discussion
When review asks for changes, just commit and push to the same branch — the PR updates automatically:
git add app/Auth/Passkey.php
git commit -m "fix(auth): validate the attestation challenge"
git push
6. Merge
Once approved and green, merge with your repo’s chosen strategy — squash is the common default for feature branches:
gh pr merge --squash --delete-branch
That squash-merges the PR, deletes the remote branch, and (with --delete-branch) the
local one too — closing the loop in a single command.
7. Clean up and go again
Return to main, pull the now-merged work, and you’re ready for the next task:
git checkout main
git pull
git branch -d feat/passkey-login # if not already removed by --delete-branch
git branch -d (lowercase, “delete if merged”) refuses to delete an unmerged branch — a
safety net. Use -D only when you genuinely want to discard unmerged work.
The whole loop, condensed
git checkout main && git pull
git checkout -b feat/x
# …commit small, conventional commits…
git push -u origin feat/x
gh pr create --fill
gh pr checks --watch
gh pr merge --squash --delete-branch
git checkout main && git pull
Caveats and best practices
- Keep branches short-lived. The longer a branch lives, the more
maindrifts out from under it and the worse the eventual conflicts. Aim for hours-to-days, not weeks. - Rebase onto fresh main before merging if your branch has gone stale:
git pull --rebase origin main. A green CI run on a week-old base proves little. - One PR, one concern. A PR that does three unrelated things is three times harder to review and impossible to revert cleanly. Split them.
- The
ghCLI is worth installing.gh pr create,gh pr checks,gh pr mergeremove most of the browser round-trips and keep you in flow.
Conclusion
The feature-branch loop is the same seven steps every time — branch off fresh main,
commit small, push, PR, review, merge, clean up. Internalize it (and the gh shortcuts)
and shipping a change stops being a series of decisions and becomes a reflex, which is
exactly what frees your attention for the actual code.