Hacker News new | ask | show | jobs
by MrJohz 497 days ago
As others have pointed out there's `jj undo` and other tools, but they all rely on the fact that JJ is less mutable than it seems.

Internally, JJ is still backed by an append-only tree of commits. You don't normally get to see these commits directly, but they're there. A change (i.e. the thing you see in `jj log`) is always backed by one or more commits. You can see the latest commit in the log directly (the ID on the left is the change ID, the ID on the right is the commit ID), but you can also look back in history for a single change using `jj evolog`, and you can see all commits using `jj op log`.

This ensures that even if you were to exclusively use `jj edit`, never made a new commit, and kept all your work and history in a single change, you could still track the history of your project (or the "evolution", hence the name evolog). It would be kind of impractical, but it would work.

The only caveat here is that, by default, JJ only creates new snapshots/commits from the working directory whenever you run the CLI. So if you made a large change, didn't run any JJ command at all, then made a second large change, JJ would by default see that as a single change to the working directory. To catch these issues, you can use a file watcher to automatically run JJ whenever any file changes, which typically means that JJ makes much more frequent snapshots and therefore you're less likely to lose work (at the cost of having a file watcher running, and also potentially bloating your repository with lots of tiny snapshots).

Note also that the above is all local. When using the git backend, Jujutsu will only sync one commit for each change when pushing to a remote repository, so the people you're collaborating with will not see all these minor edits and changes, they'll only see the finished, edited history that you've built. But locally, all of those intermediate snapshots exist, which is why Jujutsu should never lose your data.

2 comments

> you can use a file watcher to automatically run JJ whenever any file changes, which typically means that JJ makes much more frequent snapshots and therefore you're less likely to lose work (at the cost of having a file watcher running, and also potentially bloating your repository with lots of tiny snapshots).

For example? Or should I create my own in C using inotify/kqueue? Is there a library for jj?

See the documentation here: https://jj-vcs.github.io/jj/latest/config/#filesystem-monito...

The default behaviour (i.e. `core.fsmonitor = "watchman"`) is to only use the file watcher as an optimisation — rather than scanning the entire folder every time JJ wants to make a snapshot, the watch keeps a list of which files have changed, and then when creating a snapshot, JJ only needs to check those files.

However, you can also add `core.watchman.register_snapshot_trigger = true` to the configuration, and this will make it so that every time the watcher sees that a file has changed, it automatically makes the new snapshot.

That said, neither of these are active by default, and neither are necessary by default. But if you're the sort of person who uses VS Code's "Timeline" view to see exactly how each file you've worked with has changed over time, then you might also appreciate the automatic snapshotting feature.

It’s a simple config flag.
The first time I’ve tried to prepare a set of commits to push out I found out the hard way that merges cannot be undone - and I’m not sure which of the commands were doing a merge.
Merges can be undone. Either you can manually remediate by `jj abandon`ing the merge commit so that it's not visible anymore, or you can restore the entire repo state to a previous point in time with `jj undo` or `jj op restore`, or you can do some remediation in between those two extremes.

Off of the top of my head, `jj new` and occasionally `jj rebase` can create merge commits; I don't recall any others.

You can always undo the most recent action using `jj undo`. To undo older actions, the easiest solution is to look for the state you want to get back to in the operations log `jj op log`, and then restore that state directly using `jj op restore <hash of state>`.

You really can undo every action in Jujutsu (and if you can't, that's a bug), but the `undo` mechanism can be a bit surprising - it doesn't behave like a stack, where undoing multiple times will take you further back in history. Instead, undo always undoes the most recent action, and if the most recent action is an undo, then it undoes the undo. This often catches people off-guard - in future versions, JJ will show a warning when this happens, and in even further future versions, there's a plan to make undo behave more like expected.

But if you use `jj op log` and `jj op restore`, you can always get back to any previous state, including undoing merges and other complicated changes.

Thanks, that makes sense. The cheat sheets either didn’t contain the op log-reflog analog or I missed it.

For the record I’ve seen ‘cannot undo a merge’ after jj undo 3-4 times, can’t remember now. I was trying to squash a change into a single commit for a GitHub pr for the first time and couldn’t figure out how to map jj commits into something acceptable, then decided to undo the whole thing and actually managed to overwrite some of my changes in a way I couldn’t find them, fortunately only a few lines of boilerplate.