Example of Splitting a PR |
May 25th, 2025 |
tech |
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:
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.I made a new branch off of
jefftk-new-feature
to represent the refactoring and new tests:git checkout -b jefftk-refactor
.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.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.I switched back to
jefftk-new-feature
, and rangit 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