logoalt Hacker News

akerstenyesterday at 9:30 PM9 repliesview on HN

Does it fix the current UX issue with Squash & Merge?

Right now I manually do "stacked PRs" like this:

main <- PR A <- PR B (PR B's merge target branch is PR A) <- PR C, etc.

If PR B merges first, PR A can merge to main no problems. If PR A merges to main first, fixing PR B is a nightmare. The GitHub UI automatically changes the "target" branch of the PR to main, but instantly conflicts spawn from nowhere. Try to rebase it and you're going to be manually looking at every non-conflicting change that ever happened on that branch, for no apparent reason (yes, the reason is that PR A merging to main created a new merge commit at the head of main, and git just can't handle that or whatever).

So I don't really need a new UI for this, I need the tool to Just Work in a way that makes sense to anyone who wasn't Linus in 1998 when the gospel of rebase was delivered from On High to us unwashed Gentry through his fingertips..


Replies

sameenkarimtoday at 12:07 AM

Yes, we handle this both in the CLI and server using git rebase --onto

  git rebase --onto <new_commit_sha_generated_by_squash> <original_commit_sha_from_tip_of_merged_branch> <branch_name>
So for ex in this scenario:

  PR1: main <- A, B              (branch1)
  PR2: main <- A, B, C, D        (branch2)
  PR3: main <- A, B, C, D, E, F  (branch3)
When PR 1 and 2 are squash merged, main now looks like:

  S1 (squash of A+B), S2 (squash of C+D)
Then we run the following:

  git rebase --onto S2 D branch3
Which rewrites branch3 to:

  S1, S2, E, F
This operation moves the unique commits from the unmerged branch and replays them on top of the newly squashed commits on the base branch, avoiding any merge conflicts.
show 2 replies
xixixaoyesterday at 9:37 PM

Conflicts spawn most likely because PR A was squashed, and once you squash Git doesn't know that PR B's ancestors commits are the same thing as the squashed commit on main.

No idea if this feature fixes this.

Edit: Hopefully `gh stack sync` does the rebasing correctly (rebase --onto with the PR A's last commit as base)

show 1 reply
Phlogistiquetoday at 12:09 PM

I made a tool that adresses this precise problem: https://github.com/scortexio/autorestack-action/

It does some merge magic so that PR B shows the correct diff; and does so without needing to force push, so on your side you can just "git pull" and continue working.

Of course I expect this repo to become obsolete when GitHub makes their native stacking public.

pastel8739yesterday at 10:21 PM

I agree that this is annoying and unintuitive. But I don’t see the simplest solution here, so:

All you need to do is pull main, then do an interactive rebase with the next branch in your stack with ‘git rebase -i main’, then drop all the commits that are from the branch you just merged.

show 2 replies
patricktheboldtoday at 12:10 AM

I'm not sure I follow your workflow exactly. If PR B is merged, then I'd expect PR A to already be merged (I'd normally branch off of A to make B.)

That said, after the squash merge of A and git fetch origin, you want something like git rebase --update-refs --onto origin/main A C (or whatever the tip of the chain of branches is)

The --update-refs will make sure pr B is in the right spot. Of course, you need to (force) push the updated branches. AFAICT the gh command line tool makes this a bit smoother.

gregorylyesterday at 9:39 PM

If I'm following correctly, the conflicts arise from other commits made to main already - you've implicitly caught branch A up to main, and now you need catch branch B up to main, for a clean merge.

I don't see how there is any other way to achieve this cleanly, it's not a git thing, it's a logic thing right?

show 2 replies
jiveturkeytoday at 12:32 AM

You "just" need to know the original merge-base of PR B to fix this. github support is not really required for that. To me that's the least valuable part of support for stacked PRs since that is already doable yourself.

The github UI may change the target to main but your local working branch doesn't, and that's where you `rebase --onto` to fix it, before push to origin.

It's appropriate for github to automatically change the target branch, because you want the diff in the ui to be representative. IIRC gitlab does a much better job of this but this is already achievable.

What is actually useful with natively supported stacks is if you can land the entire stack together and only do 1 CI/actions run. I didn't read the announcement to see if it does that. You typically can't do that even if you merge PR B,C,D first because each merge would normally trigger CI.

EDIT: i see from another comment (apparently from a github person) that the feature does in fact let you land the entire stack and only needs 1 CI run. wunderbar!

contravariantyesterday at 11:55 PM

Oh that's annoying, seems to me there wouldn't have been an issue if you just merged B into A after merging A into main, or the other way around but that already works fine as you pointed out.

I mean if you've got a feature set to merge into dev, and it suddenly merges into main after someone merged dev into main then that's very annoying.