GitHub Code Review
Give and receive review that talks about behavior and risk, then merge with a strategy you can justify.
Review comments are GitHub, not Git
GitHub Pull Requests opened the conversation: a feature branch, a description, Closes #N, and a self-merge on a repository you own. This lesson is the discussion on that page. A GitHub review is comments and a verdict attached to the pull request. It is not a Git object. git show prints the commit. It does not print the review.
The change set
Commits and the diff live in Git. git diff main...HEAD and gh pr diff both describe that change. Neither stores a review thread.
The review
Line comments, conversation comments, requested changes, and approval are GitHub data on the pull request. Clone a fresh copy and those comments do not appear in the working tree.
# These are Git. None of them is a GitHub review comment.
git show
git diff main...HEAD
git log --oneline main..HEADUse a disposable GitHub repository you own. Self-review on your own pull request is valid practice. Do not ping a teammate for a rubber-stamp, and do not leave noise comments on a project you do not maintain.
Talk about behavior and risk
A useful comment names something a stranger can verify. “This clone command is a Pages URL, so git clone will fail” is a review. “I would have used a different heading” is taste, unless the heading hides the claim.
Behavior
What happens if this merges? Can a stranger follow the verify steps in the pull request body?
Risk
Secrets in the diff, a rewritten published branch, or a change that does not close the linked issue.
Evidence
Point at a line, a file, or a missing verify step. “Looks good” without opening Files changed is not evidence.
Scope
Review this change set. Do not demand a formatter sweep, a rename, and a new feature in the same thread.
If the pull request body has no verify steps, say that. Fixing the description can be the first requested change. Do not approve a blank argument because the diff is small.
Line, conversation, overall review
GitHub gives three places to talk. They are not interchangeable.
Line comment
Files changed, click the line, start a thread. This is how you attach a remark to exact text. There is no honest git equivalent.
Conversation comment
gh pr comment (or a comment on the Conversation tab) speaks to the whole pull request without a verdict.
Overall review
gh pr review submits a verdict: comment, request changes, or approve. It does not pin itself to a line unless you also left line threads on the website.
Inspect first
Read the description, then the diff, then comment. gh pr view and gh pr diff are the terminal path.
# From a clone of a GitHub repository YOU own, on the feature branch
# that already has an open pull request from GitHub Pull Requests.
gh pr list
gh pr view 1
gh pr diff 1
gh pr view 1 --commentsgh pr diff 1 is the change set. Use it the way Git Diff taught: know what you are about to accept before you accept it. Then open Files changed in the browser to leave the line thread.
Test what you learned
Type the GitHub CLI command that prints a pull request’s diff in the terminal (the number comes after).
Request changes, comment, approve
An overall review is a GitHub state, not a Git ref. On a disposable repository you own, you can submit these on your own pull request so the record exists.
gh pr review 1 --request-changes --body "$(cat <<'EOF'
The Clone section still uses a Pages URL.
That address is a static site host, not a Git remote. A stranger who copies it cannot git clone this repository.
Please change the command to the GitHub Git URL, then push the fix to this same branch.
EOF
)"gh pr comment 1 --body "Line comment is on the clone command in README.md. This review requests changes until that URL is a Git remote."Comment
gh pr review --comment when you have a question or a non-blocking note. The author can still merge.
Request changes
gh pr review --request-changes when a defect must be fixed before you would accept the change. Name the defect in the body.
Approve
gh pr review --approve when you have read the diff and would merge it. Approval is a claim, not a courtesy.
This lab
Leave a line comment on a planted defect, request changes, then approve after the fix lands. Do not skip the request just to merge faster.
Test what you learned
Type the GitHub CLI command that submits a review requesting changes (the pull request number and body flags come after).
Without branch protection, GitHub will still let the repository owner merge after requested changes. The point of the request is the record: the defect was named, then fixed. Protection rules that block merge until a reviewer approves stay for a later lesson.
Respond with commits, not force-push
Once someone has started reviewing—including you, on a self-review—the feature branch is shared history for that conversation. Add a commit. Push it. Do not rewrite the commits the comments already point at.
# Stay on the same feature branch. Do not switch to main.
# Do not force-push. Reviewers already have the earlier commits.
# Edit README.md so git clone uses the GitHub Git URL, then:
git add README.md
git diff --cached
git commit -m "Use the GitHub Git URL in the Clone section"
git push
gh pr view 1 --commentsgit push on a branch that already has upstream is enough. That is the same Git push Git Remote taught. GitHub attaches the new commit to the open pull request. You do not open a second pull request for the fix.
Test what you learned
Type the Git command that publishes the new fix commit on the feature branch that already tracks origin.
On the website, reply to the line thread. “Fixed in the next commit” is only useful if the next commit actually fixes it. Point at the change, or rest the verify steps.
Merge with a strategy you can justify
GitHub Pull Requests used gh pr merge --merge so the graph stayed a two-parent merge, the shape Git Merge already taught. GitHub also offers squash and rebase merge. Those buttons run on GitHub. They still produce Git history. Choose on purpose.
--merge
Creates a merge commit with two parents. Feature commits stay reachable. Use this when you want an explicit integration event.
--squash
Puts the net change on the base as one commit. Feature commits are not parents of that result. Same idea as git merge --squash, performed by GitHub.
--rebase
GitHub replays the feature commits onto the base and fast-forwards. History looks linear. The commits on GitHub after merge are not necessarily the same hashes you pushed.
This lesson
Prefer --merge unless you can say why squash or rebase is the better graph for this repository. Do not pick squash because the button is default on someone else's project.
gh pr review 1 --approve --body "Clone command now uses the GitHub Git URL. Verified on this branch."
# Pick ONE GitHub merge strategy and be able to name the graph it creates.
gh pr merge 1 --merge
# gh pr merge 1 --squash
# gh pr merge 1 --rebase
git fetch origin
git switch main
git pull origin main
git log --oneline --decorate --graph -n 8
git branch -vvApprove when the planted defect is gone, then merge. The merge happens on GitHub. git pull only brings that result onto local main. That is still Git, the same fetch-and-integrate job as before—not a second review.
Fetch the result onto local main
After GitHub merges, your local main is behind until you update it. Fetch, switch, pull. Then read the graph so the merge strategy is visible, not assumed.
git log --oneline --decorate --graph -n 8 should show a merge commit if you used --merge, or a single new commit on main if you used --squash. If you cannot point at that shape, you merged without knowing what GitHub wrote.
Deleting the feature branch on GitHub is optional housekeeping. It is not a substitute for updating local main. Do not delete unmerged work.
What not to review
A PR you have not opened
If you skipped Files changed and gh pr diff, you have not reviewed. Approval would be a courtesy stamp.
Someone else's homework
Do not leave practice comments on a repository you do not maintain. Do not merge other people's pull requests as a lab.
A formatter fight
If the project has no stated style, do not block on indent. If it does, one comment is enough—then stop.
Actions and protection
A red check on the pull request may be a workflow. Do not invent GitHub Actions here. Do not turn on required reviewers yet.
Guided practice: request, fix, merge
- 01Start from an open pull request you own
Reuse the feature-branch PR from GitHub Pull Requests, or open a small one with a planted defect: a Clone section that uses a Pages URL instead of the GitHub Git URL.
- 02Inspect
gh pr view,gh pr diff, then Files changed. Confirm the defect is visible in the diff. - 03Line comment and request changes
Comment on the clone command.
gh pr review --request-changeswith a body that names the Pages-versus-Git URL mistake. - 04Fix on the same branch
Correct the URL.
git commit, thengit push. No force-push. Reply on the thread. - 05Approve and merge
gh pr review --approve. Merge with a strategy you can name. Fetch and update localmain. Confirm the issue closed if you usedCloses #N.
Independent lab: code review
- On a GitHub repository you own, open or reuse a pull request whose diff includes one planted defect a stranger could catch (a Pages URL in a clone command is enough).
- Leave a line comment on that defect. Submit
gh pr review --request-changeswith a body that states the behavior risk. - Fix the defect on the same feature branch.
git pushwithout--force. Showgh pr view --commentsincluding the request and the new commit. - Approve, then merge with
gh pr mergeusing--merge,--squash, or--rebase. Update localmainand show the graph. - Write six lines: repository URL, pull request number, the defect you named, the merge flag you chose, one sentence on the graph that flag created, and one sentence that distinguishes a GitHub review comment from
git show. Do not comment on a project you do not maintain.
Common review mistakes
Treating git show as the review
Git shows the snapshot. GitHub stores the conversation. You need both.
Approving unread
LGTM without Files changed is not review. It is a stamp.
Force-pushing the discussion away
New commits keep the thread honest. Rewrite after review has started hides the history people already read.
Merging without naming the graph
Squash, merge, and rebase merge are different Git results. If you cannot draw the parents, you cannot justify the button.
Lesson review
You can review a GitHub pull request as a conversation about behavior and risk, keep that conversation on GitHub, answer with ordinary commits, and merge with a strategy whose graph you can name. A named branching model is Git Branching Workflow. A check reviewers can trust is GitHub Actions.
- I know GitHub review comments are not Git objects, and
git showwill not print them. - I can leave a line comment, then
gh pr review --request-changesor--approvewith a body a stranger can act on. - I respond to review with
git pushon the same feature branch, not with force-push or a second pull request. - I can justify
gh pr merge --merge,--squash, or--rebaseby the Git graph it creates.