Git: pull requests & code review
On almost every team, nobody pushes straight to main. You push a branch and open a pull request (PR): “here's my change, please check it and pull it in.” Teammates review it, you fix what they find, and then it's merged. This lesson walks through a whole PR, from first push to clean-up, including the two things that trip people up: review changes and an out-of-date branch.
You will learn
- Connect to GitHub with an SSH key
- The pull request flow: branch, push, open, review, fix, merge
- Update a PR whose branch is out of date, safely, with
--force-with-lease - Squash, merge or rebase: the three merge buttons
- How to write a good PR, and how to review one kindly
Getting set up with GitHub
Make a free account at github.com, then let your computer prove who it is with an SSH key, the same kind of key as in Linux Basics, lesson 3:
ssh-keygen -t ed25519 -C "you@example.com" # skip if you already have ~/.ssh/id_ed25519 cat ~/.ssh/id_ed25519.pub # copy this into GitHub → Settings → SSH and GPG keys ssh -T git@github.com # "Hi NAME! You've successfully authenticated…"
GitHub's own command-line tool, gh, does pull requests without the browser. Install it, then log in once with gh auth login:
| Task | Rocky / RHEL | Ubuntu / Debian |
|---|---|---|
| Install gh | sudo dnf install epel-release, then sudo dnf install gh | sudo apt install gh |
| Log in | gh auth login same on both | |
Everything gh does, you can also do on the website. The buttons have the same names.
The pull request flow
- Branch:
git switch -c add-faq. One branch per change, with a name that says what it is. - Commit and push:
git push -u origin add-faq. GitHub even prints a link to open a PR. - Open the PR:
gh pr create --title "…" --body "…", or the green button on the website. - Review: teammates read the diff and leave comments. They approve or request changes.
- Fix: commit and push to the same branch. The PR updates by itself. There's no need to open a new one.
- Merge: once it's approved (and the automatic checks pass), merge it, delete the branch, and
git pullon main.
Many teams turn on branch protection for main: nobody can push to it directly, every PR needs an approving review, and the branch must be up to date with main before it can merge. The playground's club repository works that way.
“This branch is out-of-date with the base branch”
While your PR waits for review, other PRs get merged, so main moves on. To bring your branch up to date, rebase it onto the new main (as in lesson 4), then push. The plain push is refused, because rebasing rewrote your commits:
git fetch # get the new main git rebase origin/main # replay your commits on top of it git push --force-with-lease # replace the branch on GitHub
Both replace the branch on the server. --force-with-lease first checks that nobody else pushed to it since you last fetched, and refuses if they did, so you can't wipe out a teammate's commits by accident. And this only ever goes on your PR branch. Never force-push main.
Some teams prefer git merge origin/main into the branch instead. That needs no force-push, but adds a merge commit. Both are fine, so do what your team does.
The three merge buttons
| Button / gh flag | What lands on main | Good for |
|---|---|---|
Squash and merge --squash | One commit with all the PR's changes, titled “Add an FAQ page (#12)” | A tidy main: one commit per PR. Very common. |
Create a merge commit --merge | Every commit from the branch, plus a merge commit | Keeping the full detail of how the work was done |
Rebase and merge --rebase | Every commit from the branch, replayed onto main, no merge commit | Straight history with each commit kept |
After a squash, your local branch's commits aren't on main (the squash is a new commit), so delete the branch with git branch -D, or let gh pr merge --delete-branch do it.
Good PRs, kind reviews
- Small PRs get reviewed. Ten changed lines get a careful review. A thousand get “looks good to me” and a shrug.
- The description answers why. The diff shows what changed. Say why, and how you tested it.
- Review the code, not the person. “This breaks on an empty name, what about a default?” beats “this is wrong”. Ask questions, and say what's good too.
- Be specific. Point at the line and say what you'd change.
Forks: contributing to someone else's project
You can't push branches to a project you're not a member of, so you fork it: GitHub makes your own copy, you push your branch there, and open the PR from your fork to theirs. To keep your fork's main up to date, add the original as a second remote, usually called upstream:
git clone git@github.com:YOU/project.git
git remote add upstream https://github.com/THEM/project.git
git fetch upstream && git rebase upstream/main # catch up with the original
Try it: your first pull request 🔀
The club website lives in /srv/git/site.git, which acts like GitHub here: gh is wired to it, and main is protected. You wrote an FAQ page for new members (~/faq.html). Get it onto the website the proper way. Priya will review it.
Quick check
1. A reviewer asked for a change on your open PR. How do you send the fix?
✓ A PR follows its branch, so every push to the branch shows up in it.
2. You rebased your PR branch onto the new main. git push is rejected. What now?
✓ The rebase rewrote your branch's commits, so the push has to replace them, and --force-with-lease does it safely. (A pull would merge the old commits back in.)
3. What does “Squash and merge” put on main?
✓ One tidy commit per PR, named after the PR.