How to Review a Pull Request in Code You Don't Know

A practical method for reviewing changes in a part of the codebase you have never worked in, from building context to writing comments that help.

By The OpenVisio Team · · 11 min read

Sooner or later you get tagged on a pull request in a part of the codebase you have never opened. Maybe the usual reviewer is on leave, maybe CODEOWNERS routed it to your team, maybe someone wants a second pair of eyes. The tempting responses are both bad: approve it because the tests pass and the author seems confident, or leave a pile of style nits because those are the only things you can judge.

There is a better middle path. You do not need to understand the whole module to review a change well. You need to understand what the change is trying to do, what it touches, and what could break. That is a bounded amount of work, and with a repeatable method it takes about as long as a careful review in familiar code. This post lays out that method, plus the comment patterns that make you useful rather than noisy.

Key takeaways

  • Start from intent, not the diff. Read the ticket and PR description until you can state the change in one sentence.
  • Build just enough context: the entry point, the callers of what changed, and the tests that cover it.
  • Focus on behavior and blast radius. Leave naming and style to linters and to reviewers who know local conventions.
  • Ask questions instead of asserting. In unfamiliar code, "why" comments are more useful and less likely to be wrong.
  • Be explicit about what you reviewed and what you did not. A scoped approval is honest and still valuable.
  • Pull down the branch and run it when the change touches behavior you cannot verify by reading.

Step 1: Understand the intent before reading code

Open the linked ticket, the PR description and any design notes before you open the diff. You are looking for three things: what problem the change solves, what the expected new behavior is, and how the author verified it. Try to write a one-sentence summary such as "This changes refund handling so that refunds after settlement create a reversal entry instead of a credit."

If you cannot write that sentence, stop and ask the author. A short comment such as "Could you add a sentence on what behavior changes for users and how you tested it?" is a legitimate review comment, and often the most valuable one. Changes that cannot be summarized are frequently doing two things at once.

Step 2: Get the shape of the diff

Before reading line by line, look at the overall shape.

gh pr checkout 1234
git diff --stat origin/main...HEAD
git log --oneline origin/main..HEAD

The stat view tells you which files changed and roughly how much. Sort them mentally into categories: core logic, tests, configuration, migrations, generated files, and incidental changes. A 40-file PR where 35 files are a renamed import is a very different review from a 6-file PR that changes a database migration and a payment calculation.

Flag anything that looks out of scope for the stated intent. A refund fix that also touches the session middleware deserves a question.

Step 3: Build minimum viable context

Now you need just enough understanding of the surrounding code to judge the change. Three questions get you most of the way.

Where does execution enter?

Find how the changed code gets called in production. Is it an HTTP handler, a queue consumer, a cron job, a CLI command? Search for the route definition or the job registration. If the changed function is deep inside, trace upward until you reach something that receives external input. The guide on tracing a request through a web app covers this in more detail.

Who else calls what changed?

This is the most important question for risk. If the PR changes the signature or behavior of a shared function, every caller is affected, including ones not in the diff.

# Find references to a changed function across the repo
git grep -n "calculateRefund(" -- ':!*.test.*'

# For TypeScript, the compiler is a more reliable reference finder
npx tsc --noEmit

Text search misses dynamic dispatch and re-exports, so treat it as a lower bound. A code graph or IDE "find all references" is more reliable when available. If a function has many callers and the PR changes its behavior, ask whether all of them want the new behavior.

What tests cover this?

Look for existing tests of the changed code, and look at what the PR adds. A quick way to see whether the new tests actually exercise the change: temporarily revert the production change and run them.

# Put the old production file back, keep the new tests
git checkout origin/main -- src/billing/refunds.ts
npm test -- refunds
# Restore the PR version
git checkout HEAD -- src/billing/refunds.ts

If the new tests still pass against the old code, they are not testing the fix.

Step 4: Review for behavior and blast radius

With intent and context in hand, read the diff. In unfamiliar code, concentrate your attention where an outsider adds the most value.

A checklist for unfamiliar-code reviews

  • Inputs and edge cases. What happens with empty, null, zero, negative, very large, or duplicate inputs? What about concurrent calls?
  • Error paths. When something fails, is the error surfaced, logged, retried, or swallowed? Swallowed errors in unfamiliar code are a common source of silent bugs.
  • State changes. Does the change write to a database, cache, queue or file? Is the write idempotent? What happens if it runs twice, or halfway?
  • Migrations and data. Will a schema change lock a large table? Is it backward compatible with the currently deployed code during rollout?
  • Contracts. Does an API response, event payload or public function signature change? Who consumes it?
  • Security. Is new input validated? Does authorization still apply on the new path? Are secrets or personal data logged?
  • Configuration. Are new environment variables or flags documented, defaulted safely, and set in every environment?
  • Observability. If this breaks in production, will anyone know? Is there a log line or metric on the new path?
  • Rollback. Can this be reverted cleanly, or does it leave data in a state the old code cannot read?

You do not need deep domain knowledge to ask any of these. They are about how software fails, which is similar everywhere.

What to deprioritize

Skip local style debates unless something is genuinely confusing. You do not know the area's conventions, and an expert reviewer or a linter will catch real inconsistencies. Avoid suggesting architectural rewrites in code you met an hour ago. If something looks structurally odd, ask about it rather than proposing a redesign.

Step 5: Run it when reading is not enough

Some changes cannot be verified by reading: UI behavior, performance-sensitive paths, anything involving timing or concurrency, and changes to build or deploy configuration. Check out the branch, run the relevant tests, and if practical exercise the feature locally. Even five minutes of running the code often surfaces something the diff hides, like a missing environment variable or a broken page in a state the author did not try.

Step 6: Write comments that help

How you phrase comments matters more when you are new to the area, because you will sometimes be wrong. A few patterns work well.

Ask, do not assert. "I may be missing context, but what happens here if the settlement record is missing?" invites an explanation. "This will crash if settlement is missing" is embarrassing if there is a guard you did not see.

Label severity. Prefix comments so the author knows what blocks merge:

blocking: This migration adds a NOT NULL column without a default, which will fail on existing rows.
question: Is calculateRefund also called from the nightly reconciliation job? If so, does it want the new behavior?
nit: Typo in the log message, "setlement".

Explain your reasoning. A comment that says why you are worried lets the author either fix the issue or explain why it does not apply. Both outcomes are good.

Point to evidence. Link to the caller, the test, or the line that prompted the concern. It saves the author a search and makes the comment easy to evaluate.

Step 7: Approve with an honest scope

When you approve, say what you reviewed. Something like:

Approving. I reviewed the refund logic, the new tests, and the two callers in
reconciliation and the admin API. I did not review the migration timing on the
production table size; @dmitri may want to look at that.

This is not hedging. It tells the author and any later reader exactly what assurance your approval provides, and it routes the remaining risk to someone who can handle it. Teams with a lot of agent-authored PRs will recognize this pattern from reviewing AI agent pull requests, where scoped approvals are equally important.

Turning reviews into learning

Every review in unfamiliar code is a chance to learn that code cheaply. A few habits compound:

  • Keep a short personal note of modules you have reviewed and one thing you learned about each.
  • When the author answers a "why" question, suggest turning the answer into a code comment so the next reviewer does not have to ask.
  • If you had to trace a flow to understand the change, share the trace in the PR thread. It is useful to the next reader.

Over time, being routed reviews outside your area is one of the most efficient ways to reduce knowledge silos, because it spreads context without anyone scheduling a training session.

Getting context faster

The slowest part of reviewing unfamiliar code is usually Step 3: figuring out where the changed code sits and who depends on it. A structural map shortens that. In OpenVisio you can open the repository in Explore to see a changed file's neighbors and dependents, or use Ask to get a sourced explanation of how a flow works before you start reading the diff. Coding agents connected over MCP can run the same lookups, such as listing dependents of a changed file, which helps when you review with an agent alongside you.

The method does not depend on tools, though. Understand intent, build minimum context, focus on behavior and blast radius, ask questions, and approve with an honest scope. That is a review the author can use, even in code you have never seen before.

code reviewpull requestsunfamiliar codeengineering practices

See it on your own repo

Paste a GitHub URL and get the day-one walkthrough — free, in your browser.

Index a repo

Keep reading