6 ms·
I'm trying to understand, would jj's first class conflicts solve the issue of having "stacks" of PRs that can easily be updated at any point in the stack? This
by shmichael 11mo ago
I'm trying to understand, would jj's first class conflicts solve the issue of having "stacks" of PRs that can easily be updated at any point in the stack? This is one of the features most absent from git, but prevalent in Google's tooling as well as Meta's. The only good known solution I know is graphite.dev
- sfink 11mo agoThis is only absent from git because you said "easily". ;-) git can certainly handle doing this, it has more than enough functionality for it. But you're kind of fighting against the grain to do it. Yes, jj very much supports this workflow. It's not a single feature, though: - `jj absorb` automatically guesses what patches in your stack your changes should go to and puts them there, leaving uncertain ones behind. Combine this with `jj undo`, and you can first try an absorb and then immediately undo it if it gets it wrong. - `jj squash --interactive --into X` (aka `jj squash -i -t X`) is the more controlled option, where you can select the specific files/hunks/lines to amend X with. The auto-rebasing then adjusts the rest of the stack to match. If it creates conflicts, you can either undo, fix them now, or fix them later. - if you want to experiment with reordering your stack (or more generally, reorganizing your DAG), you can do so without it making a bigger mess than is absolutely necessary. That's not just because of undo. If you try to rebase a patch too early and it produces tons of conflicts, you can rebase it back and the conflicts will be gone (assuming you didn't have some in the first place, but if you did you'll be back to the same ones). You can try different places within the stack and see what'll work best. - As an expansion of the above, you can also split off pieces of one diff and insert it or squash it anywhere in the stack (eg `jj split --revision X --insert-after Y` aka `jj split -r X -A Y`, or `jj squash --interactive --from X --into Y` aka `jj squash -i -f X -t Y`). You don't need to be "at" X to rip off pieces and put them elsewhere, you can do it anytime. In summary, the full answer is "hell yeah!" Note that this doesn't magically eliminate all problems that arise from collaboration. You can't push your stack somewhere and have other people start working off of it and modifying it while modifying it yourself locally. Or rather, you can, but you'll end up with a mess. Perhaps much less of a mess than eg git, because jj tracks evolving changes and not just commits and so you might be able to have some idea of what's going on once you've pulled the conflicting mutations back into your local repo. But generally speaking, you still have to be disciplined about changing anything that other people can see and possibly depend upon. (jj can help by automatically making such things immutable once you've made them visible to others, but that too can be a bit confusing and require setup specific to your situation.) This comes up a lot in code review, and there are solutions that handle parts of the problem with varying degrees of success, but I've already rambled quite a bit.
- 1718627440 11mo ago> But you're kind of fighting against the grain to do it. > `jj absorb` git absorb exists.
- sfink 11mo agoIt may be unclear since I screwed up the formatting of my post, but that's why I didn't end there. The rest of jj's capabilities change when and how I use it. The absorb command originated in mercurial, which is where I've used it most. With `hg absorb`, I'd only use it when I was fairly sure that it would do the right thing, and I imagine it'd be the same with git. With jj, having `jj undo` as a fallback means I can use it just to see what it does and if it gets something wrong, undo it and do what I want in a different way. (But not that different -- `jj squash -i --into X` means I can do the same thing as it was doing manually.)
- 1718627440 11mo agogit absorb doesn't rewrite anything, it just creates commits you can use with autosquash, so you see what you would change first.
- gpm 11mo agoNot 100% sure I understand what you're saying, but I think the answer is "yes". You can modify any* commit in `jj` regardless of whether it has commits on top of it at any time. Either by another commit into it, or by directly checking out the commit and editing the source tree. If this creates conflicts with commits on top of it `jj` just records those commits as having conflicts/adds conflict markers without interrupting the workflow. * Commits pushed to remotes are marked immutable so you have to pass an extra flag to say ignore that and modify them anyways. Which you generally wouldn't want to do.
- verdverm 11mo agoSo if I push a commit update, and then someone else pushes a commit to one I build on, and there is a conflict... How does recording the conflict, but not introducing it (if I'm understanding correctly), ... how does this affect my build/ci workflow?
- gpm 11mo agoIf I understand you correctly we're imagining you pulled a repo with main at commit A. You added commit B on top of A. Someone else added commit C on top of A to main on the remote, and you're asking what happens? Nothing until you pull and rebase B on top of C (two distinct steps). Once B is on top of C, when B is checked out there will be conflict markers in the source tree that will presumably break your build until you resolve the conflict (unless the conflict is in README or something). My CI workflow has always been on top of a git based forge. As far as the forge is concerned jj is git and absolutely nothing changes with regards to that.
- verdverm 11mo agoA is the remote, B is a coworkers commit, C is mine (iiuc jj uses stacked commits instead of branches) Let's remove the merge conflict and keep the commits in alphabetical order B pushes a breaking change, I push a commit to C without knowing. Are my builds and PRs now at the mercy of changes and events outside of my control? (my hunch is that there are a bunch of confusing situations in jj like git, and that being different enough will cause user churn and people will stick with the tool they already understand the quirks of)
- eddd-ddde 11mo agoWhat you are talking about is solved by jjs auto rebase behaviour. If I amend a commit, all children are rebased automatically.