Write Big, Ship Small: A Two-Phase Branching Strategy
Most engineers have felt the tension between writing code the way their brain works and opening pull requests the way their reviewers prefer. Sarah Vessels, a GitHub engineer, describes a workflow that lets you have both: develop a large feature in a single branch, then later split it into smaller, reviewable pull requests.
The core problem is familiar. Big pull requests are harder to review, merge slower, and conflict more often with the base branch. But forcing yourself to divide work into tidy branches from the start can stifle the creative process. You end up agonizing over which commit belongs in which branch instead of thinking about the feature you are building.
Vessels's solution is sequential, not simultaneous. First, write everything in one exploratory branch to confirm the implementation works end to end. Then, once the design is validated, tease out small, focused branches from it and land those changes independently.
The Spike Branch First
Start by creating a feature branch—say, add-categories for adding categories to a blog—and put all your work there. This includes database changes, validation logic, new endpoints, UI updates, and any JavaScript needed for the user experience. Add just enough tests to confirm your methods work, and verify the rest manually in the browser. Think of this branch as a spike: a test bed to validate your data model and overall approach.
You can even open a draft pull request for this branch. It is not meant for review or merging yet, but it lets your team try the feature and see the direction you are taking.
Pulling Out Small, Focused Branches
Once the spike branch feels right, return to your repository's default branch and create a new branch for the lowest-level change that has to land first. In the blog example, that is the database work, since without it, everything else is moot.
Open a branch like category-db and pull relevant work from add-categories into it. Ideally, you made atomic commits in the spike branch, allowing you to run git cherry-pick to copy just the database changes. If your commits were not that clean, use the “Files changed” tab on the spike pull request to copy code into new commits on the focused branch.
This split has a side benefit: better test coverage. Tests often double the size of a pull request, and when reviewing a sprawling branch, you may second-guess whether a test is worth the added diff. When a branch is tightly scoped, tests are expected, and you can polish them without that pressure.
The smaller branches are the ones your team will scrutinize, so give them thorough pull request descriptions, strong tests, and attention to performance and user experience. Keep the original spike branch as a draft until you have landed enough of its pieces to make the remaining diff reviewable.
Daisy-Chaining Dependencies
After creating your first focused branch, you may want to see what remains in the spike branch. Change the base branch of the add-categories pull request from the repository default to category-db, then check out add-categories and run git merge category-db before pushing. The pull request diff will now only show code not already in the downstream branch.
If the remaining work is still too large, pull out another piece. From category-db, create a new branch like category-validations. Cherry-pick relevant commits or copy code from the pull request view. Then open a pull request with category-db as its base and category-validations as the head. Update the add-categories pull request to use category-validations as its new base. The resulting chain looks like:
main ← category-db ← category-validations ← add-categories
% git branch
add-categories // adds the whole categories feature
category-db // adds database table
* category-validations // adds validation logic + tests
master
Chaining pull requests this way unblocks progress. Even if category-db cannot be merged because its database change has not happened yet, you can still get the dependent branches fully tested and approved in advance. When the first branch is finally ready, you can land several merges in short order because the review work is already done.
Collapsing the Chain
As each small branch merges, update the pull requests built on top of it to point back at the repository's default branch. When category-db lands, for instance, rebase the category-validations pull request onto the primary branch.
Eventually, every small branch has merged, and you are left with one pull request again: the original add-categories, based on the default branch. Only this time the diff is small. The branch's purpose may have shifted too—instead of adding an entire feature, it might now only contain the JavaScript polish. Update the pull request description to match.
The combined workflow gives you the freedom to develop features quickly and the discipline to submit well-reviewed code. Vessels's approach uses Git's branching and GitHub's pull requests to marry those two goals, reducing friction for both developer and reviewer.



