Hacker News new | ask | show | jobs
by tao_oat 2 days ago
Here's a common flow where I find stacked PRs are useful:

- I want to build feature X

- Ah, but it would work better if I refactored the module first

- I refactor then build feature X

- There's then some additional (and optional) cleanup work

As a reviewer I wouldn't want to see all this in a single PR, and the changes depend on each other so I can't open multiple independent PRs. Manual rebasing is fine but navigating the GitHub UI is then annoying, I have to mentally keep track of where I am in the stack.

4 comments

Those could just be individual commits on a branch. Why does it need to be a stacked PR? That concept really only exists within the interfaces of these kinds of tools.
They don't. But reviewing individual commits in the GitHub UI is hard.

A set of stacked PRs is exactly the same as a line of commits. The only difference is the UI, but the UI is the important bit here because lack of UI is what's stopping folk from doing that today.

Even when I've developed my changes as a stack of commits, I'll feed them to my team one commit (and one PR) at a time so they're easier to review — and I discovered that GitHub had turned on stacked commits UI because for one particular project I'd manually created a set of PRs in advance (with the right bases) and GitHub offered to create a stack out of them.

> They don't. But reviewing individual commits in the GitHub UI is hard.

So instead of solving that problem, GitHub developed tooling around a workaround for that problem (targeting a PR at another branch that also has a PR).

Expanding reviews to allow per-commit reviews avoids the need for managing additional branches and all the headache that comes with it.

Indeed. But lots of people have never even heard of Gerrit :P.

And the implementation feels very much like it sits in the UI layer, rather than further down the stack.

I'm not trying to claim stacking PRs in this way is the best way (it's not). But it does add an extra affordance for those who want it without burdening those who don't with the need to understand why someone would prefer it.

And there are also plenty of ways that people have been working around GitHub's (and to a lesser extent, git's) lack of tooling for working on changes in this way. I'm sure they have customers clamouring for the feature; whether they'll be happy with what they get remains to be seen.

(Very happy jujutsu user here, my tooling makes it really easy to create stacked commits with a stable identifier that maps really easily to branches and then onwards to running `gh stack`, but what GitHub have delivered is definitely still lacking)

I’m a pretty clean committee. About every graphite stack I’ve worked on for the past 2years has been single commit per PR. The tooling managing all the rebasing and PR bases is great.
The sad fact of life is that too many developers are used to pushing PRs with unprincipled commits, and relying on squash merges.

The approach that GitHub chose can show those people almost immediate benefits, which is surely the better path towards adoption than trying to reeducate everyone to adopt a development flow based on clean rebases.

And for those of us who do prefer clean rebases, the thing they built is still useful.

A bunch of details aside, the major conceptual thing that the email based flow has which is still missing in GitHub's data model is the ability to have a discussion on the stack as a whole.

> The sad fact of life is that too many developers are used to pushing PRs with unprincipled commits, and relying on squash merges.

We couldn't organise our commits once the PR review started because reviewers would complain they couldn't easily determine what had changed between rounds of reviews.

If we tried to organise them after review then approvals would be stripped so squash was the only way we could keep the main line history reasonably tidy as you can keep the approvals if GitHub does the squash via the UI.

GitHub will now maintain approval if a rebase doesn't result in a changed diff. Small things :P.
They could but they don't belong together. A PR should be about one thing. Refactoring one module for another's sake should be done in another PR. If not for reviewing, for revertability, and future debuggability.
Yeah, I think it's largely a UI issue! I really want a UI that lets me review distinct changes that are dependent on each other, and handle comments/changes neatly within that structure. I've found GitHub quite lacking there historically.

Also, if you're the mchristen I know, then I think we've had this discussion before haha! Hope you're well :)

Hah, indeed. I only know one Tao :) Some things never change I suppose
I certainly don't want to see that in a one commit. A PR has one more more commits, though.

The commits in a PR are already a stack of patches, and so PRs are already "stacked" as they are.

If feature X depends on the refactoring (cannot be rebased on the un-refactored upstream), it's part of the change; you can't just merge the feature and not the refactoring.

If the two are separable that way then, sure, it makes sense to ask for them to be separate PRs.

Why isnt refactor in its separate PR? Every developer with an ounce of thought would tell youn to:

>Do PR refactoring module A >Do PR with feature X + cleanup >Maybe PR with additional work if bigger

I think we're saying the same thing, that's how I use stacked PRs.
I do that too. I do introduce changes in separate PRs. They could be related to the same problem and referenced accordingly.

  and the changes depend on each other so I can't open multiple independent PRs
Why? Is it a technical restriction? Tightly coupled architecture is not the best solution anyway.
A refactor and then a feature implemented on that refactor is tightly coupled by definition. It would not make sense to implement the feature and refactor independently, because you’d be wasting time implementing a feature that you would have to refactor again.
This is literally the point of stacked PRs. You implement the refactor in branch A, then branch B is created on top of that so you can implement your feature. Then you make separate PRs, one for merging branch A into main, and another for merging branch B into A. The GitHub feature just provides a nicer UX when interacting with such PRs by clearly showing dependency and allowing you to merge a stack together.