Example of Splitting a PR

May 25th, 2025
tech
I'm a big fan of small focused PRs: it's much easier to tell whether they're actually doing the right thing. For example, I recently ran into a common scenario where I started adding some functionality, and realized this required some refactoring. The refactoring also made it clear that the original code was missing some important test coverage, so I added some tests. I ended up with a big set of changes which combined large refactors and a major (intended) change to the output.

This is a bad combination: if my refactoring accidentally changed functionality in a way not captured by the tests we might miss it. And with so many changes it's going to be hard for the reviewer (and even the author) to keep it all in their head at once. Instead, it would have been better if I had first done the refactoring and added tests, and then followed up with the new functionality. The first PR would be a bit noisy but conceptually straightforward and easy to validate because it produces exactly the same output for all inputs. The second PR would be very clean, but would require careful validation to verify that the changes really are an improvement.

I might be tempted to say "oh well, I should have approached this differently, I'll do better next time" but really I did need to combine these two changes when writing them: I didn't know for sure what I would want for the refactoring until I'd tried to use it to implement the functionality change. So if my plan was to do better next time I wouldn't actually do any better.

Instead I took advantage of version control to split my changes into two sets, in an order that is optimized for validation:

  1. I committed all my changes to a new branch, jefftk-new-feature, with a message that only mentioned the feature I was adding, not the refactoring or the new tests.

  2. I made a new branch off of jefftk-new-feature to represent the refactoring and new tests: git checkout -b jefftk-refactor.

  3. On jefftk-refactor I deleted everything related to the new feature, leaving only the refactoring and new tests. I verified that the output was unmodified, as you'd expect for a refactoring-only change. I committed this, with a message that only mentioned the refactoring and tests.

  4. I interactively rebased (git rebase -i HEAD~2) this branch to squash the two commits into one. I only kept the refactoring commit message. This branch is now ready to be my first PR, and is ready to send out for review.

  5. I switched back to jefftk-new-feature, and ran git rebase jefftk-refactor. This rewrote my original big commit as if it was a follow-up to the refactoring commit. There were a few merge conflicts I needed to resolve manually, but nothing too painful. This branch is now ready to be my second PR, and I'll upload it to GitHub so I can reference it in the first PR in case the reviewer is interested in taking a peek at what's coming.

This was a bit more work, but I think it's definitely worth it: I'm much more confident that my refactoring didn't break anything, and I expect it to be much easier to review.

Comment via: facebook, lesswrong, mastodon, bluesky, substack

Recent posts on blogs I like:

It isn’t always evil to ally with Steve Bannon

Scott Alexander wrote:

via Thing of Things October 19, 2026

Was the HuggingFace hacking incident scheming?

In July 2026, internal OpenAI agents hacked HuggingFace (HF) in order to figure out how their evaluation grader works. This involved a thousand agents coordinating on an improvised message board to carry out an elaborate sequence of exploits. A later grou…

via Victoria Krakovna October 18, 2026

There's no point at which turning your brain off will work

In early 2025, I started seeing people turn off their brain as they use LLMs1. They would have an LLM take an action (summarize text, write some code, etc.), and just assume that it worked2. This generally didn't work in early 2025 and the result was …

via Posts on September 18, 2026

more     (via openring)