Stacked PRs are now live on GitHub
Posted by tomzorz 3 days ago
Comments
Comment by matharmin 3 days ago
For example, merging an entire stack is completely broken in many cases: https://github.com/github/gh-stack/discussions/212
You can merge one by one, but if you're using squash and merge, you need a re-approval for each PR in the stack if you require reviews. This makes you lose out on arguably the biggest gain of stacked PRs.
The command line tooling (gh stack) helps to make things slightly less manual, but you still need to be very aware of how git rebase works, the tooling just helps automate it across multiple branches. For example, just running the "gh stack rebase" commands that the UI suggests won't work if your local branches are not in sync with the remote ones, and the tooling won't point that out to you.
I do find the stack UI quite nice. It's quite minimal compared to standalone PRs, but it's enough to show the relationship between them.
(My comments all assume you already have a good reason to stack PRs. This tooling just help to make the workflow easier, it does not give any new capabilities)
Comment by sameenkarim 3 days ago
There's an internal system we have called CPRMC (Create Pull Request Merge Commit) that is used to evaluate whether a PR is "ready" to merge. This covers everything from mergeability (checking for merge conflicts) to rule evaluations (ensuring that approvals match the potential commit that will be created by merge) and more.
This becomes particularly difficult when squash merging a stack of multiple PRs because we have to calculate a series of squashed commits, then associate those back to the rules/reviews. This is relatively easy for the first PR, but for the second PR onwards this gets more complicated because the ancestor commits are squashed and don't exist on the branch as-is. And I won't get into how much more complicated it gets for multi-parent situations lol.
It's something we need to fix and it's the top priority for the team. Our numbers show that 99% of stack merges go through successfully, but we need to get that much higher.
Thank you for being an early user in the preview and bearing with us while we work out these issues!
Comment by Game_Ender 3 days ago
We use a custom merge queue and we want it to be able to land multiple PRs from a stack at once as separate PRs. Last I checked you had to land a single PR, rebase the stack, land the next and so on. This is very expensive in CI time (and wall clock time), vs simply testing part or all of a stack in parallel then declaring those merged. In essence a robot needs the ability to say “squash merge these 3 stacked PRs”, after the queue does its thing.
Comment by sameenkarim 3 days ago
For merging, we have an API but had to move it to a new async method: https://github.github.io/gh-stack/reference/merge-api/
The legacy API was fully synchronous, and since stacks of multiple PRs can often take more than 10s (our global timeout), we had to move to async.
We've had some folks already use this to integrate stacks into their merge queues. The great part is you can land multiple PRs in one atomic operation, and then there's one push to main with all your commits from multiple PRs. So instead of having to rerun the build/deploy for each, it can trigger for the last commit that contains all of the changes.
Comment by masklinn 3 days ago
Also what about external merges? Is there a way to sanely interact with stacks when merging locally or via external tooling?
Comment by mattmatheson 3 days ago
They do indeed have APIs you can use in your mergequeue, I'm happy to share notes on how we built it so you can add it to your mergequeue.
Comment by masklinn 3 days ago
Comment by mattmatheson 3 days ago
Using the GitHub APIs means you still preserve history and commit messages they way people expect (merges through the queue and direct merges behave the same), and it lets users guarantee that the only code our mergequeue merges is the code that was in the PR.
Comment by masklinn 3 days ago
By the way could there be a way to disable that when doing integrations externally? It seems to be quite costly (which makes sense), and the pull/ refs kinda bloat the reflist.
I’m sure that external integration is not exactly beloved internally but there’s really just a small handful of big annoyances which would make it so much nicer and more comfortable.
Comment by 14u2c 3 days ago
Comment by teiferer 3 days ago
I acknowledge that it is not trivial.
But this is 2026. Many people have solved this in in-house solutions. Every place I have worked at in the last 10 years had solutions in place. Some had wrinkles but it all worked in the end. Github sees itself as the leading provider of solutions in that space and has MSFT backing. Just saying that it's difficult is not good enough, quite frankly. People have been complaining about GH support for this for a long time.
Comment by Daishiman 2 days ago
But most of those solutions don't have the number of integrations and rules executions that GH has and that's where the challenge lies.
Comment by teiferer 2 days ago
Comment by saghm 3 days ago
> You can merge one by one, but if you're using squash and merge, you need a re-approval for each PR in the stack if you require reviews. This makes you lose out on arguably the biggest gain of stacked PRs.
I'm struggling to imagine what it offers at all if that doesn't work! Is it just a way of manually marking another MR as a dependency in the UI so that it shows up with a red X if the other one isn't merged yet?
Comment by Filligree 3 days ago
Comment by saghm 3 days ago
Comment by progval 3 days ago
Comment by radicality 3 days ago
Comment by hobofan 3 days ago
Comment by sameenkarim 3 days ago
Comment by an0malous 3 days ago
Comment by mosura 3 days ago
Ultimately they have become a monopoly so it is kind of expected.
Comment by zelphirkalt 3 days ago
Comment by OtomotO 3 days ago
Even though I live in a western country, just one of my clients after all these years of being self-employed, uses GitHub.
Nobody else would ever use it. And why would they? Especially for proprietary applications.
Comment by CalRobert 3 days ago
Microsoft seems to be running the classic embrace, extend, extinguish playbook on github/git though. When it becomes impractical to join a team's workflow without github specific tooling then everyone will be forced to use gh.
Comment by vermilingua 3 days ago
Comment by selimthegrim 3 days ago
Comment by sameenkarim 3 days ago
Comment by keeganpoppen 3 days ago
Comment by ransom1538 3 days ago
Comment by necovek 3 days ago
So really, one does consider full stack a single feature, but unless they are reviewed in one go — which defeats the purpose of stacked branches and pull requests — you can end up landing one and a later review in branches higher in the stack needing changes in the lower branches even if they were already reviewed.
When you instead focus on full use-case per branch, but scope them down, it is much less likely you will need to change branches lower in the stack after they are reviewed.
Another obvious use-case is to do a pre-emptive refactor, though I actually prefer doing a post-refactor after the new use-case has been merged in — it's much easier to know the target best approach when you've got your use-cases right in front of you (or you may hit a similar problem as above).
FWIW, I remember fondly using bzr-pipeline plugin to bzr VCS ~15 years ago to do exactly this.
Comment by radicality 3 days ago
* I often used it as a way to make reviews significantly easier for the reviewer. If I split something more complex into smaller units where the small change seems obviously correct, it's much more likely i'll get a faster accept than with a very large change.
* Critically, once a unit of the stack has been approved, the approval will still stay with rebases of the whole stack.
* You can keep building up a stacs and once you think you have enough for whatever you are doing, ship the whole stack.
* Suppose you have a 'hole' in the reviews and you're missing a review for a middle part of the stack. You can still merge the bottom part up to where all are reviewed.
* Let's assume you're the reviewer: smaller changes is much easier to review. Also, each part of the stack builds incrementally on the previous one. With your example, suppose you're reviewing 'api changes' part of the stack, but it has failing tests because something is broken with the lower 'db schema changes' change - but otherwise, the 'api changes' diff looks fine - you can then accept it and this part of the stack is already reviewed. The author can now whenever fix their bottom-most change (db schema change) to have tests passing, and get someone to review that (perhaps someone completely different more familiar with db), and then rebase the 'api changes' diff, and _it will not_ require review because you haven't changed anything, just updated the diff underneath it. In this way you parallelized your approvals. Right now at work, using github, I have to serialize my PRs and can't effectively get things reviewed until the previous PR is approved.
Comment by alepar 2 days ago
I do agree the above is true. And maybe it's just me, but it feels like I'm kind of cheating if I stack PRs to get a faster approval. Because when one reviews some dangling code without the context of how it's going to be wired in, they can't really tell what the blast radius will be and consequently what bar they should hold the code against (e.g. performance, security, etc). In these circumstances, usually the most one can do is raise some stylistic nits (which to be fair PR process often degrades into anyway) and move on.
Comment by necovek 2 days ago
Except that you tried not to divide it by technical aspect (DB changes vs API vs frontend) bit instead into smaller, semantic full features (we also used a 800/400 line diff limit which helped enforce it).
Comment by nirvdrum 3 days ago
I think in my ideal world there would be a clean history and I could review a PR commit-by-commit. But, you can't just approve a single commit, so there's a tooling problem there. And most CI runs on an entire push rather than individual commits. And increasingly I see devs using git as an offsite backup for whatever change they just made, rather than breaking commits up into logical chunks. In that workflow, squashed merges make the most sense.
It's probably flawed, but the mental model I came up with is each stacked PR collapses into what would have been an individual commit in a clean PR, with the advantage of being able to be reviewed separately from the other changes and forced to clear CI. And then the whole stack becomes what would have been a clean PR in the old model. That, I can kinda see the benefit of. But, merging only part of the stack into trunk is the mental hurdle I can't clear; it'd be like merging only some commits from a PR. It kinda reminds me of when projects used CVS.
I've really only seen stacked PRs used on projects where history is little more than an audit log. I'm keen to see how this gets employed by open source projects. I think there's a disconnect and it's likely I'm not going to really get it until I see it.
Comment by defmacr0 3 days ago
Comment by nirvdrum 3 days ago
Comment by ollysb 3 days ago
Comment by eddythompson80 3 days ago
The person making the change is now going to have to run multiple confusing interactive rebases and git shenanigans, the rewrite the history of the PR branch on every feedback, then you have to re-review all the commits again because they are all different.
It’s possible of course to push all that complexity on the tooling. Have GitHub and git provide tooling for doing all that within the context of a single branch/PR. But why is that better? Multiple branches are easier to manage in git, and as long as they don’t conflict on the merge. Obviously if a feedback on PR#1 causes a conflict in PR#2 which causes a conflict in PR#3 it’s still tedious, but it’s a lot more doable than managing interactive rebases on every feedback comment.
Comment by Kinrany 3 days ago
Comment by Degorath 2 days ago
Comment by eddythompson80 2 days ago
Comment by Degorath 2 days ago
Comment by rendaw 3 days ago
Comment by flexagoon 3 days ago
Comment by necovek 2 days ago
Commits on a branch are a tool for a developer, and they will go back and forth a bit as they learn more about it, perhaps explore a path, and then go back on it.
With bzr (Bazaar, since abandoned by Canonical, but maintainers forked it as Breezy), you had a nested history: top-line merges look like squashed merges in git, but you simply do a bzr log -n1 and get to see the next level of commits in each merged branch and you can understand the build process and explore what other things original author tried out which did not work. It is simply a way to get the best of both worlds IMO (it was noticeably slower than git, though).
I did find it hard to get the product and design to adopt a similar mindset of developing a feature iteratively, so it was usually the developer who'd come up with in-between designs and UX flows while they converge to the final design over multiple small branches.
Comment by Okkef 3 days ago
I think the bigger problem is that big AI PR's need a different way of reviewing. For example, the order in which the diff's are shown can make a big difference in how easy the commits are to read (e.g., function definition change first, then all call sites, then the tests).
Or maybe we should go to a system where diffs & comments are intertwined, a bit like how "Literate Programming" intertwines code and prose.
Literate diffs / literate pull requests... I haven't found anything like that yet.
Comment by dastbe 3 days ago
For the people who work with stacked diffs (in phab/otherwise) this is exactly what they'd consider reviewing a well-curated set of commits one-by-one.
One distinction is that cognitively a unit of review (a PR, a diff) remains a single bound change. Comments are focused on that change and the PR does not grow with size of the feature
Another distinction is the ability to focus each part of the stack to a particular audience. One change may require review from an external team, another may be just your team mate, a third might be the consuming team. By focusing the stack to the different reviewers you can avoid ambiguity about "what a person is signing off on" in the stack.
aside: one thing that would be great for github reviews is the adoption of change ids such that comments persist across reviews with a rebase workflow.
Comment by skydhash 3 days ago
> . By focusing the stack to the different reviewers you can avoid ambiguity about "what a person is signing off on" in the stack.
That can be easily done with comments. If the PR are orthogonal, they could have been split. And if they're not, I would really like to know how the part that I'm reviewing interacts with the rest of the changes.
Comment by a_t48 3 days ago
Comment by skydhash 3 days ago
I strongly believe that PR should be compared to the main branch, and not rely on unmerged code. Unless you merge everything together in one go. And in the latter case, everything should be reviewed together.
Comment by a_t48 3 days ago
Comment by Degorath 2 days ago
Comment by makeitdouble 3 days ago
I'm also on the "compare to the main branch" camp in general, but will sometimes end up with a set of X,Y,Z branches that have different purposes but all depend on X.
More often than not, the base dependency is a set of constants or additional class/methods that could be released with no impact (no reference in live code) but still need a somewhat lenghty review process. Reverts would be happening on the higher level PRs, which hopefully are independent.
Comment by dastbe 3 days ago
Comments are ad-hoc and don't scale, relying on the author to interpret and adhere to the extent of the reviewers approval.
> And if they're not, I would really like to know how the part that I'm reviewing interacts with the rest of the changes.
you are free to look up, down, and around the stack; nobody is hiding the code from you. But in many cases this is just unnecessary.
Comment by tdeck 3 days ago
In my opinion there's already too much of a bias toward stamping PRs, and organizations that maintain high standards do it partly by resisting that bias in key parts of the codebase so people can push back on things that are poorly engineered or hard to maintain.
Comment by skydhash 3 days ago
Anything that would take a bit longer is either a failure of communication (no design specs, no PR description), a failure of tooling (setting up the project, running tests,...) or a lack of policies (no big changes in a PR).
Comment by hypendev 3 days ago
i.e. like this where each one targets prior PR1 db_migrations PR2 backend_base PR3 adds_frontend_scoobydoodle PR4 adds_some_landing_page_thingy PR5 probably_have_to_fix_something
Or is stacks just a feature built to make this type of PR stacking easier to review?
Comment by m11a 3 days ago
Comment by eddythompson80 3 days ago
Pretty much, yes. It’s just a UI to make it clear that those 5 PRs are liked (stacked) and gives some tooling around reviewing, merging and managing them, reduce redundant CI runs if desired, etc
Comment by teeray 3 days ago
Comment by ghthor 3 days ago
Honestly all GitHub needed to do was make reviewing and merging commit(s) from a PR possible and that would also been neat.
Comment by chillfox 3 days ago
One use I have got from it is asking an agent to go through the git history and categories the mistakes/bugs, then turn the common ones into CI checks or AGENTS.md rules.
A well curated history just hides a lot of valuable info.
Comment by eddythompson80 3 days ago
or "skjdnfks" and "fsdfs" commits.
Comment by dualvariable 3 days ago
What I can see is that you can easily append commits to e.g. the first PR in a stack, which would insert them into the middle of sequence of commits.
This will require rebasing and fixing the subsequent PRs in a stack the same way you'd need to rebase and fix the subsequent commits in a mega-PR. But it makes the right thing easy (keeping all the commits to the foundation of the change together) rather than makin the wrong thing easy (appending fixup commits across the entire change in a random order so that the actual foundational change is lost).
Keeping all the foundational commits together also keeps all the discussion over the foundational change together.
You could argue that you'd want to only do the foundational PR and stop, but doing the whole stack of PRs gives the reviewers more information about where you're going, and allows work to continue asynchronously.
Comment by Cedricgc 3 days ago
Comment by paxys 3 days ago
Comment by ahepp 3 days ago
It kinda seems like they're duplicating the "unit of change" arbitrarily, rather than just fixing the way a PR works.
I think the reason I find that a bit icky is it seems like it's diverging GitHub from the underlying git tool, which I trust a lot more.
Comment by mcintyre1994 3 days ago
I don’t really see it as diverging much from the underlying git tool TBH - it’s still just git branches pointing at each other.
Comment by paxys 3 days ago
Comment by ahepp 3 days ago
Torvalds invented Git for work on the Linux kernel, and the basic unit of change there is commits over email. It's not uncommon for them to take some commits but reject others.
Which isn't meant to say "pull requests are obviously wrong and commits over email are obviously correct", but rather to point out that the idea of a take-it-or-leave-it branch isn't some kind of natural unit of contribution
https://lkml.iu.edu/hypermail/linux/kernel/1402.2/00508.html
https://lkml.indiana.edu/2011.2/05416.html
https://lkml.iu.edu/2409.0/00960.html
https://lkml.iu.edu/hypermail/linux/kernel/2510.3/01369.html
Comment by skydhash 3 days ago
After reading this article[0], it's become clear to me that what you want is a reference branch, which people propose changes to. Then there's the integration process that takes a unit of change (commit or PR) and then tests that the reference branch is <good> after applying that change. If it's not, then that unit of changes is sent for rework. If it is, it's now become part of the reference branch and the next units of change needs to be able to work together with it.
In corporate work, I tend for the PR to be the unit of work, which means squashing and merging. But any PR is compared to the default branch, not each other. Anything that is not yet part of the default branch, even if approved, is unreliable. So as the author, you'll need to refresh your PR to not rely on an old state of the reference branch.
I think there is too much focus on the PR itself instead of the reference branch which reflect the true state of the next release. Like their PR was good at the time of writing, so it should be merged. Instead of whether merging their PR would break the reference branch.
[0] http://kroah.com/log/blog/2019/08/14/patch-workflow-with-mut...
Comment by Am4TIfIsER0ppos 3 days ago
Sure you can. The command is `git merge`
Comment by ahepp 3 days ago
As far as I can tell, the biggest benefit of stacked PRs over just making a coherent series of commits, is that it might make it easier to start work on your second PR before you merge the first one?
With human-in-the-loop coding, that sounds like it could lead to a lot of wasted work if the first PR gets substantial feedback. But with agentic coding, I can imagine how it might be desirable to keep the agent chugging while the first PR is under review.
Interested in learning more about it and generally agree that AI is stressing the current review paradigms a lot of us are accustomed to.
Comment by 332451b 3 days ago
If review is fast I'd be switching back and forth between tasks throughout the day. If review is slow I might end up implementing a feature over the course of two weeks rather than two days. With reviewers in different time zones, limited time or doing their own focused work, it adds a lot of latency going back and forth for every PR rather than iterating on a stack of PRs.
Personally I find the biggest benefit is that it lets both the author and reviewers work at the pace that works for them, with reduced context switching and latency.
Comment by ghthor 3 days ago
Comment by mmlb 3 days ago
Comment by satvikpendem 3 days ago
Comment by skydhash 3 days ago
Can't you run your CI locally? I know it's not feasible for some codebase, but at least the linting, formatting, unit tests, some integration tests should be able to be done locally.
Comment by nijave 3 days ago
If you mean automated tests and linters, sure.
Conceptually continuous integration is generally integrating 2+ different lineages of code together which is more common with multiple developers although I suppose it's becoming more relevant with agents creating a bunch of worktrees with different things.
In practice, CI has taken the same path as "DevOps Engineer" ie most people just mean "automated test server"
The opposite of CI is more-or-less merge windows or merge-fest like Linux where everyone mails in their changes and someone manually integrates.
Comment by happimess 3 days ago
> In practice, CI [often means] "automated test server"
Could you say more? I use "CI" to refer to the automated processes that run tests and (maybe) deploy code as it is merged to some blessed branch. It's what continually integrates the new code into the existing code. What am I missing?
Comment by nijave 1 day ago
Now say there's 2 developers that branch off A. Dev 1 removed dead code coolUtil and with it deleted module coolLib and commits B1. Tests pass, code works. Dev 2 adds new coolUtil2 in commit B2. Tests pass, code works. Now they both merge their changes back to branch A so it's A, B1, B2 or A, B2, B1 or A, B3 (merge of B1/2). Anyway, you try to run the code and it fails. Everything merged clean but Dev 1 removed the lib Dev 2 depends on. They didn't create any file level conflicts because they edited different things so the merging went fine however now the code is broken.
The real integration part comes from reconciling different (potentially conflicting) changes and making sure the end result still works. The server is doing the integration automatically and verifying it automatically
You could skip the server and merge everything on your machine and run the tests on your machine and achieve the same result. Still CI, no server, no automation
Hopefully that makes sense, if not I think the Wikipedia page "Practices" section does a decent job separating the pieces https://en.wikipedia.org/wiki/Continuous_integration
Comment by steveklabnik 3 days ago
Not every project requires this, but for those that do, it's impossible.
Also, it is much harder to enforce "everyone must run each commit through the CI equivalent properly" than it is when it's on your forge.
Comment by skydhash 3 days ago
Why can't you? That's what VMs are for. And even then, most cross-platform codebases have an abstraction layer that rarely changes. So even testing on one platform can raise your confidence very high.
> Also, it is much harder to enforce "everyone must run each commit through the CI equivalent properly"
Again why? I wouldn't care about the dev's local branch. But what is send to the main repo can be easily scripted to run the CI on every commit. You just send the result back with each commit that fails. They can replicate the same workflow on their local workspace as a pre-push process.
Comment by steveklabnik 3 days ago
> But what is send to the main repo can be easily scripted to run the CI on every commit.
Sure, this could work. I didn't say it was impossible, just more difficult. You have to build all of this support on top of the system that already does it for you: have your forge run CI on every commit.
Comment by sfink 3 days ago
Sure, I could load up my build machine with mac/windows/linux/android, with multiple versions of each. Emulating x86+x86_64+arm32+arm64+aarch64+... is also doable, sort of.
But considering that the real CI runs several thousand hours of tests total across all platforms, I think I won't.
Also, my Electron-based IDE needs those 10s of GB to edit text. How can you possibly edit a 1KB text file with less than 1GB of RAM?
Not to mention clangd that needs to do its ultra-important work Right Now so I can invalidate it all with my next edit. That's probably the biggest RAM hog of them all.
Comment by tabwidth 3 days ago
Comment by EduardoBautista 3 days ago
Comment by ghthor 3 days ago
Comment by m11a 3 days ago
If GitHub's unit of change were a diff, and not a branch, then that would work pretty well.
Comment by othmanosx 1 day ago
Comment by aeturnum 3 days ago
So the idea is you can much more cleanly isolate changes for large features.
Comment by brabel 3 days ago
Comment by madeofpalk 3 days ago
Comment by lnrd 3 days ago
Even if the reviewer does the review commit-by-commit, all the comments and discussions will be on the same PR leading to multiple ongoing conversations about different topics that would be split if the PR are stacked. Also, all the new commits addressing the comments with spoil this commit-by-commit design, as the previous commits will be outdated and the new changes will be on top of those. I think it's beneficial for new changes to be a separate commit and not rewriting history, to not force the reviewers to re-read everything but just the latest changes.
Comment by IshKebab 3 days ago
2. It also can't merge subsets of commits from a single PR. E.g. if you have two commits, A and B, where B depends on A... sure you can make a PR containing A and B, but if A gets approved and B doesn't, then you can't merge A.
3. The thing you want to do with a set of commits and reviewing each commit IS stacked PRs.
This is nothing to do with AI.
Comment by catlover76 3 days ago
Comment by hoppp 3 days ago
Comment by sameenkarim 3 days ago
Excited to release this more broadly so anyone can start stacking: https://gh.io/stacks
Would love to hear any feedback, especially with the UI and CLI. We've got a lot more updates to the PR experience in store!
Also happy to answer questions about the design decisions we made. There's a bunch happening behind the scenes, and it's one of the largest launches in GitHub history covering almost every service from Actions and protection rules to the CLI and mobile apps.
Comment by sunshowers 3 days ago
The fundamental issue with GitHub -- really, its original sin -- is that the review model is wrong. It encourages a new commit + merge workflow, which is simply worse than an amend + rebase workflow. Basically every other review system in existence -- Gerrit, Phabricator, what Google and Meta have internally, the LKML -- works around stacks where people amend and rebase their commits when changing them. All of these have some notion of a "diff", with "versions" that are each tracked separately, and the ability in the review tool to do diffs between those versions. My hope with stacked PRs was that for once GitHub would use this as an opportunity to modernize its review system and bring it in line with all of these other ones. But sadly that just doesn't seem like it's on the cards.
Comment by Anon1096 3 days ago
Comment by crakhamster01 3 days ago
1. Adding commits means reviewers can easily diff changes to the PR
2. Squash merging preserves only 1 commit per PR ends up on trunkComment by sunshowers 3 days ago
Comment by Game_Ender 3 days ago
The optimistic person in me thinks now that have a major feature which rebases and amends all the time, they will dust that off and get it shipped. Like you said, is shows a fundamental miss-understanding of the problem.
Comment by ptx 3 days ago
Comment by Groxx 3 days ago
GitHub constantly feels like features get requested with a one-sentence description, and then people who have never used any other major code review systems go build it without any further assistance or feedback, and eventually it just escapes containment and nobody tells the authors that there's a gigantic pile of bug feedback threads until almost a year later. Ten things get fixed, then another feature breaks out and focus shifts.
Comment by sunshowers 3 days ago
Comment by ahoka 3 days ago
Comment by sunshowers 3 days ago
I guess the next best thing would be to port spr to this. (Probably time to start looking at this to be honest!) This makes me quite sad.
Comment by Degorath 2 days ago
Comment by sunshowers 2 days ago
Comment by Degorath 2 days ago
Comment by sunshowers 1 day ago
Comment by Groxx 3 days ago
Comment by Too 3 days ago
Allowing two different workflows – even within the same project – just shows the lack of strategy for how this should work.
Re-educating when and when not force-push is a holy sin is also a barrier to alignment.
Comment by sunshowers 3 days ago
Comment by sefrost 3 days ago
Comment by pavon 3 days ago
Comment by sunshowers 3 days ago
Comment by gsnedders 3 days ago
There’s enough ways you can match up commits, with plenty of prior art in this space.
Comment by huflungdung 3 days ago
Comment by brabel 3 days ago
Comment by dogleash 3 days ago
Why did you choose extra pull requests as the division of work instead of building out a decent UI for reviewing/applying/reworking at the commit level? I assume there's some extra insight that made you ignore the mailing list "series of patches" workflow that inspired this whole thing and go with "series of series of patches" instead.
Comment by mattmatheson 3 days ago
We worked with Sameen over the last month to add support for GitHub stacks into our mergequeue, and I'm excited to announce support for it today: https://trunk.io/blog/trunk-merge-queue-now-supports-github-...
Comment by MBCook 3 days ago
Am I right this is only available through the CLI?
If so it’s a no go for me and my team. Which is too bad because it looks quite useful.
An addition ability I would love, which is a MUCH bigger feature and I recognize that, would be multi-repo stacks.
My company doesn’t use a monorepo, and I like that. But as we’ve been breaking monoliths sometimes a logical feature touches multiple repos.
Being able to have them all in a stack, each building on the previous logically though in different repos, would be amazing.
Maybe it should have a different name. PR Trains? PR Chains? IDK. But being able to have multiple projects in one logical review is the one benefit of a monorepo I’d like, and if I could get it a different way I’d love it.
Comment by fphilipe 3 days ago
Comment by MBCook 3 days ago
Comment by carderne 2 days ago
Comment by leo60228 3 days ago
Comment by sameenkarim 3 days ago
We will support a stack that is fully contained within a single fork, where the entire stack targets the original repo.
For example, a contributor who has a fork (user/buzz) of the original repo (org/buzz) could create the following stack:
``` frontend → PR #3 (base: user/buzz:api-endpoints) api-endpoints → PR #2 (base: user/buzz:auth-layer) auth-layer → PR #1 (base: org/buzz:main) org/buzz:main (trunk) ```
Comment by doctorpangloss 3 days ago
i appreciate that you are trying to make it possible for people who vibe code solutions to problems to get code merged by people who have made GitHub their lifestyle. but surely you see how, in my framing there, the people who are worried about how their history "looks" are the problem
Comment by RyJones 3 days ago
Comment by hedgehog 3 days ago
Comment by DreadY2K 2 days ago
Comment by joenot443 3 days ago
Comment by lobofta 3 days ago
Comment by miovoid 3 days ago
Comment by saghm 3 days ago
Comment by CBLT 3 days ago
Comment by Too 3 days ago
Comment by Shish2k 3 days ago
(I would love to be proven wrong if there's been some progress that I didn't get the memo about ^^)
Comment by steveklabnik 2 days ago
Comment by steveklabnik 3 days ago
If you buy the idea that stacking produces better software, then this also has the opportunity to really help out quite a few people.
Comment by nonethewiser 3 days ago
Comment by shmichael 3 days ago
Comment by Insimwytim 3 days ago
Stacked pull requests break large changes into small, reviewable pull requests.
That's how pull requests are supposed to be, no? If yours aren't that - you ought to rewrite them. With stacks, you can independently review and check each pull request, then merge everything together in one click.
Why would I want to do that instead merging (and deploying/testing) separately, which gives me more reliability? No more opening a single large pull request that takes forever to review, or splitting work across multiple branches you have to keep manually rebasing.
Well, it doesn't seem like a simplification over dreaded "manual rebasing". And the target branch still moves, doesn't it? So, how are you "saved" from rebasing?It's like responsibility is shifted from the author to the tool. That has been tried before, and every time it seem to consistently produce a similarly shaped mess in a different area of a process, but with an added bonus of the tool's own problems and restrictions.
Comment by kazinator 3 days ago
> With stacks, you can independently review and check each pull request, then merge everything together in one click.
Consider:
"With pull requests, you can independently review and check each commit inside the pull request, and then merge the entire pull request in one click."
Pull requests are stacked commits. This does not have to recurse; you don't need stacked pull requests, not to mention stacked pull request stacks.
A commit can already contain changes to multiple files. In many cases, even a complex change can be just one commit. A sequence of multiple commits handles all the remaining cases.
Stacked PRs sound like a use case for someone who never wants a PR to be a container for multiple commits, such that if a unit of work is best done as three commits, they want them in separate PRs. Oh, but now they are not related together, the way a stack of commits is related under one PR, so we need a meta-PR to contain PRs or something.
This could be a consequence of commits being sort of second class citizens in the GitHub UI compared to PRs. If you want a commit to be treated as PR, on the same level, you must create a PR with nothing but that commit. So then, what would have been a single PR with four commits that you could merge with one click is now four PRs. Which you want to be able to merge them with one click.
Comment by masklinn 3 days ago
Except you can’t really do that on GitHub, the “unit if review” is the PR so reviewing commits is adhoc, inconsistent, and awkward, and tracking their changes as they get fixed up is a pain. “Splatting” that as PRs is not the nicest way to do it green field, but it’s an evolution that makes sense in GitHub’s model.
Comment by kazinator 3 days ago
Comment by tao_oat 3 days ago
- 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.
Comment by mchristen 3 days ago
Comment by andrewaylett 3 days ago
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.
Comment by 4lx87 3 days ago
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.
Comment by andrewaylett 3 days ago
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)
Comment by ghthor 3 days ago
Comment by atq2119 3 days ago
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.
Comment by cube00 2 days ago
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.
Comment by andrewaylett 2 days ago
Comment by esafak 3 days ago
Comment by tao_oat 3 days ago
Also, if you're the mchristen I know, then I think we've had this discussion before haha! Hope you're well :)
Comment by mchristen 2 days ago
Comment by kazinator 3 days ago
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.
Comment by hypendev 3 days ago
>Do PR refactoring module A >Do PR with feature X + cleanup >Maybe PR with additional work if bigger
Comment by tao_oat 3 days ago
Comment by Insimwytim 3 days ago
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.Comment by malcolmgreaves 3 days ago
Comment by pyth0 3 days ago
Comment by mahmouds 2 days ago
Comment by mrkeen 3 days ago
The problem I sometimes have is when I queue up 4 or 5 PRs in the afternoon and expect someone to take a look in the morning.
The diff of A into master looks OK, but then the diff of B looks like AB, and the diff of C looks like ABC - each PR has changes that will have already been merged once earlier PRs have been accepted.
My way around it was to raise E as a PR into D, raise D as a PR into C, etc. Then once approved, I change their destinations back to master for the actual merges.
It really confuses reviewers though, even though it's meant to make it so they only see the appropriate changes.
Comment by ghthor 3 days ago
Comment by m11a 3 days ago
And the v1 is also a bit... basic, and buggy. And I'm surprised there's not clear documentation for agents (given using GitHub stacked PRs CLI won't be in models' training data yet).
It does feel like GitHub hasn't been great at shipping new features for a few years now. Nonetheless, I'm glad to see this rolling out. Once polished, it's going to be exciting to use.
Comment by steveklabnik 2 days ago
It was new leadership back in October that decided to build this, so it took them 9 months or so. To be clear, I am not saying this is a long amount of time, they had a LOT of work to do to get it to this point, just being clear about timelines.
Comment by steveklabnik 2 days ago
Comment by lucky_cloud 3 days ago
Whimsy is fine but that change made me super suspicious about what I was looking at.
Comment by sameenkarim 3 days ago
Comment by Waterluvian 3 days ago
Comment by patte 3 days ago
Comment by phyzome 3 days ago
Comment by aizk 3 days ago
Comment by cebert 3 days ago
Comment by themanmaran 3 days ago
Comment by Waterluvian 3 days ago
Comment by Shish2k 3 days ago
Comment by otto-riz 3 days ago
Comment by petepete 3 days ago
Comment by hext 3 days ago
Comment by robin_reala 3 days ago
Comment by ebrahimh 3 days ago
Comment by sepeth 3 days ago
Comment by sarthak-ag 3 days ago
Comment by Scoring6931 3 days ago
If one wants to keep it to vanilla git.
Comment by yes_but_no 3 days ago
Comment by tao_oat 3 days ago
Comment by theappsecguy 3 days ago
Comment by perspectivezoom 3 days ago
Comment by literallyroy 3 days ago
Comment by theappsecguy 3 days ago
git-spice is specifically targeted to be useful for PR stacking and doesn't require you to do anything differently from normal git operations that you likely use already. It has a bunch of really nice flows and doesn't try to step outside the bounds of what is needed to easily stack PRs
Comment by rrradical 3 days ago
1. The PRs are across different related repos, so they literally can't be combined into one PR.
2. You want to keep producing work while the first PR is in review. So you stack subsequent PRs onto the same branch. Basically just pipelining.
But this feature doesn't seem to hit either use case, and instead just seems to be a different form of stacking commits into a single PR. The standard advice has always been to make atomic and meaningful commits (using e.g. rebase to tell a nice story for the reviewer). And reviewers can go through commit by commit if they like.
What am I missing?
Comment by piskov 3 days ago
Instead of using the same branch, make new branches from that parent and commit there.
The cool thing about that approach is that (at least in git-tower app) is when you edit a parent branch after pr comments, all those new commits will be automatically “restacked” on descended branch (children branches will be rebased on new state or parent, incorporating the hew fixes)
Comment by hypendev 3 days ago
This would be such a insanely useful features for a small subset of power users that they will never deliver.
Comment by lucideer 3 days ago
Pre-approval the CLI tooling effectively enables easier automations around splitting a task into multiple atomic PRs - really great locally but then when you push they just show up as independent unlinked PRs.
Post-approval... they still show up as independent PRs. There's a small nav drop down up top listing the other PRs in the stack but that's it. Literally no meaningful UI changes.
The dropdown also allows you to perform a limited subset if the CLI functionality but this is similar to the ability to edit files in the UI - an optional extra casual use feature that won't be a part of dev workflows: the CLI (or IDE plugins I guess) would be the primary way to perform these actions.
It all left me wondering what the big deal with the preview not being a general release - it's extremely minor optional UI. The stacks cli has been general release since this was announced.
Comment by sameenkarim 3 days ago
Comment by shoyer 3 days ago
Comment by jezzamon 3 days ago
Say you do change A, add a protocol buffer API definition, then implement the server logic (B) and the front end code (C) so that both depend on A but not each other. That can be in a tree. But now you want to add an integration test (D) that depends on B and C. The tree doesn't help you there, and you were better off making it a linear chain by arbitrarily picking one of B or C to be dependant on the other so that you have a code state with all of A,B and C applied to create D on top of.
Comment by dmix 3 days ago
Comment by charcircuit 3 days ago
Comment by othmanosx 1 day ago
even though it's good to have, Github's UI doesn't help it, Github already sucks in terms of the review experience in a pull request and the implementation of the stacked PRs leaves a lot to be desired.
thankfully, I was working on my own solution for this problem and I already integrated a better stacked PRs implementation compared to github, and I'm pretty happy with it.
Pyor (pyor.review), I built it myself, sits on top of github, syncs everything with it, and gives me the benefit of having a better UI and code review experience.
Comment by beaker52 3 days ago
And the upshot for the LLM providers is that they get to charge for n reviews, instead of one.
Comment by eddythompson80 3 days ago
Yes, GitHub could have made the UI allow a “per commit” comments somehow, then allow you to select the set of commits to include in the merge somehow, then write a blog post on how to manage “Address PR comments #1” commits. But the stacked PRs solve all that. Not to mention how people treat commits as their own internal save states. I always enable “squash and merge” option because I think it makes a lot more sense to have 1 commit on main per PR where all the context of the change is either in the commit message or the linked PR.
Also LLM providers charge per token. Charging per “work unit” is still not a solved problem. You can’t charge per “review” when your cost is per token. Just like airlines can’t charge “per ticket”, they have to charge differently depending on the destination. Unless you invent some bs arbitrage to lure users and eventually bait and switch on them.
Comment by IshKebab 3 days ago
1. The whole review interface isn't set up for reviewing individual commits.
2. You can't merge changes progressively.
3. CI doesn't run on each commit.
4. If you have linear history (good idea IMO) you'll lose your nice commit history when you merge it.
This is much better.
Comment by beaker52 3 days ago
You don’t need to merge those changes progressively. If you do, you go through exactly the same process of creating a separate branch and PR. The only difference is that GH has now added some UI and automation for rebasing and merging the PRs. In the past we would have explained the chaining in the PR and rebased manually.
You don’t need CI to run on each commit.
You only lose your commit history if you squash merge, many people don’t, and you don’t have to either.
The arguments come from angle that doesn’t appear to be aware that stacked PRs were a thing before GH made these UX improvements.
Comment by IshKebab 2 days ago
When you have written and submitted a flob for review, you often want to continue your work on top of that, and then you may end up with a second dependent flob that is finished before the first flob is merged.
You want both to be reviewed. You want CI to run on both. It's simply a much better experience if flobs are PRs rather than commits. I dunno how else to put it.
> stacked PRs were a thing before GH made these UX improvements
Not in a way that worked properly. You could sort of do it for PRs within a fork, but it was impossible across forks which is the way most open source GitHub PRs are done.
Comment by beaker52 2 days ago
Yeah, it’s called a branch, or PR. It’s a set of changes you want to sign off.
It seems like you want CI run on every commit, which seems rather unnecessary. And if you don’t, well, that’s always been the case.
> Not in a way that worked properly.
GitHub operates git. No git changes have happened. It’s just commits and branches, in git. So anything that worked before, works exactly the same now, but with buttons taking out some of the small amount of effort you had to put in.
Comment by IshKebab 1 day ago
Comment by yreg 3 days ago
Comment by johsole 3 days ago
Comment by jeremy_k 3 days ago
Comment by 8260337551 3 days ago
Comment by techscruggs 3 days ago
Comment by amethyst 3 days ago
Comment by PennRobotics 3 days ago
Comment by IshKebab 3 days ago
Comment by smoll 3 days ago
Comment by dmix 3 days ago
Comment by dysoco 3 days ago
Sure merging with one single button is nice but I rarely do that, if I'm stacking PRs it's because I probably want to merge gradually.
Comment by jeltz 3 days ago
Comment by jollyllama 3 days ago
Comment by dml2135 2 days ago
Stacking PRs is useful, but I haven't encountered issues with the ergonomics of just using normal git operations to do it. My stacking workflow is roughly:
- Open the first PR from `branch-1` against `main`
- While waiting for a review on that first PR, if I need to build on subsequent work in `branch-1`, I'll `git checkout -b branch-2`, and open a draft PR against `branch-1`
- If the open review requires me to make changes to make changes to `branch-1`, I'll `git merge branch-1` on `branch-2` to pull them up the stack
- After `branch-1` is merged, my draft PR for `branch-2` will automatically update to being opened against `main`
- Repeat as necessary depending on how much stacking is requires and how far ahead I get against my reviewers
I don't find any of this all that difficult or cumbersome. Is there something that this feature offers, that I'm missing out on?
Comment by lukaszkorecki 2 days ago
Comment by danpalmer 3 days ago
If there's an expectation that you might merge a whole stack, I think you're aiming for the wrong thing. And it seems like landing the whole stack is the biggest push GitHub are making here. Part of the point is independently reviewable and independently mergable. If you're going to merge in one go then just put everything in one PR and review commit by commit in that PR. The commit by commit review flow used to suck, but since ~2021 it has been fine.
I feel like GitHub have built what users (who haven't used a true stacking system) asked for, not what they actually need to change their workflow for the better.
A great implementation would be asking hard questions like: what's the role of a single commit? Should PRs be single commit only? What's the real benefit here? How do you encourage smaller units of review (because it doesn't look like this does).
Comment by Kinrany 2 days ago
Comment by skipants 3 days ago
I know that jj isn't for everyone, but for me it's been trivial to see the state of and update all the stacks of branches I have on the go.
Not that I don't welcome this feature; I just think I don't need it anymore.
Comment by Shish2k 2 days ago
Comment by _doctor_love 3 days ago
Comment by wesselbindt 3 days ago
Comment by msalsas 3 days ago
Comment by pyth0 3 days ago
Comment by camilomatajira 3 days ago
Comment by jasonephraim 3 days ago
Comment by rbanffy 2 days ago
The most important thing about tooling is to keep it conceptually simple. The fewer moving parts you need to pay attention to, the more brain cells you can devote to solving your problem.
Comment by ankit84 3 days ago
The underlying stacked PR workflow is unchanged:
1. Create branch B from branch A.
2. Open PR A against main.
3. Open PR B against branch A.
4. Repeat for additional layers.
Comment by zdc1 3 days ago
Comment by gsnedders 3 days ago
The most obvious case is something like adding a Reviewed-By/Signed-off-by trailer based on reviewers, but there’s also a decent number of big projects that want more semantically meaningful commit identifiers (think more revision, in a numeric sense).
It seems like making merges async should make it a lot more possible to implement that!
Comment by DDayMace 3 days ago
Comment by grugdev42 3 days ago
Plus it's vendor lock in.
Give it time. Soon you'll only be able to push using Github's CLI.
Comment by Shish2k 2 days ago
Comment by ozozozd 3 days ago
And we solve this by splitting into 2 PRs that still merge at the same time. Oh, super useful!
Only if your reviews are so shallow that you don’t try to reason about the state of PR B merged to PR A, which would then be merged to main, and your real problem is just GitHub UI failing to handle a giant PR, which we all know that this feature is attempting to help with.
Comment by efromvt 3 days ago
Comment by chill_ai_guy 3 days ago
Comment by zelphirkalt 3 days ago
Comment by whichdan 3 days ago
Comment by Hypnosis6173 3 days ago
Comment by byterivet 3 days ago
Comment by paxys 3 days ago
Comment by hungryhobbit 3 days ago
Both are an improvement (GH's seems a little better, with their one-button merge that GL lacks) ... bit both are so incredibly "meh".
When are we going to see the major hosts give tools designed to help facilitate human code review? Simple example: lets say I want to leave notes in my PR (MR on GitLab). I can use the review comments to do so, but then I have a million comments to resolve at the end before I can merge, my comments look just like the reviewer comments (with extra UI for replying that's unecessary), etc.
It'd be so easy to just have a "sign post" feature to let authors annotate their code before reviewers review it ... and nobody offers this, or any other features focused on actually helping humans review. It's all just new command line features that save a bit of rebasing (which Claude can do just fine on its own).
Comment by jaredsohn 3 days ago
Comment by RohoSwagger 2 days ago
Comment by ivolimmen 3 days ago
Comment by eddythompson80 3 days ago
In the scenario you described of your team splitting the tickets, this gives you a UI to manage the PRs of the multiple tickets so you are no longer blocked on merging PR#1 before you can proceed to PR#2. Yes you might have to deal with conflicts, but you would have had to deal with that regardless.
Comment by santoriv 3 days ago
When you click merge, does a 3 stack PR show up as 1 PR in the Dx metrics or 3?
Comment by pluc 3 days ago
Comment by fatwang2 3 days ago
Comment by bdubaut 3 days ago
Comment by andy_ppp 3 days ago
Comment by sfink 3 days ago
but note line 111:
> This section describes what to do if you're in a Jujutsu (jj) repository. If the user is not using jj, good luck and try your best.
(The whole skill kind of assumes jj. I think you'd need to make a git version if you actually wanted to use it.)
Comment by bmitc 3 days ago
Comment by lovetocode 2 days ago
Comment by sarthak-ag 3 days ago
Comment by slaye 3 days ago
Comment by ligarota 3 days ago
Comment by pzmarzly 3 days ago
Comment by cassidoo 3 days ago
Comment by ln809 3 days ago
Comment by smb06 3 days ago
Comment by ymir_e 3 days ago
Happy to see something in the right direction. I think they've woken up a bit. Still surprising how slow things can move at big companies.
Companies like Linear, Vercel, Zed and Cursor all seem to be looking at GitHub more aggressively though. I do suspect there will be more competition shortly.
Comment by threethirtytwo 3 days ago
Comment by zxspectrum1982 3 days ago
The case where I need stacked PRs is when I have a ton of changes and I want to upstream them. I have so many changes that I have probably written code in this order: 1. feature1 work 2. feature2 work 3. architecture rework 4. docs 5. feature3 work 6. optimization 7. docs 8. feature4 work 9. security fixes 10. optimization 11. docs 12. last pass security fixes
By the time I want to upstream, I probably want to reorder my commits and generate on PR per theme (arch, feature1 + docs + optimization, feature2+docs + optimization, etc) before I submit a bunch of PRs.
GitHub stacked PRs solve none of my problems. Stacked PRs doesn't take care of the reordering of commits, it doesn't take care of rebasing changes, it adds very little on top of what I was already able to do by saying "this is PR 1 out of 7, this is PR2 out of 7 and build on top of the branch that I used for PR1/7, etc".
Hugely disappointing, bordering useless.
Comment by IshKebab 3 days ago
That's literally all it's supposed to do. Make that dev flow less awful so you don't have to say "by the way this PR depends on #123, I will change the target branch when that is merged" and nonsense like that.
Comment by zxspectrum1982 3 days ago
Comment by calumcl 3 days ago
Comment by IshKebab 3 days ago
Comment by qihqi 3 days ago
Comment by miovoid 3 days ago
Comment by _--__--__ 3 days ago
Comment by hmokiguess 3 days ago
Comment by sitzkrieg 3 days ago
Comment by ben8bit 3 days ago
Comment by Chyzwar 3 days ago
Comment by OJFord 3 days ago
...but if the end result is more popularity of 'stacked' logical changes, yay anyway?
Comment by DmitryO 3 days ago
Comment by RomanPushkin 3 days ago
Comment by piyushsingariya 3 days ago
Comment by cyanregiment 3 days ago
I do it all the time.
It’s just merging branches.
Comment by calmbonsai 3 days ago
Fix. Your. Culture.
Comment by SEJeff 3 days ago
Comment by SEJeff 16 hours ago
Comment by thenewguy077 3 days ago
Comment by sharpvik 3 days ago
Comment by cabyambo 3 days ago
Comment by feiz45607 3 days ago
Comment by fenestella 3 days ago
Comment by bogota 3 days ago