Happy to see vc-jj.el mentioned! We just made an organization for it on codeberg and will work on getting it into gnu elpa next. It’s not feature-complete yet, but happy to get feature requests etc, https://codeberg.org/emacs-jj-vc/vc-jj.el
I was talking about what I’d need in an editor plugin: give me the magit collapsible diff UI, plus two or three shortcuts to common operations (like new, describe or commit), and I’ll be happy!
gg is not as rich as magit, and of course isn’t integrated into the editor. But it demonstrates the power of the simpler model of jj, because it’s like 70% of what you need even though it doesn’t have a ton of functions.
It could use better docs/tutorials, because it can do some very useful things that are not very discoverable (basically, drag and drop is pretty magical). If it had a jj split view it would be in a good spot — almost no need for the CLI anymore.
I used to do a lot in GitX and gg is almost to that point now.
gg looks nice, although it hasn’t been updated in a few months now, so it’s a bit behind the latest jj releases. But it doesn’t really fit the magit use case; I’m sure there’s a public for these standalone GUIs, similar to GitKraken and others for git, but they’re not for me, I really need something integrated into my editor.
I’ve been having similar feelings, while git feels a bit like a bloated mess, as a Magit (/gitu) user I have not really seen where it solves a significant problem.
I also like the same workflow of making a bunch of changes, then coalescing them into commits. I actually think the “decide on a change, then implement it” flow is nicer, almost Pomodoro-esque, but it’s not how I work in practice.
Otherwise I have years of accumulated git fixing experience that doesn’t help me, and commit signing is painfully slow which isn’t great for jj’s constant committing.
I do hope we get some progress in the space, Pijul seemed promising, I just don’t see the value for me personally at this point.
Otherwise I have years of accumulated git fixing experience that doesn’t help me, and commit signing is painfully slow which isn’t great for jj’s constant committing.
I’ve been using git practically since it was initially released, I have 4 digit github user id. I’m on my 3rd or 4th attempt to switch to JJ. Breaking habits that are so old is really painful. Also there’s bunch of nice things that JJ could have but still doesn’t, and one can tell right away that the project is still early. Still, I hope it will be worth it…
In git managing a lot of commits is just too inconvenient, and despite all the deficiencies a lot of people (me included) can immediately see the potential of the whole philosophy.
commit signing is painfully slow
With git I use gpg on yubikey, so I need to touch the yubikey for every signature (paranoia hurts), and I had to just disable it in JJ, because it’s unworkable.
I hope eventually JJ will have ability to sign only when switching away from a change and/or when pushing changes. Similarly, I’m missing git pre-commit hooks. I hope soon JJ will have a hook system optimized for that flow.
I also really, really miss the git rebase -i.
Pijul seemed promising
Pijul seems great in theory, but JJ wins by being (at least initially) fully compatible with Git. One can’t ignore network effects as strong as Git has at this point.
Same here, but with a single unlock. I’ve been experimenting with signing through SSH on Yubikey instead, which seems to be somewhat faster. I guess GPG is also just waiting to get replaced by something that isn’t as user-hostile. I get a pit in my stomach every time I have to fix anything related to it.
One can’t ignore network effects as strong as Git has at this point.
This actually reminds me, I really like the fact that branches aren’t named, but in reality we’re all pushing to GitHub, which means you need to name your branches after all, and JJ even adds the extra step of moving your branch/bookmark before every push, which I thought was a bit of a drag.
JJ even adds the extra step of moving your branch/bookmark before every push, which I thought was a bit of a drag.
People are discussion big ideas with “topics” that would bring some of the auto-forwarding functionality of branches back. In the meantime, I found making a few aliases is perfectly fine. This one in particular is great:
It finds the closest ancestor with a bookmark and moves it to the parent of your working-copy commit. For me, pushing a single branch is usually jj tug ; jj p
I also have a more advanced alias that creates a new commit and places it at the tip of an arbitrary bookmark in a single step. This is great in combination with the megamerge workflow and stacked PRs:
cob = ["util", "exec", "--", "bash", "-c", """
#!/usr/bin/env bash
set -euo pipefail
# usage: jj cob BOOKMARK_NAME [COMMIT_ARGS...]
if test -z ${1+x}
then
echo "You need to specify a bookmark onto which to place the commit!"
exit 1
fi
target_bookmark="$1" ; shift
jj commit "$@"
change_id="$(jj --ignore-working-copy log --revisions @- --no-graph --template change_id)"
jj --ignore-working-copy rebase --revisions "$change_id" --insert-after "$target_bookmark"
jj --ignore-working-copy bookmark move "$target_bookmark" --to "$change_id"
""", ""]
I’ve been experimenting with signing through SSH on Yubikey instead
I have not looked into it. Does it work? I would definitely consider. Just not having to touch gpg is always a plus.
It generally does, and seems well enough supported (mainly GitHub). It does require registering the key as an allowed signing key in a separate file in ~/.ssh, but I can live with that I guess.
Note that you can still use git rebase -i in a colocated repo. Make sure to add the --colocated flag to jj git clone and jj git init. All my repos are always colocated, it makes all the git tooling work out-of-the-box.
The next time you run jj after a git rebase, it will import those changes from the git repo, so everything just works. With one big exception: jj will not be able to correlate the old commit hashes with the new ones, so you lose the evolog of every commit that changed its hash. But then again, git doesn’t have an evolog in the first place, so you’re not losing anything compared to the baseline.
It could be a fun side-project to add the git-like rebase UI to jj. A standalone binary that opens your editor with the same git rebase todo list, parses its content and submits equivalent jj rebase commands instead of letting git do it.
It could be a fun side-project to add the git-like rebase UI to jj. A standalone binary that opens your editor with the same git rebase todo list, parses its content and submits equivalent jj rebase commands instead of letting git do it.
Any particular reason you suggest a separate tool, rather than something to contribute to jj upstream? I also wouldn’t mind a convenient tool to reorder changes, and I would rather have it integrated in jj rebase directly. (This could also be a TUI instead, whatever.)
There are other interactive modes that git support, for example the usual -p workflows with a basic TUI to approve/reject patches in the terminal (as an alternative to jj’s split interface relying on a 2-diff tool), which I wouldn’t mind seeing supported in jj as well. (I don’t think it’s a matter of keeping the builtin feature set minimalistic, given that the tool already embeds a builtin pager, etc.)
Any particular reason you suggest a separate tool, rather than something to contribute to jj upstream? I also wouldn’t mind a convenient tool to reorder changes, and I would rather have it integrated in jj rebase directly. (This could also be a TUI instead, whatever.)
I think nobody has yet invented a text-based interface for general graph editing:
For example: It’s not obvious how to intuitively represent divergent branches in the git rebase -i interface.
Ideally, there would be a simple text-oriented way to express the topology (via indentation, maybe?), rather than relying on label/reset commands in git rebase -i.
(I don’t think git rebase -i can currently initiate edits which would affect multiple branches (with no common descendant), so you incidentally don’t encounter this situation that often in practice.)
For example: The “mega-merge” workflow, which involves continually rewriting a set of commits and re-merging them, seems particularly painful in the git rebase -i interface.
A non-text-based TUI might work (perhaps based on GitUp’s control scheme?), but nobody has implemented that, either.
There are other interactive modes that git support, for example the usual -p workflows with a basic TUI to approve/reject patches in the terminal (as an alternative to jj’s split interface relying on a 2-diff tool), which I wouldn’t mind seeing supported in jj as well.
A naive idea for a TUI would be to reuse the current terminal-intended visualization approach of jj log, or git log --oneline --graph: they show one change per line, with an ascii-art rendering of the commit placement on the left to visualize the position in the commit graph. In the TUI we could move the cursor to any commit and use simple commands to move them “up” or “down” in their own linear history (the default case), and other commands to move them to another branch that is displayed in parallel to the current branch (or maybe to another parent or child of the current node). Of course, this visualization allows other operations than commit displacement, arbitrary interactive-rebase style operations could be performed, or maybe just prepared, on this view.
You should already be able to do this with jj’s :builtin TUI
Woah, thanks! Turns out I read the doc before trying jj split, and I dutifully followed the recommendation to go with meld from the start, so I never got to try this.
Replying to myself: it looks like jjui offers a workflow similar to the text-based graph editing I described above, see their demonstration video for Rebase.
(I don’t think it’s a matter of keeping the builtin feature set minimalistic, given that the tool already embeds a builtin pager, etc.)
I do think it would bloat the UI. And I have a hunch that the maintainers would see it the same way, but do feel free to open a feature request! It’s always good to talk these things through.
My opinion is that the rebase todo list workflow is not very good and doesn’t fit with the way jj does things. When you edit the todo file, you are still making several distinct operations (reorder, squash, drop, reword etc.). In jj those map to a single command each. By just using the CLI, you can always confirm that what happens is what you expected. If it isn’t you can easily jj undo that single step. With the todo file, you just hope for the best and have to start all over if something didn’t go well. The todo file also is not a great graphical representation of your commit tree. In git, it’s realy optimized for a single branch. You can configure git so interactive rebase can be used in the context of a mega-merge-like situation… but the todo file will become very ugly and difficult to manage. On the other hand, the output of jj log is great! So I think offering the todo-file approach in jj would be inconsistent UI in the sense that it discourages workflows that other parts of the UI intentionally encourage.
Regarding the comparison with the pager, I don’t think the maintainers are too concerned about binary size or number of dependencies, but rather having a consistent UI. A pager doesn’t really intrude on that.
When you edit the todo file, you are still making several distinct operations (reorder, squash, drop, reword etc.). In jj those map to a single command each. By just using the CLI, you can always confirm that what happens is what you expected. If it isn’t you can easily jj undo that single step.
I find this argument very unconvincing. When I operate on a patchset that I am preparing for external review, I have a global view of the patchset, and it is common to think of changes that affect several changes in the set at once. Reordering a line of commits, for example (let’s forget about squash,drop,reword for this discussion), is best viewed as a global operation: instead of A-B-C-D I want to have C-B-A-D. The cli forces me to sequentialize this multi-change operation into a sequence of operations on individual changes, and doing this (1) is unnatural, and (2) introduces needless choices. Exercise time: can you easily describe a series of jj rebase command to do this transformation on commits in that order?
The todo file also is not a great graphical representation of your commit tree.
I agree! But the command-line is even worse as it is no graphical representation at all. It would be nice to have a TUI or a keyboard-driven GUI that is good at displaying trees when we do more complex things, but the linear view of an edit buffer is still better than the no-view-at-all of the CLI when I want to operate on groups of changes as a whole.
Exercise time: can you easily describe a series of jj rebase command to do this transformation on commits in that order?
Yeah, that’s not hard with jj.
jj rebase -r C -B A # insert C between A and its parent(s)
jj rebase -r B -B A # insert B between A and its parent, which is now C
And I would still insist that in a realistic scenario, these commits have semantic meaning so there are naturally going to be thoughts like “X should be before Y” which trivially translates to jj rebase -r X -B Y.
To make it clear though, I’m not saying your perspective is wrong. Just that I don’t think this workflow would be a good addition upstream. I’d be very happy if there was an external tool that implemented this workflow for you and I don’t think the experience would be any worse than as a built-in option (apart from the on-time install step I guess.)
But the command-line is even worse as it is no graphical representation at all.
What do you mean it’s not graphical? Have you seen the output of jj log? For example:
The cli forces me to sequentialize this multi-change operation into a sequence of operations on individual changes, and doing this (1) is unnatural, and (2) introduces needless choices.
I hear what you’re saying, and I think it’s kinda funny: from a different perspective, git rebase forces you into a serial sequence of operations, whereas jj rebase never does. Doesn’t mean you’re wrong, of course, it just took me a moment to grok what you meant, given that I usually view it as the opposite!
(Another pain point with the CBAD thing is that last time i had to do this, it introduced a lot of conflicts thanks to the intermediate state being, well, not what i wanted, and so seeing all that red was stressful. they disappeared after moving another commit around, but in the moment, i was not psyched about it)
Note that you can still use git rebase -i in a colocated repo. Make sure to add the –colocated flag to jj git clone and jj git init. All my repos are always colocated, it makes all the git tooling work out-of-the-box.
Oh, that’s good know. Generally, I am afraid to do anything with git directly after enabling jj in a given repo. I’m afraid of confusing myself, and I’m afraid of confusing the tooling.
It could be a fun side-project to add the git-like rebase UI to jj. A standalone binary that opens your editor with the same git rebase todo list, parses its content and submits equivalent jj rebase commands instead of letting git do it.
I’m looking forward for it to be built-in, at least eventually. git has it. And jj already opens commit message editor on jj desc, so it’s not some new type of UI.
Can you describe what you’re doing with interactive rebases that you can’t do (or can’t do as efficiently) with JJ? Is it specifically this interface to rebasing commits that you’re missing, or a particular feature that only works with git rebase -i?
Just the interface. Editing lines in a text editor is a perfect blend of (T)UI and CLI. Just being able to reorder commits would be great. With squash/fixup, that’s 99.9% of my usage of git rebase -i.
I have not really seen where it solves a significant problem.
The main problem I encounter that it could solve is when I talk to someone who doesn’t already know git and have to kinda sheepishly say “welllll, yeah you can get the code you want with this one tool, but it suuuuuuucks; it’s so bad, I must apologize on behalf of all programmers everywhere except Richard Hipp”
I’m fully aware that I’m just Stockholm-syndromed to git. Having tried to explain how to use git to someone myself, I completely agree that it’s incredibly opaque and inconsistent. I do think that a lot of that only surfaces once you use git in non-trivial ways, clone-edit-stage-commit-push might not be optimal, but it’s fine.
For casual users I feel like the biggest overall usability win would be if GitHub could find a way to let you contribute to a repository without having to fork it.
For casual users I feel like the biggest overall usability win would be if GitHub could find a way to let you contribute to a repository without having to fork it.
This is one of the reasons that as a serial drive-by contributor, I much prefer projects hosted on Codeberg (or random Forgejo instances, perhaps even SourceHut, though I’m not a fan of the email based workflow): I can submit PRs without forking.
After your comment I actually went back and signed into Codeberg, but I’m not finding how you’re supposed to PR without forking. Even their documentation talks about the fork-based workflow. Am I missing something?
It is the AGit workflow that lets you do this. It’s not advertised, because there’s no UI built around it (yet?), and is less familiar than the fork+PR model. But it’s there, even if slightly hidden.
While I’m in general not a big fan of it, that’s one useful thing about Githubs gh commandline tool: a simple gh repo fork in a clone of the upstream will create a fork and register it as a remote. Now if they only added a way to automatically garbage-collect forks that have no open branches anymore…
That’s still 1-2 commands more, and an additional tool, compared to a well crafted git push.
Of course, I could build a small cron job that iterates over my GH repos, and finds forks that have no open PRs, and are older than a day or so, and nukes them. It can be automated. But with Codeberg, I don’t have to automate anything.
I’m assuming “being screwed” means it was hard to fix the conflict, that sucks, I’m sorry to hear that.
What “first class” means in this conflict is that jj stores the information that the conflict exists as part of the metadata of the commit itself. Git doesn’t really let you keep a conflict around, it detects conflicts and then has you resolve them immediately. jj will happily let a change sit there conflicted for as long as you’d like. Rather than “good at making conflicts not happen in the first place,” which is a separate thing that seems like hasn’t been true for you. I don’t know if and what differences jj has with git in that regard.
I had it again today and managed to work my way through it but not because there’s a good “first aid in case of conflict” documentation or anything. That’s the major issue: the tricks and skills we collectively built up to work with and around git aren’t there for jj yet.
But then while resolving the conflict, gg showed my bookmark to have split into 3 which was mildly surprising to say the least.
Yes, there are expert-level tools that can make Git somewhat pleasant and diminish the added value of jj.
But these tools are only used by a minority of Git users – for example Magit assumes Emacs, and most new people entering programming these days are not using Emacs.
Bringing others up to speed with advanced Git workflows is a pain, and I’m directly affected by the way they use git when we collaborate together.
A tool like jj (or a better git porcelain that would actually get traction) can improve the field for everyone, without relying on extra advanced tools.
Besides, jj is not just a porcelain, it has the idea of conflicts being first-class commit objects which is a net conceptual improvement.
It’s no surprise that expert magit or lazygit users don’t get that many jj benefits for themselves (I guess there still are, in particular around conflicts; but jj is also less pleasant to use in various ways). But maybe they could think of jj as a gift for others.
I have been semi seriously using jj for a couple months (i tried it earlier last year and bounced off pretty hard, so this is my second attempt). I think where I’ve come to with it is that I like it in theory a lot, and the git integration is basically required if I’m collaborating with anybody else, but in practice I find it very difficult to use and often have to drop back into git in order to get something done.
I also recognize that it’s still an early project and I haven’t had as much time to put into learning it as would be ideal, so this shouldn’t be read as a critique of the project in any way. I really hope it continues to grow and gain popularity!
not knowing how to do something in jj and not being able to (or not having the time to) figure out from the docs - I forget the exact exact details but there was some change I made recently where I couldn’t get jj to do what I wanted so I ended up just recloning the repo in a separate directory and making the change with git
i only have jj installed and set up in a handful of repos so I’m constantly context switching which repo I’m in and how to make it work.
The second problem is hypothetically solvable by just switching everywhere but the fact that I don’t understand it and have run into situations like (1) make me nervous.
Edit: Oh actually I remember now–somehow i’d gotten jj into a state where it assigned the same stable id to two different commits and it was very unhappy about that, and I couldn’t figure out how to fix it
If you’re willing to use discord, the discord is very friendly to questions, even beginner ones.
The docs do need work. It’ll get there.
somehow i’d gotten jj into a state where it assigned the same stable id to two different commits and it was very unhappy about that, and I couldn’t figure out how to fix it
I’ve been experimenting with using jj co-located with git; although I’m still getting the hang of jj’s model, having magit-find-file and magit-diff-dwim while I’m editing helps me get the best of both worlds.
Thanks for writing this comparison! I am looking forward to getting a magit-like interface to jj. How well does gg compare?
+1. I’m keen on the idea of jj, but am too comfortable with magit.
I might only need 5-10% of what magit can do: collapseable diff and interactive staging.
Yeah I’ve been running jj split in a separate terminal window but magit staging for n-level splits would be great
[Comment removed by author]
Yes, I’d also settle for that (plus some commands to create a new change when i’m done, and maybe describe them)
I’ve wanted to play around with https://github.com/caldwell/commit-patch?tab=readme-ov-file#commit-patch-bufferel for a while, which abstracts “commit this hunk” using vc-diff and diff-mode.
Maybe that could work with vc-jj.el, easier to write than a whole new UI.
Happy to see vc-jj.el mentioned! We just made an organization for it on codeberg and will work on getting it into gnu elpa next. It’s not feature-complete yet, but happy to get feature requests etc, https://codeberg.org/emacs-jj-vc/vc-jj.el
Your parenthetical wish sounds like either
jj new -m <description>orjj commit -m <description>, I’m not sure which.I was talking about what I’d need in an editor plugin: give me the magit collapsible diff UI, plus two or three shortcuts to common operations (like
new,describeorcommit), and I’ll be happy!gg is not as rich as magit, and of course isn’t integrated into the editor. But it demonstrates the power of the simpler model of jj, because it’s like 70% of what you need even though it doesn’t have a ton of functions.
It could use better docs/tutorials, because it can do some very useful things that are not very discoverable (basically, drag and drop is pretty magical). If it had a
jj splitview it would be in a good spot — almost no need for the CLI anymore.I used to do a lot in GitX and gg is almost to that point now.
gg looks nice, although it hasn’t been updated in a few months now, so it’s a bit behind the latest jj releases. But it doesn’t really fit the magit use case; I’m sure there’s a public for these standalone GUIs, similar to GitKraken and others for git, but they’re not for me, I really need something integrated into my editor.
I’ve been having similar feelings, while git feels a bit like a bloated mess, as a Magit (/gitu) user I have not really seen where it solves a significant problem.
I also like the same workflow of making a bunch of changes, then coalescing them into commits. I actually think the “decide on a change, then implement it” flow is nicer, almost Pomodoro-esque, but it’s not how I work in practice.
Otherwise I have years of accumulated git fixing experience that doesn’t help me, and commit signing is painfully slow which isn’t great for jj’s constant committing.
I do hope we get some progress in the space, Pijul seemed promising, I just don’t see the value for me personally at this point.
I’ve been using git practically since it was initially released, I have 4 digit github user id. I’m on my 3rd or 4th attempt to switch to JJ. Breaking habits that are so old is really painful. Also there’s bunch of nice things that JJ could have but still doesn’t, and one can tell right away that the project is still early. Still, I hope it will be worth it…
In git managing a lot of commits is just too inconvenient, and despite all the deficiencies a lot of people (me included) can immediately see the potential of the whole philosophy.
With git I use gpg on yubikey, so I need to touch the yubikey for every signature (paranoia hurts), and I had to just disable it in JJ, because it’s unworkable.
I hope eventually JJ will have ability to sign only when switching away from a change and/or when pushing changes. Similarly, I’m missing git pre-commit hooks. I hope soon JJ will have a hook system optimized for that flow.
I also really, really miss the
git rebase -i.Pijul seems great in theory, but JJ wins by being (at least initially) fully compatible with Git. One can’t ignore network effects as strong as Git has at this point.
Rejoice! This feature was released last week in v0.26.0: https://jj-vcs.github.io/jj/latest/config/#sign-commits-only-on-jj-git-push
That’s awesome! Thanks!
Same here, but with a single unlock. I’ve been experimenting with signing through SSH on Yubikey instead, which seems to be somewhat faster. I guess GPG is also just waiting to get replaced by something that isn’t as user-hostile. I get a pit in my stomach every time I have to fix anything related to it.
This actually reminds me, I really like the fact that branches aren’t named, but in reality we’re all pushing to GitHub, which means you need to name your branches after all, and JJ even adds the extra step of moving your branch/bookmark before every push, which I thought was a bit of a drag.
People are discussion big ideas with “topics” that would bring some of the auto-forwarding functionality of branches back. In the meantime, I found making a few aliases is perfectly fine. This one in particular is great:
It finds the closest ancestor with a bookmark and moves it to the parent of your working-copy commit. For me, pushing a single branch is usually
jj tug ; jj pI also have a more advanced alias that creates a new commit and places it at the tip of an arbitrary bookmark in a single step. This is great in combination with the megamerge workflow and stacked PRs:
Oh, welcome, fellow gpg-sufferer.
I have not looked into it. Does it work? I would definitely consider. Just not having to touch gpg is always a plus.
Same. I’m looking forward to some automatically-moving bookmarks
It generally does, and seems well enough supported (mainly GitHub). It does require registering the key as an allowed signing key in a separate file in
~/.ssh, but I can live with that I guess.I followed https://calebhearth.com/sign-git-with-ssh, and that worked just fine with my key from the Yubikey.
Note that you can still use
git rebase -iin a colocated repo. Make sure to add the--colocatedflag tojj git cloneandjj git init. All my repos are always colocated, it makes all the git tooling work out-of-the-box.The next time you run
jjafter a git rebase, it will import those changes from the git repo, so everything just works. With one big exception: jj will not be able to correlate the old commit hashes with the new ones, so you lose theevologof every commit that changed its hash. But then again, git doesn’t have anevologin the first place, so you’re not losing anything compared to the baseline.It could be a fun side-project to add the git-like rebase UI to jj. A standalone binary that opens your editor with the same git rebase todo list, parses its content and submits equivalent
jj rebasecommands instead of letting git do it.Any particular reason you suggest a separate tool, rather than something to contribute to
jjupstream? I also wouldn’t mind a convenient tool to reorder changes, and I would rather have it integrated injj rebasedirectly. (This could also be a TUI instead, whatever.)There are other interactive modes that
gitsupport, for example the usual-pworkflows with a basic TUI to approve/reject patches in the terminal (as an alternative to jj’ssplitinterface relying on a 2-diff tool), which I wouldn’t mind seeing supported injjas well. (I don’t think it’s a matter of keeping the builtin feature set minimalistic, given that the tool already embeds a builtin pager, etc.)I think nobody has yet invented a text-based interface for general graph editing:
git rebase -iinterface.label/resetcommands ingit rebase -i.git rebase -ican currently initiate edits which would affect multiple branches (with no common descendant), so you incidentally don’t encounter this situation that often in practice.)git rebase -iinterface.A non-text-based TUI might work (perhaps based on GitUp’s control scheme?), but nobody has implemented that, either.
If you’re only relying on approving/rejecting patches (and not e.g. editing hunks), then you should already be able to do this with jj’s
:builtinTUI (see https://jj-vcs.github.io/jj/v0.26.0/config/#editing-diffs).A naive idea for a TUI would be to reuse the current terminal-intended visualization approach of
jj log, orgit log --oneline --graph: they show one change per line, with an ascii-art rendering of the commit placement on the left to visualize the position in the commit graph. In the TUI we could move the cursor to any commit and use simple commands to move them “up” or “down” in their own linear history (the default case), and other commands to move them to another branch that is displayed in parallel to the current branch (or maybe to another parent or child of the current node). Of course, this visualization allows other operations than commit displacement, arbitrary interactive-rebase style operations could be performed, or maybe just prepared, on this view.Woah, thanks! Turns out I read the doc before trying
jj split, and I dutifully followed the recommendation to go withmeldfrom the start, so I never got to try this.Replying to myself: it looks like
jjuioffers a workflow similar to the text-based graph editing I described above, see their demonstration video for Rebase.I do think it would bloat the UI. And I have a hunch that the maintainers would see it the same way, but do feel free to open a feature request! It’s always good to talk these things through.
My opinion is that the rebase todo list workflow is not very good and doesn’t fit with the way jj does things. When you edit the todo file, you are still making several distinct operations (reorder, squash, drop, reword etc.). In jj those map to a single command each. By just using the CLI, you can always confirm that what happens is what you expected. If it isn’t you can easily
jj undothat single step. With the todo file, you just hope for the best and have to start all over if something didn’t go well. The todo file also is not a great graphical representation of your commit tree. In git, it’s realy optimized for a single branch. You can configure git so interactive rebase can be used in the context of a mega-merge-like situation… but the todo file will become very ugly and difficult to manage. On the other hand, the output ofjj logis great! So I think offering the todo-file approach in jj would be inconsistent UI in the sense that it discourages workflows that other parts of the UI intentionally encourage.Regarding the comparison with the pager, I don’t think the maintainers are too concerned about binary size or number of dependencies, but rather having a consistent UI. A pager doesn’t really intrude on that.
I find this argument very unconvincing. When I operate on a patchset that I am preparing for external review, I have a global view of the patchset, and it is common to think of changes that affect several changes in the set at once. Reordering a line of commits, for example (let’s forget about squash,drop,reword for this discussion), is best viewed as a global operation: instead of A-B-C-D I want to have C-B-A-D. The cli forces me to sequentialize this multi-change operation into a sequence of operations on individual changes, and doing this (1) is unnatural, and (2) introduces needless choices. Exercise time: can you easily describe a series of
jj rebasecommand to do this transformation on commits in that order?I agree! But the command-line is even worse as it is no graphical representation at all. It would be nice to have a TUI or a keyboard-driven GUI that is good at displaying trees when we do more complex things, but the linear view of an edit buffer is still better than the no-view-at-all of the CLI when I want to operate on groups of changes as a whole.
Yeah, that’s not hard with jj.
And I would still insist that in a realistic scenario, these commits have semantic meaning so there are naturally going to be thoughts like “X should be before Y” which trivially translates to
jj rebase -r X -B Y.To make it clear though, I’m not saying your perspective is wrong. Just that I don’t think this workflow would be a good addition upstream. I’d be very happy if there was an external tool that implemented this workflow for you and I don’t think the experience would be any worse than as a built-in option (apart from the on-time install step I guess.)
What do you mean it’s not graphical? Have you seen the output of jj log? For example:
I’d say that’s quite graphical. jj even has a templating language that let’s you customize this output in a very powerful and ergonomic way.
You don’t get this visual tree structure in git rebase’s todo file.
I hear what you’re saying, and I think it’s kinda funny: from a different perspective,
git rebaseforces you into a serial sequence of operations, whereasjj rebasenever does. Doesn’t mean you’re wrong, of course, it just took me a moment to grok what you meant, given that I usually view it as the opposite!(Another pain point with the CBAD thing is that last time i had to do this, it introduced a lot of conflicts thanks to the intermediate state being, well, not what i wanted, and so seeing all that red was stressful. they disappeared after moving another commit around, but in the moment, i was not psyched about it)
Oh, that’s good know. Generally, I am afraid to do anything with git directly after enabling jj in a given repo. I’m afraid of confusing myself, and I’m afraid of confusing the tooling.
I’m looking forward for it to be built-in, at least eventually. git has it. And jj already opens commit message editor on
jj desc, so it’s not some new type of UI.Can you describe what you’re doing with interactive rebases that you can’t do (or can’t do as efficiently) with JJ? Is it specifically this interface to rebasing commits that you’re missing, or a particular feature that only works with git rebase -i?
Just the interface. Editing lines in a text editor is a perfect blend of (T)UI and CLI. Just being able to reorder commits would be great. With squash/fixup, that’s 99.9% of my usage of
git rebase -i.TUIs like jjui are really good for that.
The main problem I encounter that it could solve is when I talk to someone who doesn’t already know git and have to kinda sheepishly say “welllll, yeah you can get the code you want with this one tool, but it suuuuuuucks; it’s so bad, I must apologize on behalf of all programmers everywhere except Richard Hipp”
I’m fully aware that I’m just Stockholm-syndromed to git. Having tried to explain how to use git to someone myself, I completely agree that it’s incredibly opaque and inconsistent. I do think that a lot of that only surfaces once you use git in non-trivial ways, clone-edit-stage-commit-push might not be optimal, but it’s fine.
For casual users I feel like the biggest overall usability win would be if GitHub could find a way to let you contribute to a repository without having to fork it.
This is one of the reasons that as a serial drive-by contributor, I much prefer projects hosted on Codeberg (or random Forgejo instances, perhaps even SourceHut, though I’m not a fan of the email based workflow): I can submit PRs without forking.
After your comment I actually went back and signed into Codeberg, but I’m not finding how you’re supposed to PR without forking. Even their documentation talks about the fork-based workflow. Am I missing something?
It is the AGit workflow that lets you do this. It’s not advertised, because there’s no UI built around it (yet?), and is less familiar than the fork+PR model. But it’s there, even if slightly hidden.
While I’m in general not a big fan of it, that’s one useful thing about Githubs
ghcommandline tool: a simplegh repo forkin a clone of the upstream will create a fork and register it as a remote. Now if they only added a way to automatically garbage-collect forks that have no open branches anymore…That’s still 1-2 commands more, and an additional tool, compared to a well crafted
git push.Of course, I could build a small cron job that iterates over my GH repos, and finds forks that have no open PRs, and are older than a day or so, and nukes them. It can be automated. But with Codeberg, I don’t have to automate anything.
Correct. Git is a tool I’d be embarrassed to show a new developer. Jujutsu is one of be proud of.
I at this point have been screwed most of the times that jj ran into a conflict. Not sure how first class it is…
I’m assuming “being screwed” means it was hard to fix the conflict, that sucks, I’m sorry to hear that.
What “first class” means in this conflict is that
jjstores the information that the conflict exists as part of the metadata of the commit itself. Git doesn’t really let you keep a conflict around, it detects conflicts and then has you resolve them immediately.jjwill happily let a change sit there conflicted for as long as you’d like. Rather than “good at making conflicts not happen in the first place,” which is a separate thing that seems like hasn’t been true for you. I don’t know if and what differencesjjhas withgitin that regard.I had it again today and managed to work my way through it but not because there’s a good “first aid in case of conflict” documentation or anything. That’s the major issue: the tricks and skills we collectively built up to work with and around git aren’t there for jj yet.
But then while resolving the conflict, gg showed my bookmark to have split into 3 which was mildly surprising to say the least.
My reasoning:
jj.jj(or a better git porcelain that would actually get traction) can improve the field for everyone, without relying on extra advanced tools.jjis not just a porcelain, it has the idea of conflicts being first-class commit objects which is a net conceptual improvement.It’s no surprise that expert magit or lazygit users don’t get that many
jjbenefits for themselves (I guess there still are, in particular around conflicts; butjjis also less pleasant to use in various ways). But maybe they could think ofjjas a gift for others.I have been semi seriously using jj for a couple months (i tried it earlier last year and bounced off pretty hard, so this is my second attempt). I think where I’ve come to with it is that I like it in theory a lot, and the git integration is basically required if I’m collaborating with anybody else, but in practice I find it very difficult to use and often have to drop back into git in order to get something done.
I also recognize that it’s still an early project and I haven’t had as much time to put into learning it as would be ideal, so this shouldn’t be read as a critique of the project in any way. I really hope it continues to grow and gain popularity!
What are the things that you’re dropping into git for, out of interest?
Two things:
not knowing how to do something in jj and not being able to (or not having the time to) figure out from the docs - I forget the exact exact details but there was some change I made recently where I couldn’t get jj to do what I wanted so I ended up just recloning the repo in a separate directory and making the change with git
i only have jj installed and set up in a handful of repos so I’m constantly context switching which repo I’m in and how to make it work.
The second problem is hypothetically solvable by just switching everywhere but the fact that I don’t understand it and have run into situations like (1) make me nervous.
Edit: Oh actually I remember now–somehow i’d gotten jj into a state where it assigned the same stable id to two different commits and it was very unhappy about that, and I couldn’t figure out how to fix it
If you’re willing to use discord, the discord is very friendly to questions, even beginner ones.
The docs do need work. It’ll get there.
This is called a “divergent change” https://jj-vcs.github.io/jj/latest/FAQ/#how-do-i-deal-with-divergent-changes-after-the-change-id and as the FAQ says, if you only want one of them, abandon the other, and if you want both, duplicate one so it gets a new change id, and then abandon the one with the duplicate change id. Hopefully that can help you for next time!
I have similar experience but with lazygit - it made working with git so pleasant that advantages of jj fell almost insignificant.
I’ve been experimenting with using jj co-located with git; although I’m still getting the hang of jj’s model, having magit-find-file and magit-diff-dwim while I’m editing helps me get the best of both worlds.