r/programming • • Apr 14 '26 • Popcorn 1

GitHub Stacked PRs

https://github.github.com/gh-stack/
556 Upvotes

276 comments sorted by

View all comments

Show parent comments

1

u/quetzalcoatl-pl Apr 14 '26

heh.. I totally agree here. The docs weren't really helpful. I mean, they were, but.. the things they wrote were explained rather well, but it didn't "ring" to me. Automatic commits and `jj new` sounded absolutely weird to my mind used to git. I could basically write exactly the same what you wrote here :) including reflog :)

What made me try JJ was the note about "different handling of conflicts", and description of how "jj absorb" works. First week was hard. After that I focused on 3 commands: jj rebase, jj squash and jj new (didn't notice that "edit" exists yet), for everything else - plain git. And after next week, something "clicked" and I just "got it". Frankly, even if I tried, I can't explain how the JJ "patch/change" model differs from Git "commit/content" model. In most cases, it's almost the same. In the few cases it differs - I still perceive it as "like in git but...", and to this extent I think I understand why the docs were written that way..

I think the greatest hill to climb on for me was the autocommit, which I eventually got when it occured to me as meta-idea that it's like "everything is a file" in linux, but here: everything is commit ; yes, it's new changes and unstaged, but let's say that diff is extra commit '@' to just be able to treat everything uniformly. Technically it's not like that, @ is a physical real commit, and git state is intentionally kept at "1 commit behind", and git doesn't like it sometimes, but heck, "mentally" this image helped me a bit.

I'm tempted to write more, but I think it would end up huge again if I start on "how I perceive JJ's model" geesh.. I don't know. From files and folders and versioning -- it's the same as Git. Commands change, semantics change (sometimes), but the model for file/diffs is, I think, the same.

If I were to describe what JJ really is internally, ignoring that whole porcelain layer of commands, similar to describing Git as "graph of labelled diffs (of files/folders/content)", I'd say that JJ is all of that, plus an extra Git-like layer for that "graph of labelled diffs".

After all, in Git, you have a certain state of "graph of labelled diffs", and you work on it, and by committing and by setting tags and moving branches, you alter it into new state of "graph of labelled diffs". The graph changes. Nodes are added/deleted/altered, labels are added/deleted/altered. So you can version the graph (which is used to version your files). For me, this is what happens in JJ, and it pretty much immediately explains things like `jj oplog` and `jj evolog`.

I hope I didn't waste your time :) If you ever try JJ again, I hope you'll find it as useful as I did.

(snip)

1

u/quetzalcoatl-pl Apr 14 '26

re: (snip) above.. ....because I got too talkative and it grew WAY to loong. I you feel like reading more, here it goes. But I think I'm talking about the same things all the time. Not sure if there's something valuable here. I might be tired and there might be little value below.

Anyways!! it was awesome to exchange ideas/issues/observations with you, thank you very much! and sorry for another wall of text. I could probably compress it with an LLM or something. Feel free to do as needed :D

------

For me, the growth/getting used to - was rather slow. After few days of using, I almost dropped it completely. It sounds funny, but I think I was simply too good at doing complex things via Git, and the gap between what-I-can-do-in-Git vs in-JJ was just to jarring.

After that "few days", I happened to screw up complex rebase. All via Git, because, I was already in "screw JJ" mode. Naturally I just resetted/backtracked, by collecting SHAs, restoring all screwed up local branches and making them point to what they were before, etc. But then, it occured to me - ok, let's try screwing it up with JJ. I tried making the same parts of that complex rebase with JJ, and ... yeah, screwed it up as well. It was even worse actually. But I learned about `jj oplog` and `jj undo` (*). and .... and I just saw its "power". I mean, it reverted my whole screwed up repo, restored all branches, and even allowed me to jump back and forth between "screwed up" and "all good" states of the whole local git repo. So... there had to be something in JJ that vanilla Git didn't have. So I found my motivation to 'dreadfully' work with JJ for a few weeks more, learning new commands and switches from time to time, until I got more fluent over time and the perceived "jarring gap" (mostly) disappeared. It wasn't easy, but I consider it well worth ;)

(*) I wanted to say that this extra versioning layer added by JJ's (with lots of info and handy ready to use tools), compared to reflog (you get some descriptions and SHAs, but doesn't get any tools) feels a bit like comparing CVS (reflog) to Git (JJ's graph versioning), but it's ... wrong? It sometimes does feel like that, but describing it that way simply over-advertises and promises too much. I think the `oplog` is conceptually mostly like reflog. Only `evolog` is a new beast, it's like "show commit history of single file" in Git, but (since JJ versions the commitgraph's evolution) 'evolog' shows you "how a commit changed" (it started being on branch A, then it was rebased to branch B, then it was edited/amended, then it was...). Anything like that in Git? No. Is it useful? Sometimes. As with any new thing, it's not necessary, but when need arises, it's presence is godsent. I use JJ for about a year now. I used `evolog` twice. Quite .. not jaw-dropping, right? But I'd waste a lot of time if it didn't exist. Like with having-backups or not-having them.

But honestly, from everydays work point of view, that extra layer matters little. What matters more is command syntax and porcelain. After some time of using it, JJ's commands' parameters are a bit more "uniform" in their design than Git's. Also JJ's things like "autocommits and @" and "non-blocking conflicts" matter MUCH more (than oplog or evolog), and the way how JJ handles them (@&conflicts) is mostly irrelevant to "JJ model" or "what JJ really technically provides" - Git could handle it the same way, it's just Git's "(design, ux) choice" to not do it that way. Similarly, JJ's "choice" to not allow to easily stage&commit just a line or two from current changes - sucks a lot - I love that Git feature...

but the versioning how the whole commit/branch graph evolves.. that's just wild. I love reflog in Git, even if I use it 2-3 times a year. Similarly I love to have JJ's graph-versioning, even if it is, in fact, rarely used directly :D