Review and Merge Pull Requests
Review and merge pull requests on GitHub — Git Tutorial.
Focus: review and merge pull requests on github
You’ve written the code, pushed your branch, and opened a pull request — but the work isn’t done until someone actually reviews and merges it. The real bottleneck in every team is not writing code, it’s the slow, awkward dance of reviewing and merging pull requests on GitHub. If you’ve ever stared at a PR with 14 comments and wondered where to click, or merged something that broke main, this lesson is your playbook. By the end, you’ll review with confidence, merge with strategy, and keep your team’s history clean and reviewable.
The problem this lesson solves
Pull requests are the heart of collaboration on GitHub, but they’re also where projects stall. Review and merge pull requests on GitHub — the actual process of commenting, approving, and merging — is often learned by trial and error, which leads to messy histories, missed bugs, and merge conflicts that could have been avoided.
The pain is real: you open a PR, wait hours for a review, then the reviewer says “LGTM” without actually checking the diff. Or you merge with “Create a merge commit” and three weeks later nobody can tell which feature broke production. Without a clear mental model of what review and merge actually do to your repository, every PR becomes a gamble.
Why now? You already know how to branch and commit. This lesson turns that into a controlled, repeatable collaboration workflow — the difference between a repo that feels like a zoo and one that ships reliably.
Core concept / mental model
Think of a pull request as a proposal envelope sitting on the team’s table. Inside is your branch’s diff, a description, and a checkbox list of what you think is done. The reviewer’s job is to open that envelope, inspect every page, and either sign off or send it back with notes. Merging is the moment the envelope’s contents are officially sewn into the team’s shared history — main.
Three pieces make the model tick:
- The PR conversation — comments, code reviews, and automated checks that happen before merging.
- The merge action — how the branch’s commits get integrated into the base branch (merge commit, squash, or rebase).
- The merge state — the repo after merging: clean history, resolved conflicts, and an up-to-date
main.
Here’s the mental image: imagine main is a published book, your feature branch is a draft chapter, and the PR is the editorial process. Reviewing is line-editing; merging is the final approval to print. Choose the wrong merge type and you might ship a chapter that contradicts the table of contents.
Definition box: A pull request (PR) is a GitHub feature that bundles a branch, its commits, and a discussion thread. Review means inspecting and commenting on changed lines via the GitHub review UI. Merge integrates those changes into the base branch using one of several history-preserving methods.
How it works step by step
Here’s the complete journey from branch to merged PR — the sequence any developer should follow every time.
1. Prepare the PR
- Push your feature branch:
git push -u origin feature/checkout. - Open a PR via GitHub web UI or
gh pr create. Fill in a clear title and description — link issues, list tests run, note any migration steps. - Self-review: scroll through your own diff before requesting reviewers. Catch obvious typos or debug leftovers.
2. Request a review
- Use the Reviewers sidebar to assign teammates. On the PR page, click Reviewers and type names or team names.
- If you have CI (e.g. GitHub Actions), wait for the checks to run. A PR that fails tests needs fixing before human review.
3. Review the changes
When you’re the reviewer:
- Open the Files changed tab. Set a view mode (split or unified) that works you.
- Click the + next to a line to add a comment. You can write general comments, code suggestions, or start a review thread.
- After reading the full diff, click Review changes (top right) and choose:
- Comment — general feedback without approval.
- Approve — you’re satisfied, merge can proceed.
- Request changes — blocking issues must be fixed first.
- Leave a summary comment summarizing what’s good and what needs work. Be specific — reference line numbers or commit hashes.
4. Address review feedback
If you authored the PR and receive change requests:
- Go back to your local branch: git checkout feature/checkout.
- Make the edits, commit, and push: git push. The PR updates automatically.
- Reply to each review comment on GitHub (👍 or a short note) to keep the thread clear.
- Request another review if the reviewer asked to see the changes.
5. Merge the pull request
Once approved and all CI checks pass, you (or any maintainer) can merge: - Scroll to the bottom of the Conversation tab. Click Merge pull request. - Choose a merge method (see the table in the next section). - Click Confirm merge. GitHub will ask if you want to delete the branch — do it if the branch is no longer needed.
6. Clean up locally
- After merge, switch to
mainand pull:git checkout main && git pull. - Delete the local feature branch if you cleaned it up remotely:
git branch -d feature/checkout. - If the merge introduced conflicts with your other work, resolve them as you would any merge.
Pro tip: Use the
ghCLI for faster flows.gh pr listshows open PRs,gh pr checkout 123checks out the branch locally, andgh pr merge 123 --squashmerges with squash — all from your terminal.
Hands-on walkthrough
Let’s do a complete cycle in your terminal and the GitHub UI. First, ensure you have a repo with main and a feature branch. The example uses a Python calculator file, but the pattern applies to any code.
# Setup: from your repo, create and switch to a feature branch
git checkout -b feature/division-error
# Make a change — add a division function to calculator.py
echo 'def divide(a, b):
return a / b' >> calculator.py
git add calculator.py
git commit -m "Add divide function"
# Push the branch and create a PR (use gh CLI or open the URL GitHub prints)
git push -u origin feature/division-error
gh pr create --title "Add divide function" --body "Adds division support."
Now open the PR page in your browser. You’ll see the diff, a placeholder for checks, and the review buttons. Here’s what reviewing looks like in code — a reviewer might comment on the missing zero-check. Let’s simulate that with a comment thread:
# calculator.py
# Reviewer might point out that a/0 raises ZeroDivisionError
# A fix could be:
def divide(a, b):
if b == 0:
raise ValueError("Cannot divide by zero")
return a / b
After fixing, commit and push. Now merge with squash to keep history clean:
git add calculator.py
git commit -m "Guard against zero division"
git push
# On GitHub, click “Merge pull request” and select “Squash and merge”
# Then clean up locally:
git checkout main
git pull
git branch -d feature/division-error
Expected output after push:
remote:
remote: Create a pull request for 'feature/division-error' on GitHub by visiting:
remote: https://github.com/yourname/yourrepo/pull/1
remote:
To https://github.com/yourname/yourrepo.git
* [new branch] feature/division-error -> feature/division-error
After the squash merge, git log --oneline main will show a single commit like Add divide function (#1) that contains both original commits — clean and easy to reverend.
Compare options / when to choose what
GitHub offers three merge methods. Choosing the right one affects your history forever. This decision is often the most contentious — here’s the breakdown.
| Merge method | What it does | History | When to use it |
|---|---|---|---|
| Create a merge commit | Preserves every commit, adds a merge commit (e.g. “Merge branch ‘feature’ into main”) | Full, non-linear | Never never for default — use this when you need to keep the individual commits for evidence or a long-lived release branch. |
| Squash and merge | Combines all branch commits into one commit on main with (#PRnumber) suffix |
Clean, linear | Default for most teams. Good for feature work that’s one logical unit. Simplifies git bisect and reversion. |
| Rebase and merge | Replays your commits on top of main without a merge commit — history looks like straight line |
Linear, but keeps each commit | Use when you want a linear history and preserve meaningful intermediate commits, but beware of rewrite conflicts on shared branches. |
Beyond the merge method, decide who merges:
- Single maintainer — safest for open source, avoids conflicting merges.
- Any approved author — speeds delivery, common in small teams with clear ownership. GitHub allows protecting branches so only users with write access can merge, and you can require approval before merge.
My recommendation: squash and merge for 95% of feature PRs, rebase for work that needs granular history (like a long refactor with clear steps), and plain merge only when you must preserve every commit — otherwise it’s noise.
Pro tip: If your PR is behind
main, you can update it before merging. Use “Update branch” button on the PR page (introduces a merge commit ofmaininto your branch) orgit merge mainlocally. Better: rebase your branch (git rebase main) to keep history clean, then force-push — but only if the branch isn’t shared.
Troubleshooting & edge cases
Even experienced developers hit snags. Here’s how to fix the most common problems when reviewing and merging PRs.
PR shows “This branch has conflicts that must be resolved”
- Cause:
mainhas changes that your branch doesn’t include, and they overlap. - Fix: On GitHub, click “Resolve conflicts” — it opens a web editor for simple conflicts. For complex ones, do it locally:
git checkout feature,git merge main, resolve,git push. Never resolve by deleting chunks without understanding the intent — ask the original author.
CI status shows “Some checks were not successful”
- Cause: Tests failed, linting errors, or a required check never ran.
- Fix: Click the failing check to see logs. Fix your code, push a new commit, and re-run checks if needed. Never merge over red checks if you’ve set branch protection. If a check is flaky, rerun it rather than merging — trust the process.
You accidentally merged the wrong PR
- Cause: The classic “I clicked the wrong branch” scenario.
- Fix: Revert with
git revert <commit-sha>— this creates a new commit that undoes the changes. For a squash-merged PR, revert that single commit. For a merge commit, usegit revert -m 1 <sha>to keep the first parent line. Then open a follow-up PR to re-introduce the intended changes.
The reviewer requested changes but you disagree
- Take it to the PR thread. Be professional: explain your reasoning, cite the code, and propose a compromise. If the reviewer is blocking a merge and you can’t agree, escalate to the team lead. Remember: it’s about the code, not ego.
Branch protection is blocking the merge
- Cause: Your repo requires reviews, passing checks, or a specific merge method.
- Fix: Go to Settings → Branches → Add rule. Set “Require a pull request before merging”, “Require approvals”, and “Require status checks”. To merge despite protection, you’d need admin rights — better to satisfy the rules.
What you learned & what's next
You’ve now mastered the complete review and merge lifecycle on GitHub: you can propose a PR, inspect a diff like a pro, give structured feedback, resolve conflicts, and merge using the right method for your team’s workflow. You know why squash keeps history clean, how to troubleshoot merged mistakes with git revert, and how to use branch protection to enforce quality gates.
You’ve covered every learning objective: you can explain the core idea — that a PR is a collaborative proposal, not a solo upload — and you’ve completed a hands-on exercise that took a branch from push to merge. The next lesson in this Git Tutorial track will dive into resolving merge conflicts, where you’ll learn to untangle the hairiest code collisions — armed with the merge skills you just practiced. Go merge something!
Practice recap
Try this mini exercise: On a test repository, create a PR, then role-play as reviewer by adding a comment on a line and requesting changes. Fix the note, update the PR, and merge using squash-and-merge. Then break something on purpose, merge it, and practice reverting with git revert.
Common mistakes
- Merging with 'Create a merge commit' by default, creating a messy, non-linear history that's hard to debug.
- Skipping the self-review and approving your own PR without checking the diff — always review your own work first.
- Merging before CI passes, or ignoring failing checks because 'it works on my machine'.
- Forgetting to delete the branch after merge, leaving stale branches cluttering the repo.
- Reverting a merge commit with a plain
git revertthat doesn't use-m, breaking the history even further.
Variations
- Use GitHub's 'Require conversation resolution' branch protection to track resolved review threads.
- Adopt a 'trunk-based development' workflow where all PRs use squash-and-merge into a short-lived main.
- Leverage GitHub Actions 'merge queue' to automatically merge approved PRs in any order, preserving stability.
Real-world use cases
- Teams using GitHub Flow enforce squash-and-merge for every feature PR, keeping
mainlinear and deployable at any commit. - Open-source maintainers require at least one approval and passing CI before merging a contributor's rapid-fire PRs.
- A release team uses branch protection and a merge queue to guarantee only fully-tested, committed code reaches production.
Key takeaways
- A pull request is a collaborative proposal — review it carefully, not just glance at the diff.
- Use squash-and-merge for most PRs to keep history clean and easy to revert.
- Always wait for CI to pass before merging; branch protection can enforce that rule automatically.
- Resolve conflicts early, either on GitHub or locally, before they become unmanageable.
git revertis your safety net for a wrong merge — know how to use it correctly for merge vs squash commits.- After merge, pull
main, delete stale branches, and keep your local repo tidy.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.