Add rules to not overwrite git/jj history without asking, since this destroys the reviewer's view of things. And some information on dealing with stacks of commits within a single bookmark/PR. Prek can make fixes for whatever caused a failure, and then pass when you run it again, even though the user didn't change anything, and that is now explained. Assisted-by: Opus 5
3.9 KiB
name, description
| name | description |
|---|---|
| Jujutsu (jj) usage | Instructions for using Jujutsu (jj) for version control in the Carbon repository. |
Jujutsu (jj) usage
Jujutsu is a Git-compatible version control system that may be used in Carbon checkouts.
[!IMPORTANT] You can detect if Jujutsu is in use by checking for a
.jjdirectory in the repository root. If present, you must usejjand must not usegit. If absent, you must not usejj.
General usage
Always use the --no-pager flag when invoking jj to prevent the command from
blocking or waiting for terminal paging.
Common commands
Syncing with remote
- Fetch from remote:
jj --no-pager git fetch - Create a new change on top of trunk:
jj --no-pager new trunk - Show repository status:
jj --no-pager status - Show commit history:
jj --no-pager log
Managing changes
- View diff of current changes:
jj --no-pager diff - Commit changes:
jj --no-pager commit- Note: Prefer using
jj commitover the combination ofjj describeandjj new.
- Note: Prefer using
- Abandon/discard current changes:
jj --no-pager abandon - Rebase current change onto trunk:
jj --no-pager rebase -o trunk
Working with a stack of changes
A change is often built as a stack of commits sent up as a single pull request.
The stack is not necessarily based on trunk; it may be based on another change
that is itself still in flight.
[!WARNING] Never rewrite the history of a change that has been submitted as a pull request. Reviewers track a PR by its commits, and squashing, reordering, or abandoning them discards review that is already in progress. This cannot be undone from their side.
Before rewriting history in any other case, propose the exact command and wait for confirmation. This applies to
squash,rebase,abandon, anddescribeon an existing change.
Finding the base of the stack
Bookmarks delimit the stack. List the bookmarks that are ancestors of the working copy, nearest first:
jj --no-pager log -r '::@ & bookmarks()'
Reading the result takes care, because two situations produce similar output:
- Editing an existing change. The nearest bookmark names the change being worked on, and the bookmark below it is the base.
- Starting a new change. The commits above the nearest bookmark have no bookmark of their own yet, so the nearest bookmark is itself the base.
trunk is only ever a base. Finding trunk nearest means new work is being
built on top of it, never that trunk itself is being worked on.
The graph does not distinguish the two cases: an unbookmarked or empty commit above a bookmark may be the next commit of that change or the start of a new one. Ask which it is when it is not clear, and ask before choosing where a fix should land rather than after. Guessing wrong means squashing into a change that may already be under review.
Once the base is known, use it to scope commands to the current stack:
jj --no-pager log -r '<base-bookmark>..@'
Managing the stack
- Fold a fix into an earlier change:
jj --no-pager squash --into <change-id> [path]. Follow-up fixes and formatter reflows belong in the change that introduced the code, not in a trailing "fixes" commit, unless that change has already been submitted. Naming a path squashes only that part of the working copy, leaving unrelated work in place. - Descriptions: only one change in the stack needs a long description, the one used as the pull request description. Every other change gets a short one-line summary. Do not repeat the long text across the stack.