9 ms·
I'm giving jj a try but one aspect of it I dislike is edits to files are automatically committed, so you need to defensively create empty new commits for your c
by tom_alexander 6mo ago
I'm giving jj a try but one aspect of it I dislike is edits to files are automatically committed, so you need to defensively create empty new commits for your changes. As in, want to browse the repo from a commit 2 weeks ago? Well if you just checkout that commit and then edit a file, you've automatically changed that commit in your repo and rebased everything after it on top of your new changes. So instead you create a new branch off of the old commit and add an empty commit to that branch so any file changes don't end up rewriting the past 2 weeks of history. git is much nicer in that I can do whatever I want to the files and it won't change the repo until _I tell it to_.
- smackmybishop 6mo agoJust don't ever use `edit`, use `new` instead; then your changes are tracked without making a mess. I think that's much nicer than juggling stashes in git.
- VMG 6mo ago... unless you actually want to edit a change!
- throawayonthe 6mo agowell, you can do jj new <revision>, make your edit, and then do jj squash which will add the changes to the prev revision i do this for example when i want to see a specific edit highlighted in my editor, it's a nice workflow i think
- Aeolun 6mo agoThis is exactly how someone explained Git to me 12 years ago or so, and I’ve finally wrapped my head around it. Not changing now.
- hacker161 6mo ago[flagged]
- mh- 6mo agoIf I'm understanding the thread correctly, I have a git alias to `git commit --amend --no-edit`, for exactly this workflow. When I'm hacking on something locally and want to just keep amending a commit. I only ever do this if it's HEAD though.
- steveklabnik 6mo agoYes, one way to think about jj in a sort of low-level way is that every jj command does the equivalent of that, every time. (You can also set up watchman and have that happen on every file change...)
- arccy 6mo agostill use new, and then squash your changes in. that way you can actually see what changes you made
- incognito124 6mo agothen you `new` & `squash` :)
- BeetleB 6mo agoI go back and forth between the two approaches, but because of the whole "accidentally made some temporary changes and now it's a pain to separate/undo them because not all changes were temporary", I also usually do a jj new and then jj squash.
- embedding-shape 6mo ago> Just don't ever use `edit`, use `new` instead As a git-ist (?), if I'd ever move away from git, it would be to avoid tooling that has idioms like this (like git too has), if `jj` just gonna surface a bunch of new "bad ideas" (together with what seems like really good ideas), kind of makes it feel like it isn't worth picking up unless you don't already know git.
- surajrmal 6mo agojj edit has good use cases, but it's not the default command you need. For instance, say you were working on some changes but had to change branches for a few minutes to do something. If you didn't manage to create a commit and want to go back to the previous staging area, you would use the jj edit command rather than jj new. It's very intuitive in my experience, something I can't say is true for managing git commits (unless you've spent years forcing it into muscle memory). I never need to run jj help. I run help commands with git all the time.
- dzaima 6mo ago`edit` is still useful; just, for ..editing (!) something, instead of viewing it. If you have some unfinished changes at the tip and want to temporarily checkout something 2 weeks ago, you `jj new` to there (similar to `git stash; git switch whatever`), and then later `jj edit your-old-tip` to go back (equivalent to `git switch main; git stash pop`; I think `jj edit` being an extended replacement for stash-popping things is a reasonable way to think about it). (and if you don't have any uncommitted changes, you always `jj new`) jj also has a concept of immutable commits (defaulting to include tagged commits, and trunk at origin, which it'll disallow editing as a layer of defense)
- saghm 6mo agoThe idiom here is use `edit` if you want to edit a commit, and use `new` if you want to make a new commit. This works identically whether you specify the commit via branch name or commit id. I'm not sure why people are saying not to use `edit` ever. It's basically just a shorthand for staging and amending changes in an existing commit, and there's still a use case for that; it's just not "I want to see the changes on this old branch".
- busfahrer 5mo agoOnce you get your head around it a bit, doing a new in this circumstance will be second nature, since you will have realized that a `new XYZ` in jj leads to the same underlying git state as a `git checkout XYZ` in git
- jdkoeck 6mo agoWow, that’s a total deal breaker to me. Using git may require a complex mental model, but at least it’s not doing anything I didn’t ask for.
- deleted 6mo ago[deleted]
- Diggsey 6mo agoYou would have had to run `jj edit` in order for this to happen, so I think it's a stretch to say you didn't ask for the edit? This is the main difference though: in git files can be `staged`, `unstaged` or `committed`, so at any one time there are 3 entire snapshots of the repo "active". In `jj` there is only one kind of snapshot (a change) and only one is "active" (the current working directory). When you make changes to the working directory you are modifying that "change". As others have mentioned, the equivalent to `git checkout` would be `jj new`, which ensures a new empty change exists above the one you are checking out, so that any changes you make go into that new change rather than affecting the existing one.
- saghm 6mo agoUsing `jj edit` will edit a commit you specify, and `jj new` will make a new empty commit after the one you specify. These work exactly the same whether you specify a commit by branch or by the hash. I'd argue that you're getting exactly what you ask for with these commands, and by comparison, what "checkout" is asking for is much less obvious (and depends on context). We've just internalized the bad behavior of git for so long that it's become normalized.
- csmantle 6mo ago`jj new` works like `git checkout` most by creating an empty revision on the top. `jj edit` on the other hand resembles `git checkout; [edits...]; git add -A; git commit --amend --no-edit`.
- arianvanp 6mo agoYou can disable the auto staging of new files since recently which removed the main grype for me
- tom_alexander 6mo agoooo that will be a nice improvement. So many times I've run `jj status`, then saw a file I wanted gitignored, so I'll edit my gitignore, but the file has already been added to the repo so I have to `mv <file> /tmp/ && jj status && mv /tmp/<file> .` to get the file out of the repo.
- steveklabnik 6mo agoYou can `jj file untrack` instead of that mv bit.
- tom_alexander 6mo agoOh neat, thanks! I (clearly) did not know that command.
- kps 6mo ago[snapshot] auto-track = '~glob:**/*'
- modulared 5mo ago[dead]
- smweber 6mo agojj edit is the biggest jj footgun I can think of, as other comments said just use jj new. But also if you do accidentally edit or change something jj undo works surprisingly well. I found when using jj it worked best for me when I stopped thinking in commits (which jj treats as very cheap “snapshots” of your code) and instead focus on the “changes”. Felt weird for me at first, but I realized when I was rebasing with git that’s how I viewed the logical changes I made anyway, jj just makes it explicit. jj auto-rebasing doesn’t matter until you push changes, and once you do it marks them immutable, preventing you from accidentally rebasing changes that have been shared.
- saghm 6mo ago> jj edit is the biggest jj footgun I can think of Honestly, this is only because `git checkout` is so convoluted that we've collectively changed our expectations around the UX. "checkout" can mean switching to another branch (and creating it if you specify a flag but erroring if you don't), looking at a commit (in which case you have "detached HEAD" and can't actually make changes until you make a branch) or resetting a file to the current state of HEAD (and mercy on your soul if you happen to name a branch the same as one of your files). Instead of having potentially wildly different behavior based on the "type" of the thing you pass to it, `jj edit` only accepts one type: the commit you want to edit. A branch (or "bookmark", as jj seems to call it now) is another way of specifying the commit you want to edit, but it's still saying "edit the commit" and not "edit the bookmark". Unfortunately, the expectation for a lot of people seems to be that "edit" should have the same convoluted behavior as git, and I'm not sure how to bridge that gap without giving up part of what makes jj nice in the first place.
- nightski 6mo agoIt's not "wildly" different behavior based on the thing it's pointing to. In all 3 cases, the command is pointed at a commit and the behavior is the same. Once you know that branches/HEAD are just named pointers to commits, then it becomes obvious you are always just working on commits and branches/ids/HEAD etc are just ways of referencing them.
- Jenk 6mo agoThis is literally jj's schtick and reason for existing, so I wouldn't be surprised if you decide it is not the tool for you.
- tom_alexander 6mo agoYeah, that's a very real possibility. On the bright side, jj is git-compatible so at least the two camps can live together in harmony.
- saghm 6mo agoHow are you "checking out" the old commit? It sounds like you're using `jj edit`, which I'd argue does what it says on the tin. Switch to using `jj new <branch>` and your problem goes away.
- tom_alexander 6mo agoThat avoids the problem for the specific workflow of checking out an old revision (and it was what I was describing with checking out a new branch off the old commit and adding a blank commit to that branch), but another way this design bites me: At work I am constantly jumping around numerous repos because I might be working on repo <foo> but then someone on my team will ask for help with repo <bar>. So I'll turn on screen sharing, open up repo <bar> and I'll type out psuedo-code into <bar> as I'm explaining things to them. So if the last thing I did on <bar> was finish some work by making a new commit, then writing some changes, and then giving it a commit message with `jj desc`, then I am now polluting that commit with the unrelated explanatory psuedo-code. So when switching to a repo I'm not actively working in, I need to defensively remember to check the current `jj status` before typing in any files to make sure I am on an empty commit. With git, I can jump around repos and make explanatory edits willy-nilly, confident that my changes are distinct from real meaningful commits. I guess one way to describe it is: we want to make it easy to make good commits and hard to make bad commits. jj seems to be prioritizing the former to the detriment of the latter. My personality prioritizes rigorous safety / lack of surprises.
- icorbrey 6mo agoFwiw I generally solve this by using `jj commit` instead of `jj desc` unless I'm specifically targeting something that isn't my working copy. Technically it violates the "we want commands to be orthogonal" guideline we use to write Jujutsu (otherwise this would indeed be `jj desc; jj new`) but as a habit it's never let me down
- tom_alexander 6mo agoAh, thanks! That's a command I haven't learned yet, so I'll have to check it out. I learned jj from the tutorial that was posted and I don't think it covered `jj commit` at all.
- et1337 6mo agoJujutsu has a concept of mutable vs immutable commits to solve this. Usually everything in a remote branch is immutable. To work on a branch, I track it and that makes it mutable.
- alunchbox 6mo agoif you loose an edit jj op log is incredible, I've saved a ton of work more-so now with AI's making mistakes. Also workspaces are super fast compared to git worktree's - same concept, different implementation. I agree, that was a bit of an interesting approach but more-so than not it's been better in DX even though you have to 'unlearn' long term it's been a benefit IMO, but a soft one, not something you can measure easily.
- baq 6mo ago> edits to files are automatically committed this is a core feature and it makes jj possible - you're supposed to get used to jj new and jj squash into the previous bookmarked commit, which you map to the git branch head/PR. IOW you're supposed to work on a detached git head and jj makes this easy and pleasant.
- rstuart4133 6mo ago> so you need to defensively create empty new commits for your changes. I thought that for a long while too, and was equally pissed. Then I happened upon `jj evolog`. Turns out jj had a better solution than staging all along - I just didn't realise it existed. The move from using jj as an alternate porcelain to git to using it efficiently took me more months than I care to admit. I suspect being familiar with git cli is actually a handicap in learning jj. New users without pre-conceptions will have a much easier time of it. And oddly, I also suspect they will also end up knowing more about the underlying git storage engine than git users. It turns out it's capable of being used far more effectively than git uses it. Doubly oddly, I blame Linus's familiarity with CVS and SVN for that. He (correctly) bemoaned how unsuited to the job of distributed source code management they were and invented a storage engine that has proved to be remarkably good at the job. But he carried across many the concepts in their CLIs to gits porcelain. Jj (with a lot of help from hg), finally broke free of that legacy.
- simonmic 5mo agoYou can turn that off (I do). In your config file: [snapshot] auto-track = "none()" Auto-tracking could be a great default in certain projects, and a terrible one in others. jj doesn't require it at all and is still awesome without it. Bonus tips: # show help by default, as the subcommands do [ui] default-command = "-h" # more readable log (also affects jjui) [templates] log = 'builtin_log_oneline'