Skip to content

← Writing

engineering

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 main drifts 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 gh CLI is worth installing. gh pr create, gh pr checks, gh pr merge remove 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.