-
Notifications
You must be signed in to change notification settings - Fork 751
docs: Add Jujutsu for Git experts #7754
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
# Jujutsu for Git experts | ||
|
||
People who are proficient with Git often ask what benefit there is to using | ||
Jujutsu. This page explains the practical advantages for Git experts, with | ||
examples showing how common workflows become easier, safer, or faster with | ||
Jujutsu. | ||
|
||
## Git can be used side-by-side in the same repository | ||
|
||
Jujutsu repositories are colocated by default, so you can use `jj` and `git` | ||
side-by-side. If you find a situation that's easier with Git, run the `git` | ||
command and return to `jj` when you're done. | ||
Comment on lines
+11
to
+12
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: Add "Also please file a feature request" or similar? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we have worries about destructive git commands in this case? I don't want to get too into the weeds right at the start, though... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
Colocation makes migration easier because you can adopt Jujutsu for the | ||
workflows it improves without losing access to the Git commands and tools you | ||
already know. | ||
|
||
## Automatic and safer history editing | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should probably mention the staging area somewhere. I don't know if that would be part of this section or somewhere else. Feel free to just leave a TODO if you agree. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would make it a section right above this one, it's going to be the largest change that someone runs into immediately. |
||
|
||
If you frequently amend, reorder, or squash commits, Jujutsu can often perform | ||
the same operations in fewer commands. | ||
|
||
Suppose you want to amend an older commit and squash it into earlier history. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This sentence sounds a bit redundant to me because "amend an older commit" and "squash into earlier history" sounds like about the same thing. Maybe "Suppose you want to amend some changes in the working copy into an older commit" or something like that? |
||
With Git you might do this in three steps: | ||
|
||
```sh | ||
git add file1 file2 | ||
git commit --fixup abc | ||
git rebase -i --autosquash | ||
``` | ||
|
||
With Jujutsu, you simply squash the changes directly into the commit you want to | ||
amend. All descendants are automatically rebased on top of the amended commit: | ||
|
||
```sh | ||
jj squash --into abc file1 file2 | ||
``` | ||
|
||
## Undo is more powerful than using the reflog | ||
|
||
Git's reflog is powerful, but it's per-ref and can be awkward to use when | ||
multiple refs and operations are involved. | ||
|
||
Jujutsu's operation log records the state of the entire repository: Every change | ||
is an operation you can inspect, and you can restore to any earlier state with | ||
one command. | ||
|
||
Common uses of the operation log: | ||
|
||
- `jj undo` reverts the last operation in one step, without needing to figure | ||
out which ref to reset. You can repeat `jj undo` to continue stepping backwards | ||
in time. | ||
|
||
- `jj op log -p` shows operations with diffs so you can inspect what happened. | ||
|
||
- `--at-operation ID` lets you run commands as if the repository were in a | ||
previous state. | ||
|
||
## The evolution log shows the history of a single change | ||
|
||
The Git reflog shows how refs moved over time, but makes it difficult to see how | ||
a particular commit evolved over time. Jujutsu's evolution log ("evolog") shows | ||
exactly this: Each time a change is rewritten, the update is visible in the | ||
evolog. | ||
|
||
You can use the evolog to find a previous version, then `jj restore` to restore | ||
the complete or partial contents to the current version. | ||
|
||
## Conflict resolution can be deferred | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is a big one that we'll have to iterate on, a lot of people want to see something more concrete here. like they don't get the "well you can just do it later" without more details. I had a good example of this somewhere recently and now I've lost it, ugh... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was an example I read (I don't see it in the docs) that explained how a command could generate a conflict which is then resolved automatically in the next command, which is the best case for deferring. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added one paragraph about the "need to go fix a critical bug" situation, and then a second paragraph for, "I did another rebase and it resolved all the conflicts for me". What do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's somewhat rare that the "rebase again resolves conflicts" is very useful in practice. I'm not sure it's going to convince many. Perhaps it will be more confusing that it's helpful. I wonder if this paragraph should be about the conflict algebra (probably without using that term). If it is, I think I would rank 3 things it provides like this:
My point is that I think deferring conflict resolution is actually less important as a feature. Just a thought; feel free to ignore. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For a new git-minded user this is probably true. But FWIW, in practice I've found that on long-running branches I routinely have conflicts at or near the tip, which I just keep around for weeks or months. These commits typically started as a nontrival change where I decided to go a slightly different direction, by pulling out individual changes into new commits that I put in front of the original one. After a while, the original commit becomes an increasingly-conflicted mess but I keep But anyway, I don't think I would find this story very convincing when I was a git user starting out with jj. It sounds super ugly and it's impossible in git. So it may not belong here. |
||
|
||
Git forces you to resolve conflicts immediately while merging or rebasing is | ||
in progress. Jujutsu lets you defer that work, which is useful when conflicts | ||
are complicated or when you want to switch context to fix something else. | ||
|
||
You can leave a commit in a conflicted state, continue other work, and return | ||
later. This reduces the cost of context switching when resolving a large number | ||
of conflicts. | ||
Comment on lines
+75
to
+77
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An advantage of this is that you can rebase like really old work on top of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do that too. I wonder if that sounds like a benefit, though. I imagine the rebuttal: "If the conflict isn't resolved, you can't use the branch, so why bother even rebasing it?" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I think this is something we can let people discover later. They'll likely even discover it on their own. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I mean having the ability to revive any patch from the past of a codebase is to me a big plus. But your rebuttal is correct though. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I came here to suggest a similar thing; I have a |
||
|
||
Because Jujutsu records the inputs to conflicts, not just conflict markers, it | ||
can sometimes automatically resolve conflicts after a rebase. When performing | ||
several rebases in sequence, some conflicts may be introduced by one and then | ||
later automatically resolved by another, without any manual effort to resolve | ||
the conflicts. | ||
Comment on lines
+79
to
+83
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: this paragraph should reference that this makes Git's rerere functionality obsolete since it is built in |
||
|
||
## `jj absorb` makes it easier to update a patch stack | ||
|
||
When amending several commits in a stack of changes, Git requires you to run | ||
`git commit --fixup <ID>` at least once for each commit before running `git | ||
rebase --autosquash`. | ||
|
||
`jj absorb` is useful when you've made small fixes in the working copy and want | ||
them incorporated into recent commits. It automatically moves each change in the | ||
working copy into the previous commit where that line was changed. | ||
|
||
It doesn't solve all cases: If multiple commits in the stack modified the same | ||
line as was changed in the working copy, it will not move that change. But it | ||
does help the trivial cases, leaving you to decide how to squash the remaining | ||
changes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would skip the colocated jargon and just talk about how they're next to each other.