The loop, on any platform
The pull request is not a git feature — it is the platform's way of saying "please merge this branch", with a place to talk about it. Git's side of it is a branch and a push.
git switch main
git pull # start from what everyone else has
git switch -c fix-discount-total # a branch named after the work
# …work, in small commits…
git push -u origin fix-discount-total # first push links the branch
# open a pull request
# …review, changes, more commits, push…
# merge, then delete the branch
Keeping the branch fresh while you work
Before anyone has looked at it, rebase: the branch stays a straight line and the pull request shows only your work. Once people are reviewing and commenting on specific commits, merging is kinder — rebasing rewrites the commits their comments are attached to.
git fetch origin
git rebase origin/main # your branch, replayed on top. Tidy — before review.
git merge origin/main # a merge commit in your branch. Safe — during review.
Reviewing, and being reviewed
- Small branches get reviewed properly. A four-hundred-line pull request gets "looks good".
- Write the description for someone who was not in the meeting: what, why, and what you deliberately left out.
- A review comment is about the code, not the person, and the author is allowed to disagree with a reason.
- "Nit:" for taste, and make it easy to ignore. Block only on correctness, security and things that will be expensive to change later.
- Approve when it is better than what is on main — not when it is perfect.
Forks and upstream
git clone https://github.com/you/doors.git # your fork → origin
git remote add upstream https://github.com/them/doors.git
git fetch upstream
git rebase upstream/main # catch up with the original
git push -u origin my-fix # push to YOUR fork
# open the pull request against theirs
After a rebase, your own branch needs a force-push
This is expected, and it is safe on your own branch: the commits the server has are the old copies of your work, and nobody else is building on them. --force-with-lease adds the check that matters — it refuses if the branch on the server has moved since your last fetch, which is exactly the case where someone else did push to it.
git rebase origin/main
git push origin fix-total
! [rejected] fix-total -> fix-total (fetch first)
git push --force-with-lease origin fix-total
Rules the repository enforces for you
Protected branches (no direct pushes to main, no force-push), required reviews, required status checks, and a merge style — merge commit, squash, or rebase — chosen once for the whole repository. Squash-merging gives main one commit per pull request, which is why so many teams stop worrying about tidy branch history.
None of this is git; all of it is the platform. Know which is which, because when something is refused it saves an hour of debugging the wrong tool.