Git, Pull Requests and Code Review
Keep history readable, keep changes small, and review the code without attacking the person
Guess first
Pick an answer. You will see if you were right at the end of the lesson.
What should a good commit message mainly explain?
Real-world analogy
What is it?
Git records the history of your code as commits on branches. A pull request asks to merge your branch into a shared one. It is also where teammates review the change. For a mid-level developer the habits matter as much as the commands. Keep changes small and focused, and write messages that explain why. Never rewrite history others rely on, and make reviews specific and kind. These habits make a team faster because changes are easy to read, test and undo.
Real-world relevance
A developer opens a 2,000-line pull request that mixes a rename of 40 files with a new feature. The reviewer cannot tell which changes matter, approves it after a skim, and a bug ships. Splitting it into a rename PR and a feature PR would have taken ten extra minutes. In another team a developer force-pushes a shared branch, and two colleagues lose a day of work.
Key points
- Small branches, small commits — One branch does one job, and each commit is one step that builds. Small changes are easier to review, to revert and to understand later.
- Commit messages say why — The diff already shows what changed. The message should say why, for example "Round totals per line to match the invoice".
- Rebase and merge — Merge joins two histories and keeps both. Rebase replays your commits on top of another branch, which gives a straight history but creates new commits.
- Do not rewrite shared history — Rebasing or force-pushing a branch others have pulled breaks their copies. Rewrite only your own unshared work, and use --force-with-lease instead of --force.
- Resolve conflicts calmly — A conflict means two changes touched the same lines. Read both sides, keep what is right, run the tests, then continue. Ask the other author if you are unsure what they meant.
- A good pull request — It is small, has a clear description, includes tests, and shows screenshots for UI changes. The reviewer should not need to guess why it exists.
- Review for what matters — Read for correctness first, then clarity, then tests. Ask questions, and label comments as must fix or nit so the author knows what blocks the merge.
- Review the code, not the person — Say "this loop skips the last item" instead of "you forgot". Suggest, explain the reason, and assume the author tried to do the right thing.
- Mentor in review, receive it well — With a junior, explain the why and link an example. When you receive review, ask what you missed instead of defending the first version.
Quick check
Answer from memory — scrolling up first makes it stick less.
Why is force-pushing a branch that teammates have pulled a problem?
You see a small style issue in a pull request. What is the best way to write it?
Code example
git switch main
git pull --ff-only
git switch -c feature/order-total-rounding
# Work in small steps, and say why in the message
git add src/Orders/OrderTotal.cs tests/Orders/OrderTotalTests.cs
git commit -m "Round order totals per line to match the invoice"
# Bring in what others merged, replaying my commits on top
git fetch origin
git rebase origin/main
# First push of the branch
git push -u origin feature/order-total-rounding
# After a later rebase, on my own branch only
git push --force-with-leaseLine-by-line walkthrough
- 1. This is a shell script, not a program. The first three lines switch to main, update it with a fast-forward only pull, and create a new feature branch.
- 2. git add stages exactly two files, the code and its test, instead of everything. git commit records one small step with a message that says why.
- 3. git fetch downloads what others merged. git rebase origin/main replays my commits on top of it, so my branch starts from the latest main.
- 4. The first push uses -u to create the remote branch and remember it.
- 5. After a later rebase the commit hashes change, so a normal push is rejected. --force-with-lease overwrites the remote branch only if it still matches what my last fetch saw. Use it only on your own branch.
Spot the bug
# develop is the shared integration branch
git switch develop
git pull
git rebase main
git push --force origin developNeed a hint?
Show answer
Explain like I'm 5
Fun fact
Hands-on challenge
More resources
- About pull requests (GitHub Docs)
- Reviewing proposed changes in a pull request (GitHub Docs)
- GitHub pull requests documentation (GitHub Docs)
Lock it in