Comment by stouset
2 days ago
Rewriting these for jj users. I'm prefering long option names and full command names for clarity here, but all the commands have shortened aliases and all the option names have single-letter alternatives. `@` means "the current revision", `x+` means "the revision just after `x`", `x-` means "the revision just before `x`".
2. "Accidentally committed something to master that should have been on a brand new branch".
This doesn't really have an analogue. Branches ("bookmarks") only move when you tell them to. If you make a new commit on top of master, it doesn't point master to it, it just lives one past the tip of master. But let's say you accidentally moved master to include the new commit you shouldn't have:
# set master to the previous commit (and reaffirm that
# you're okay moving a bookmark backward)
$ jj bookmark set master --allow-backwards --revision @-
# there is no step two, you're still editing the change you already were
3. Move a commit from one branch to another.
# move the revision one-past-master on to our desired bookmark
$ jj rebase --revision master+ --destination name-of-the-correct-bookmark
# there is also no step two; technically we're not updating the bookmark
# to point to the new commit yet, but this isn't something you'd do as rote
# habit in jujutsu anyway
4. Fuck this noise, I give up:
# list all the operations I've performed against the repo
$ jj op log
# restore to some previous known-good state
$ jj op restore {id}
Bonus content, translated from the article:
> Oh shit, I committed and immediately realized I need to make one small change!
# move the current edits into the previous revision
$ jj squash
> Oh shit, I need to change the message on my last commit!
# re-describe the previous revision
$ jj describe --revision @-
> Oh shit, I tried to run a diff but nothing happened?!
# there is no staging area, all your changes are part of the repo and there is no
# staging area pseudo-commit; please understand that this still works elegantly
# with "patch-add" workflows and does not imply that large change sets can't be
# easily broken up into small commits
> Oh shit, I need to undo a commit from like 5 commits ago!
# find the commit
$ jj log
# back it out
$ jj backout {id}
> Oh shit, I need to undo my changes to a file!
# find the commit
$ jj log
# restore the paths provided to their contents in the given revision
$ jj restore --from {id} [paths...]
And finally there are a few things that are super easy/obvious in jujutsu that are far more annoying in git.
> Oh shit, I committed and many commits later realized I need to make one small change!
# moves the changes in the current working copy into the revision provided
$ jj squash --into {id}
> Oh shit, I committed and many commits later realized I need to make extensive changes!
# sets your working copy to the commit provided; later commits will be
# auto-rebased on top live as you make modifications
$ jj edit {id}
> Oh shit, I need to reorder two commits!
# does what it says on the tin
$ jj rebase --revision {a} --insert-before {b}
> Oh shit, I haven't committed anything in hours but I need something from an interim change from like thirty minutes ago
# look in the "obsolete log" for earlier iterations of the current revision
$ jj obslog
# restore the contents
$ jj restore --from {id} [paths...]
> Oh shit, I made a bunch of changes but want them to be in multiple commits (e.g., patch-add workflow)
# choose the parts to move out; you'll end up with two revisions, one with each half
$ jj split
> Oh shit, I need to break out a change from my current work into a new branch off master
# choose the parts to move out; you'll end up with two revisions, one with each half
$ jj split
# move the stuff I pulled out onto master
$ jj rebase --revision @- --destination master
# optional: name it; most of the time you wouldn't bother
$ jj bookmark create new-name --revision master+
> Oh shit, I need to make three sequential changes but roll them out one-by-one. I also might need to make fixes to previous ones before later ones are rolled out.
# author a new change on top of master and name it a
$ jj new master
…
$ jj bookmark create a
# author a new change on top of a and name it b
$ jj new
…
$ jj bookmark create b
# author a new change on top of b and name it c
$ jj new
…
$ jj bookmark create c
# edit a; nothing else is necessary to ensure b and c remain as descendants of
# revision a
jj edit a
…
# author a new change as part of b; nothing else is necessary to ensure c remains
# up to date on top of b
$ jj new --insert-before c
…
# point c at the new change
$ jj bookmark set b
Please kindly write one for a jj-specific issue: "my build vomitted out a bunch of files and I used any jj command before editing my .gitignore"
I've found myself using git to fix the mess in this particular instance.
Alternatively if you have a bunch of files spewed everywhere with no rhyme or reason which can't be globbed or enumerated reasonably:
One thing I really appreciate is that you can run `jj new master` at _any_ time to drop what you're doing and start a new change. The way jj handles the working copy, conflicts, and visible heads means there's just no need to think about uncommitted changes, unfinished conflict resolution, detached head, etc.. So many things that would get in your way just can't happen.
I haven’t thought about it at all but you’re right. It’s surprising how nice it is that I can enter a repo and `jj new main` without needing to remember any context whatsoever.
My post was a pretty naked attempt to showcase how much less convoluted basic operations are in jj vs. git and hopefully drum up some interest. Hopefully someone bites.
`jj new trunk()` is even better than `jj new main`, I just realized, ha!
1 reply →