334 lines
14 KiB
Markdown
334 lines
14 KiB
Markdown
---
|
|
name: jujutsu
|
|
description: Use this skill for any version control operations (commit, log, diff, push, fetch, bookmark, workspace, rebase, undo, etc.). If a `.jj` directory exists, the repo is jujutsu and git mutations will corrupt it — use `jj` for all mutations; read-only `git log/diff/show/blame/grep` are allowed. Covers co-located repos, multi-agent parallel workspaces, and operation-log recovery. **DO NOT IGNORE**
|
|
allowed-tools: Bash(jj *)
|
|
license: Apache-2.0
|
|
metadata:
|
|
author: johnstegeman
|
|
version: "1.3"
|
|
---
|
|
|
|
# Jujutsu (jj) Version Control System
|
|
|
|
This skill helps you work with Jujutsu, a Git-compatible VCS with mutable commits and automatic rebasing.
|
|
|
|
**Tested with jj v0.41.0** - Commands may differ in other versions.
|
|
|
|
For token-sensitive inspection commands, prefer the compact commands in `references/TEMPLATES.md` over jj's default output.
|
|
|
|
The compact commands in `references/TEMPLATES.md` intentionally use `jj --no-pager ...`.
|
|
|
|
For revsets, filesets, and template syntax, see `references/QUERY_LANGUAGES.md`.
|
|
|
|
For sibling or unrelated work that should start from `trunk()`, see `references/NONLINEAR.md`.
|
|
|
|
For common surprises and easy mistakes, see `references/GOTCHAS.md`.
|
|
|
|
<!--
|
|
Attribution and inspiration sources:
|
|
|
|
- Forked from danverbraganza/jujutsu-skill (https://skills.sh/danverbraganza/jujutsu-skill/jujutsu).
|
|
The original scaffolding, references/ structure, and core mental-model wording are from there.
|
|
|
|
- Enforcement language in "Critical: never use git for mutations" was tightened using the
|
|
read-only-git allowlist pattern from knoopx/pi@jujutsu
|
|
(https://skills.sh/knoopx/pi/jujutsu).
|
|
|
|
- "Parallel Workspaces" framing as a tool for multi-agent isolation draws on
|
|
onevcat/skills@onevcat-jj (https://skills.sh/onevcat/skills/onevcat-jj),
|
|
which is explicitly subtitled "Version Control for Agent Workflows".
|
|
|
|
- The .workspaces/ project-local directory convention, the .gitignore safety check,
|
|
and the directory-selection priority documented in references/WORKSPACES.md
|
|
come from edmundmiller/dotfiles using-jj-workspaces
|
|
(https://lobehub.com/skills/edmundmiller-dotfiles-using-jj-workspaces).
|
|
|
|
- The "op log records every mutation; nothing is ever truly lost" framing in the
|
|
Recovery section is adapted from trevors/dot-claude@jj-workflow
|
|
(https://skills.sh/trevors/dot-claude/jj-workflow).
|
|
|
|
- Query-language guidance, nonlinear-work patterns, and workspace handoff /
|
|
monitoring ideas were adapted from joshuadavidthomas/agent-skills `jj`
|
|
(https://github.com/joshuadavidthomas/agent-skills/tree/main/jj) and its
|
|
`workspaces.md`
|
|
(https://raw.githubusercontent.com/joshuadavidthomas/agent-skills/main/jj/workspaces.md),
|
|
while intentionally preserving this skill's local describe-first workflow and
|
|
`.workspaces/` / `workspaces/` directory priority.
|
|
-->
|
|
|
|
|
|
## Detecting a jj repo
|
|
|
|
Check whether a directory is part of a jj repo:
|
|
|
|
```bash
|
|
jj root
|
|
```
|
|
|
|
If it returns a path, the repo is jj-managed. If it returns `Error: There is no jj repo in <directory>`, it isn't. The presence of a `.jj/` folder is another giveaway. If the repo is not a jj one, do not further use this skill.
|
|
|
|
<!-- Enforcement wording (allowed/forbidden split with read-only git allowlist) adapted from knoopx/pi@jujutsu. -->
|
|
## Critical: never use git for mutations in a jj repo
|
|
|
|
In a jj repo (including co-located repos that also have `.git/`):
|
|
|
|
- **Forbidden** (corrupts jj state): `git commit`, `git add`, `git stash`, `git reset`, `git checkout <branch>`, `git switch`, `git rebase`, `git merge`, `git cherry-pick`, `git push`, `git pull`.
|
|
- **Allowed** (read-only): `git log`, `git show`, `git diff`, `git blame`, `git grep`, `git status`. Prefer the `jj` equivalents (`jj log`, `jj show`, `jj diff`, etc.) but read-only git commands won't break anything.
|
|
- **Use jj instead**: `jj git push`, `jj git fetch`, `jj edit <change>` (not `git checkout`), `jj rebase`, `jj new <a> <b>` (for merges).
|
|
|
|
See `references/COLOCATED.md` for the full co-located repo workflow.
|
|
|
|
## Important: Automated/Agent Environment
|
|
|
|
When running as an agent or running on behalf of the user:
|
|
|
|
1. **Always use `-m` flags** to provide commit messages inline rather than relying on editor prompts:
|
|
|
|
```bash
|
|
# Always use -m to avoid editor prompts
|
|
jj desc -m "message" # NOT: jj desc
|
|
jj squash --into @- -m "message" # NOT: jj squash (which opens editor or prompts for hunks)
|
|
```
|
|
|
|
Editor-based commands will fail in non-interactive environments.
|
|
|
|
2. **Verify operations with `jj st`** after mutations (`squash`, `abandon`, `rebase`, `restore`) to confirm the operation succeeded.
|
|
|
|
## Important Principles
|
|
|
|
1. Each commit should represent one logical change. See [commit messages](references/COMMIT_MSG.md) for details on good commit messages. Before starting work on a new change, make sure the working copy is clean (no changes)
|
|
|
|
```bash
|
|
jj st
|
|
```
|
|
|
|
## Core Concepts
|
|
|
|
### The Working Copy is a Commit
|
|
|
|
In jj, your working directory is always a commit (referenced as `@`). Changes are automatically snapshotted when you run any jj command. There is no staging area.
|
|
|
|
There is no need to run `jj commit`.
|
|
|
|
### Commits Are Mutable
|
|
|
|
**CRITICAL**: Unlike git, jj commits can be freely modified. This enables a high-quality commit workflow:
|
|
|
|
1. Before starting work, run `jj st`. If `@` already has changes, run `jj new` first. If `@` is empty, use it as-is.
|
|
2. Describe your intended changes with `jj desc -m "Message"`
|
|
3. Make your changes.
|
|
4. Do NOT run `jj new` when finished — leave that to the next task's step 1.
|
|
|
|
You may refine the commit using `jj squash` or `jj absorb` as needed
|
|
|
|
### Change IDs vs Commit IDs
|
|
|
|
- **Change ID**: A stable identifier (like `tqpwlqmp`) that persists when a commit is rewritten
|
|
- **Commit ID**: A content hash (like `3ccf7581`) that changes when commit content changes
|
|
|
|
Prefer using Change IDs when referencing commits in commands.
|
|
|
|
## Essential Workflow
|
|
|
|
### Starting Work: Describe First, Then Code
|
|
|
|
**Always create your commit message before writing code:**
|
|
|
|
```bash
|
|
# First, describe what you intend to do
|
|
jj desc -m "feat: Add user authentication to login endpoint"
|
|
|
|
# Then make your changes - they automatically become part of this commit
|
|
# ... edit files ...
|
|
|
|
# Check status
|
|
jj st
|
|
```
|
|
|
|
For the full starting-a-change workflow (when to reuse `@` vs `jj new`, anti-patterns, decision logic), see `references/NEW_CHANGE.md`.
|
|
|
|
For unrelated or sibling work that should branch from `trunk()`, see `references/NONLINEAR.md`.
|
|
|
|
### Creating Atomic Commits
|
|
|
|
Each commit should represent ONE logical change.
|
|
|
|
### Viewing History
|
|
|
|
```bash
|
|
# View recent commits
|
|
jj log
|
|
|
|
# View with patches
|
|
jj log -p
|
|
|
|
# View specific commit
|
|
jj show <change-id>
|
|
|
|
# View diff of working copy
|
|
jj diff
|
|
```
|
|
|
|
If you need to run `jj log`, `jj show`, or `jj diff` as an agent, use the matching compact command from `references/TEMPLATES.md` unless the full default output is explicitly needed.
|
|
|
|
For the revsets, filesets, and template syntax behind those compact commands, see `references/QUERY_LANGUAGES.md`.
|
|
|
|
### Moving Between Commits
|
|
|
|
```bash
|
|
# Create a new empty commit on top of current
|
|
jj new
|
|
|
|
# Create new commit with message
|
|
jj new && jj desc -m "Commit message"
|
|
|
|
# Edit an existing commit (working copy becomes that commit)
|
|
jj edit <change-id>
|
|
|
|
# Edit the previous commit
|
|
jj prev -e
|
|
|
|
# Edit the next commit
|
|
jj next -e
|
|
```
|
|
|
|
## Refining Commits
|
|
|
|
If you need to refine a commit (squash, abandon, undo, split, etc), see (Refining commits)[references/REFINE_COMMIT.md]
|
|
|
|
## Working with Bookmarks (Branches)
|
|
|
|
Bookmarks are jj's equivalent to git branches:
|
|
|
|
```bash
|
|
# Create a bookmark at current commit
|
|
jj bookmark create my-feature -r@
|
|
|
|
# Move bookmark to a different commit
|
|
jj bookmark move my-feature --to <change-id>
|
|
|
|
# List bookmarks
|
|
jj bookmark list
|
|
|
|
# Delete a bookmark
|
|
jj bookmark delete my-feature
|
|
```
|
|
|
|
If you need to run `jj bookmark list`, use the matching compact command from `references/TEMPLATES.md`.
|
|
|
|
<!--
|
|
Multi-agent workspace framing inspired by onevcat/skills@onevcat-jj.
|
|
The .workspaces/ project-local convention codified in references/WORKSPACES.md
|
|
is adapted from edmundmiller/dotfiles using-jj-workspaces.
|
|
-->
|
|
## Parallel Workspaces
|
|
|
|
For running multiple agents in parallel against the same repo without working-copy collisions, use `jj workspace`. Each workspace gets its own `@` while sharing the underlying repo store.
|
|
|
|
```bash
|
|
# Quick reference (full convention in references/WORKSPACES.md)
|
|
jj workspace add .workspaces/<repo>-<purpose> # Create
|
|
jj workspace list # List
|
|
jj workspace forget <name> # Untrack (files stay on disk)
|
|
```
|
|
|
|
If you need to run `jj workspace list`, use the matching compact command from `references/TEMPLATES.md`.
|
|
|
|
See `references/WORKSPACES.md` for the full convention: the `.workspaces/` directory layout, `.gitignore` safety check, naming, environment bootstrapping, agent handoff, monitoring, stale-workspace recovery, and merging results from multiple workspaces back together.
|
|
|
|
## Working with tags
|
|
|
|
jujutsu does not yet support tags and pushing them to a remote. If you need to tag (such as for a release), you will need to use git to create and push the tags.
|
|
|
|
## Git Integration (Co-located Repos)
|
|
|
|
Always use co-located repos when working with existing git projects. They give you jj locally while keeping the repo remote-compatible with git tooling.
|
|
|
|
```bash
|
|
jj git clone <url> --colocate # Clone a git repo
|
|
jj git init --colocate # Adopt an existing git repo
|
|
```
|
|
|
|
See `references/COLOCATED.md` for the complete workflow: the mutation rule (`git` is forbidden for mutations, allowed read-only), the git-command allowlist, common gotchas, and switching modes when absolutely necessary.
|
|
|
|
See `references/GOTCHAS.md` when the behavior feels surprising and you want the short list of jj-specific footguns before trying a git-style workaround.
|
|
|
|
### Pushing Changes
|
|
|
|
For pushing bookmarks to a remote, see `references/PUSH.md`. For named remotes, fork+upstream setups, and other multi-remote workflows, see `references/REMOTES.md`.
|
|
|
|
## Handling Conflicts
|
|
|
|
jj treats conflicts as first-class objects — a commit can contain a conflict, and that conflict persists through rebases until resolved. `jj` refuses to push conflicted commits, so they must be resolved before `jj git push`.
|
|
|
|
```bash
|
|
jj st # Reports if @ has unresolved conflicts
|
|
jj resolve --list # Lists conflicted paths
|
|
jj resolve --tool :ours # Take side #1 non-interactively (agent-safe)
|
|
jj resolve --tool :theirs # Take side #2 non-interactively (agent-safe)
|
|
```
|
|
|
|
**Never run bare `jj resolve` (no `--tool`)** — it's interactive and will hang in non-interactive agent environments. Either pass `--tool :ours` / `--tool :theirs`, or edit conflict markers directly in the file and let `jj st` snapshot the resolution.
|
|
|
|
See `references/CONFLICTS.md` for the full resolution playbook: marker formats (diff vs snapshot), five resolution paths, ancestor-level resolution to avoid re-resolving across descendants, verification (beyond `jj st`), and anti-patterns.
|
|
|
|
<!-- Recovery framing ("op log records every mutation; nothing is ever lost") adapted from trevors/dot-claude@jj-workflow. -->
|
|
## Recovery and the Operation Log
|
|
|
|
The op log records every mutation. Nothing is ever lost.
|
|
|
|
```bash
|
|
jj undo # Reverse the last operation (primary recovery tool)
|
|
jj op log # See all operations
|
|
jj op restore <op-id> # Jump back to any past state
|
|
jj evolog -r <change> # See how a specific change evolved
|
|
```
|
|
|
|
If you need to run `jj op log` or `jj evolog`, use the matching compact commands from `references/TEMPLATES.md` first. Add `-p` only after you have narrowed the scope.
|
|
|
|
**Always reach for `jj undo` first** when something looks wrong — it's always correct and safe. See `references/RECOVERY.md` for recovery patterns by scenario (bad squash, accidental abandon, lost work, etc.).
|
|
|
|
## Preserving Commit Quality
|
|
|
|
**IMPORTANT**: Because commits are mutable, always refine them:
|
|
|
|
1. **Review your commit**: `jj show @` or `jj diff`
|
|
2. **Is it atomic?** One logical change per commit
|
|
3. **Is the message clear?** Use imperative verb phrase in sentence case format with no full stop: "Verb object"
|
|
4. **Are there unrelated changes?** Use `jj restore` to move changes out, then create separate commits
|
|
5. **Should changes be elsewhere?** Use `jj squash` or `jj absorb`
|
|
|
|
## Quick Reference
|
|
|
|
| Action | Command |
|
|
|--------|---------|
|
|
| Describe commit | `jj desc -m "message"` |
|
|
| View status | `jj st` |
|
|
| View log | `jj log` |
|
|
| View diff | `jj diff` |
|
|
| New commit | `jj st` then `jj new` only if `@` has changes, then `jj desc -m "message"` |
|
|
| Edit commit | `jj edit <id>` |
|
|
| Squash to parent | `jj squash --into @- -m "message"` |
|
|
| Auto-distribute | `jj absorb` |
|
|
| Abandon commit | `jj abandon <id>` |
|
|
| Undo last operation | `jj undo` |
|
|
| Restore files | `jj restore [paths]` |
|
|
| Create bookmark | `jj bookmark create <name>` |
|
|
| Push bookmark | `jj git push -b <name>` |
|
|
| Add workspace | `jj workspace add .workspaces/<repo>-<purpose>` |
|
|
| List workspaces | `jj workspace list` |
|
|
| Forget workspace | `jj workspace forget <name>` |
|
|
| See operation log | `jj op log` |
|
|
| Jump to past state | `jj op restore <op-id>` |
|
|
| See change evolution | `jj evolog -r <id>` |
|
|
|
|
## Best Practices Summary
|
|
|
|
1. **Describe first**: Set the commit message before coding
|
|
2. **One change per commit**: Keep commits atomic and focused
|
|
3. **Use change IDs**: They're stable across rewrites
|
|
4. **Refine commits**: Leverage mutability for clean history
|
|
5. **Embrace the workflow**: No staging area, no stashing — the op log replaces both
|
|
6. **Workspaces for parallel agents**: Isolate concurrent agent work in `.workspaces/<repo>-<purpose>` (see `references/WORKSPACES.md`)
|
|
7. **`jj undo` first**: When something looks wrong, undo before fixing manually (see `references/RECOVERY.md`)
|