Opening the loop on code review
Your feature is done. Tests pass locally. You push to GitHub and wait—sometimes hours, sometimes days—for feedback. By then, you've lost context and moved on to the next task. A solid GitHub pull request workflow for Git & GitHub developers flips this around: you open a draft PR early, get small feedback loops, and merge with confidence. This isn't about process theater. It's about shipping faster, catching bugs before production, and keeping your team unblocked.
The flow: small steps, fast feedback
The core rhythm is simple and repeatable. Create a branch from main, commit small logical changes, open a draft pull request early, pass automated checks and human review, then merge and clean up. Each step feeds into the next. Let's walk through a real scenario.
You're adding a new payment method to an e-commerce checkout. Instead of grinding away for a week and pushing a 2,000-line PR, you break it into stages:
- Branch:
git checkout -b feat/paypal-integration - Commit the domain model and tests (100 lines)
- Open a draft PR immediately
- Commit the API adapter (200 lines)
- Commit the UI component (150 lines)
- Mark draft as ready for review
- Address feedback in focused commits
- Merge when CI passes and reviewers approve
- Delete the branch
This cadence means your teammates see your work in progress, can spot architectural misalignments early, and don't have to context-switch to review a monolithic changeset. You also stay in flow—you're not waiting for approval to keep working on the next piece.
Here's what that looks like in practice:
git checkout -b feat/paypal-integration
# Make domain model changes
git add src/payments/PaymentMethod.ts src/payments/__tests__/PaymentMethod.test.ts
git commit -m "Add PayPal payment method type and tests"
git push origin feat/paypal-integration
# Open draft PR on GitHub
# Continue work
git add src/services/PayPalAdapter.ts
git commit -m "Implement PayPal API adapter"
git push origin feat/paypal-integration
# More commits as needed
# Convert draft to ready when feature is feature-complete
# After approval and CI passes
git switch main
git pull origin main
git merge --squash feat/paypal-integration
git commit -m "feat: Add PayPal payment integration"
git push origin main
git branch -d feat/paypal-integration
git push origin --delete feat/paypal-integrationEach commit in that sequence is purposeful. Each push triggers CI immediately, so you know if something breaks before review even starts. By the time a human looks at your code, the boring stuff—linting, type checking, unit tests—is already done.
Small PRs: under 400 lines get better reviews
Large pull requests are the enemy of good code review. Studies across teams show that reviews slow down, feedback becomes vague, and bugs slip through when a PR exceeds 400 lines of actual code changes. Your reviewers are human. They get tired. Context fades. They rubber-stamp instead of thinking.
Aim for PRs between 150 and 350 lines of meaningful change. That includes tests. It includes comments. Pure churn (auto-formatting, import sorting) should be separate.
What does a small PR look like? Here's an example from a React component update:
feat: Add loading skeleton to product card
- New SkeletonProductCard component (45 lines)
- Tests for skeleton states (60 lines)
- Update ProductCard to render skeleton on loading (20 lines)
- Total: 125 lines
Files changed: 3
Insertions: 125
Deletions: 8Your reviewer can read this in 5 minutes. They can spot if the skeleton matches the design, if the loading state is wired correctly, if the tests cover the happy path. They can leave specific feedback. "Consider adding aria-busy to the wrapper div" is useful. "This doesn't feel right" is not.
If your feature naturally spans more than 400 lines, split it into multiple PRs stacked on top of each other. Modern GitHub workflows handle this well with branch dependencies. First PR lands the foundation, second PR builds on it, third PR adds the finishing touches. Each one is reviewable independently. Each one can merge independently if it's ready.
Describe the why: context, screenshots, and testing notes
Your PR description is the first thing a reviewer reads. It should answer three questions: Why are we doing this? What did you change? How do I verify it works?
Don't assume the reviewer knows the context. They might be new to the codebase. They might be reviewing between meetings. They're not in your head. Write as if explaining to a colleague from a different team.
A good PR description looks like this:
Why: Customers in high-latency regions report 404 errors when placing orders. Root cause is a race condition between inventory deduction and order creation. This PR adds a distributed lock using Redis to serialize writes to the same product inventory.
What changed: - New
InventoryLockservice wrapping Redis SETEX and Lua scripts -OrderService.create()now acquires lock before deducting stock - Lock timeout is 5 seconds; we release early on success - Added integration tests with Redis testcontainers - Updated OrderService docs How to test: 1. Runnpm run test:integration(new tests included) 2. Manual: Hit/ordersendpoint with concurrent requests usingab -n 100 -c 20 http://localhost:3000/orders3. Verify inventory never goes negative in the database Known limitations: - This doesn't handle distributed deadlocks across multiple services yet. We can revisit in a follow-up. - Redis is a new dependency for this service. We already use it elsewhere, so ops burden is minimal.
Include screenshots if your change is visual. A before-and-after of a button layout takes 30 seconds to understand instead of 5 minutes of explanation. Include a link to the ticket if your team uses a task tracker. Include test results if you've done manual testing on a staging environment.
If your change touches deployment, database migrations, or environment variables, call that out explicitly. Reviewers need to know if merging this requires ops work or a staged rollout.
Respond quickly: keep reviews moving
A PR sitting unreviewed for 3 days is a PR that's getting stale. Your context evaporates. The codebase moves on. Merge conflicts creep in. You lose momentum.
Once you've opened a PR (draft or not), treat reviews as synchronous work. If someone leaves a comment, respond within a few hours. If they ask for changes, push a new commit within a day. Don't let it languish.
Set expectations on your team: PR review is part of your daily work, not something you do "when you have time." If your SLA is 24 hours, write it down. If critical path work needs faster reviews, establish a rotation or async signal system.
When you respond to feedback, don't just push code. Reply to each comment. If you disagree, explain why—briefly and with respect. If you agree, say so. If you need clarification, ask. This back-and-forth is how you build shared understanding and prevent the same issues in the next PR.
# Example: You've received feedback on a PR about error handling
# Reviewer: "Should we catch InvalidPaymentError here?"
# You: "Good catch. I initially didn't because we want that to bubble up
# to the caller for logging. But you're right—we should handle it here
# to prevent cascading failures. Added in the latest commit."
git add src/services/PaymentService.ts
git commit -m "Handle InvalidPaymentError in payment retry logic"
git push origin feat/paypal-integrationThis conversation is visible to everyone. It becomes part of the PR history. Future developers reading the code see not just the final state, but the reasoning behind it.
Common mistakes
Opening a PR without a description. Don't assume your code speaks for itself. It doesn't. Write a paragraph. Spend 2 minutes. You'll save your reviewer 20 minutes of digging.
Mixing refactoring with feature work. If your PR is "add feature X and reformat all files to match new linting rules," it becomes impossible to review. Do the refactoring in a separate PR. Land it. Then add the feature. This keeps the signal-to-noise ratio high.
Ignoring CI failures and requesting review anyway. If your build is red, no reviewer will approve. Fix the failure. Your review request will sit there, accumulating frustration. Get green first.
Treating review comments as personal attacks. They're not. Code review is about the code, not about you. When someone suggests a different approach, they're doing their job. Thank them. Discuss it. Move on. Your team reviews faster when everyone assumes good intent.
Waiting for perfect before opening a draft PR. Draft PRs exist for a reason. Open one early. Get feedback on architecture before you write 800 lines. Your reviewers might catch a design issue that saves hours of rework.
Key takeaways
- Follow the rhythm: branch → small commits → draft PR early → CI + review → merge + delete. Each step keeps momentum and feedback loops tight.
- Keep PRs under 400 lines. If your feature is bigger, stack multiple PRs. Small PRs get better reviews, faster approvals, and clearer feedback.
- Write a genuine PR description. Explain the why, what changed, and how to test. Include screenshots for visual changes. Assume your reviewer has zero context.
- Respond to review feedback within hours, not days. Push new commits promptly. Reply to comments. Keep the conversation moving so the PR doesn't go stale.
- Don't mix refactoring with feature work. Don't ignore CI failures. Don't assume your code is self-explanatory. These small habits compound into a team that ships faster and ships better.






Comments
Loading comments…