Pull requests
A pull request is a platform workflow on top of git: push a feature branch, open a PR, get review and CI checks, then merge. PRs offer three merge strategies — merge commit, squash-and-merge, rebase-and-merge. Review plus CI is the gate before code reaches main.
You have learned to push branches, integrate changes, and rewrite history safely. But on a real team you rarely push straight to main — you open a pull request. Here is the surprise for many engineers: there is no git pull-request command. A PR is not a git feature at all; it is a workflow that GitHub, GitLab, and Bitbucket built on top of git, adding the one thing raw git lacks — a place to review, discuss, and gate changes before they land.
By the end of this lesson you will be able to describe the full PR lifecycle, choose between the three merge strategies a PR offers, and explain why the review-plus-CI gate is the point of the whole thing.
After this lesson you can explain that a pull request is a platform workflow layered on git, walk through its lifecycle from feature branch to merge, and choose deliberately between merge-commit, squash, and rebase merge strategies.
A pull request proposes merging one branch into another, and lives on the platform, not in git. The mechanics are plain git underneath: you create a branch, commit, and push it. The PR is the platform wrapper around that branch — a page that says “please merge feature/login into main” and collects review, discussion, and automated checks:
git switch -c feature/login
# ...commit work...
git push -u origin feature/login
# then open a PR on the platform targeting mainNothing here is a new git command. The PR is metadata the server tracks: a source branch, a target branch, comments, approvals, and check results.
The PR lifecycle is: push → open → review + CI → merge. Once the branch is pushed and the PR opened, two gates run in parallel before anything reaches main:
- Code review — teammates read the diff, comment, request changes, and eventually approve.
- CI checks — automated pipelines run tests, linters, type checks, and builds against the branch, reporting pass or fail on the PR.
Only when reviewers approve and the required checks are green does the merge button unlock. That gate is the entire reason PRs exist — it moves quality control to before code lands, not after it breaks main.
A PR offers three merge strategies, each producing a different history. When you click merge, the platform asks how to bring the branch in:
- Merge commit — adds a merge commit joining the branch to
main; keeps every individual commit and the true branch topology. - Squash and merge — collapses all the branch’s commits into one clean commit on
main; the messy work-in-progress history disappears. - Rebase and merge — replays the branch’s commits onto
mainone by one with no merge commit, keeping them separate but linear.
The trade is the same merge-versus-rebase tension as local integration, now applied at the moment work lands on the mainline.
▸Why this works
Why do most teams default to squash and merge? Because a feature branch’s real history is usually noise — “wip”, “fix typo”, “address review”, “actually fix it”. Squashing turns ten throwaway commits into one meaningful unit on main (“Add login throttling”), so main’s history reads as one clean change per feature and reverting a feature is a single git revert. The cost: you lose the intermediate steps. Teams that value fine-grained bisecting or that write disciplined commits prefer rebase and merge to keep each commit; merge commit is favoured when preserving the literal branch topology matters. There is no universal right answer — it is a deliberate policy choice.
A long-lived PR drifts from main and must be kept current. While your PR waits for review, main keeps moving. If it drifts too far, CI may pass against stale code or the merge may conflict. You refresh the branch one of two ways:
git fetch origin
git merge origin/main # merge main into the PR branch, OR
git rebase origin/main # rebase the PR branch onto main (then force-with-lease)Merging in is simplest and safe on a shared PR branch; rebasing keeps the branch linear but rewrites its commits, so it needs --force-with-lease to push. Many platforms expose this as an “Update branch” button that performs the merge for you.
Drafts and the CLI make PRs part of the everyday loop. A draft PR signals “not ready to merge” — it runs CI and gathers early feedback without inviting final approval, useful for sharing work-in-progress. The GitHub CLI opens PRs without leaving the terminal:
gh pr create --base main --head feature/login --draft
gh pr create --fill # title/body from your commits
gh pr status # see review + CI stateMarking a draft “ready for review” flips it into the normal approval flow. The CLI keeps the whole push-open-track cycle inside your shell.
One feature, from branch to mainline.
You build login throttling on feature/login across eight messy commits (“wip”, “fix test”, “review nits”). You git push -u origin feature/login and open a PR targeting main with gh pr create --fill.
CI runs your test suite and linter on the branch — one test fails, the PR shows a red check, the merge button stays locked. You push a fix; CI re-runs and goes green. A reviewer comments that a magic number needs a constant; you push another commit, they approve.
Meanwhile main advanced by three commits. CI now warns the branch is behind, so you click “Update branch” (a merge origin/main into your PR branch) and checks re-run green against current code. Finally you click Squash and merge: your eight commits collapse into a single main commit, “Add login throttling (#142)”, linked to the PR. main gains one clean, reviewed, CI-verified change — and the eight-commit scramble that produced it stays in the PR’s record but never clutters the mainline.
▸Common mistake
A common misunderstanding is treating CI’s green check as proof the code is correct, so review becomes a rubber stamp. CI proves only what the tests assert — it cannot catch a misunderstood requirement, a missing edge case nobody wrote a test for, or a design that will not scale. Review and CI are complementary gates: CI catches what is mechanically checkable, humans catch intent and judgment. Skipping either is how broken-but-green code reaches main.
Your PR has eight messy commits ('wip', 'fix typo', ...). The team wants main's history to show exactly one clean commit per feature. Which merge strategy fits?
A pull request is a workflow the platform layers on top of git — there is no git pull-request command. Its lifecycle is push a feature branch → open the PR → pass code review and CI checks → merge, and that review-plus-CI gate, blocking the merge until humans approve and pipelines are green, is the whole point. At merge time you choose a strategy: a merge commit keeps every commit and the branch topology, squash and merge collapses the branch into one clean commit on main, and rebase and merge replays commits linearly. Keep a long-lived PR current by merging or rebasing main in, use draft PRs and gh pr create to fold this into your daily loop, and remember CI and review catch different classes of problem. This completes the remotes-and-collaboration arc: from a lone clone to a reviewed change landing on a shared mainline.
Practice
Start at the top. Tasks go easiest → hardest: recall a fact, apply it to a case, then a senior-level stretch. Open one, attempt it, then reveal.
Something unclear?
Ask a question about this lesson. Questions are anonymous and go straight to the author to make the lesson better.