Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:24:50 +08:00
commit 532dda1435
18 changed files with 2564 additions and 0 deletions

View File

@@ -0,0 +1,71 @@
{
"name": "jj",
"description": "Autonomous commit stacking and curation workflow for Jujutsu (jj) version control",
"version": "0.2.0",
"author": {
"name": "emiller"
},
"skills": [
"./skills/"
],
"commands": [
"./commands/"
],
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"condition": "args.command matches '^git '",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/git-to-jj-translator.py"
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": "jj fix -s @ 2>/dev/null || true"
}
]
},
{
"matcher": "Bash",
"condition": "args.command matches '(jj (describe|new|commit)|/jj:(commit|new))'",
"hooks": [
{
"type": "command",
"command": "jj fix -s @ && echo '✓ Formatting applied' || echo '⚠️ Formatting failed but continuing'"
}
]
}
],
"UserPromptSubmit": [
{
"hooks": [
{
"type": "prompt",
"prompt": "${CLAUDE_PLUGIN_ROOT}/hooks/user-prompt-commit.py",
"timeout": 30
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "prompt",
"prompt": "${CLAUDE_PLUGIN_ROOT}/hooks/stop-auto-commit.py",
"timeout": 30
}
]
}
]
}
}

3
README.md Normal file
View File

@@ -0,0 +1,3 @@
# jj
Autonomous commit stacking and curation workflow for Jujutsu (jj) version control

82
commands/cleanup.md Normal file
View File

@@ -0,0 +1,82 @@
---
allowed-tools: Bash(jj workspace:*), Bash(jj log:*)
description: Remove empty or stale jj workspaces
model: claude-haiku-4-5
---
## Context
- Available workspaces: !`jj workspace list`
- Current workspace: !`jj workspace list | grep '*'`
## Your Task
Clean up empty or stale jj workspaces.
**What are jj workspaces?**
Jujutsu workspaces allow you to have multiple working copies of your repository simultaneously. Each workspace can work on different revisions independently.
**When to use cleanup:**
- After finishing work in a temporary workspace
- When you have orphaned workspaces from interrupted work
- To reclaim disk space from unused workspaces
- Regular maintenance to keep workspace list clean
**Steps:**
1. **List all workspaces:**
```bash
jj workspace list
```
2. **Check each workspace status:**
For each workspace (except the current one), check if it's empty or stale:
```bash
jj log -r <workspace-name>@ --no-graph -T 'if(empty, "empty", "has_changes")'
```
3. **Remove empty/stale workspaces:**
```bash
jj workspace forget <workspace-name>
```
**Safety notes:**
- Never remove the current workspace (marked with `*`)
- `jj workspace forget` doesn't delete files, it just removes the workspace tracking
- You can always recreate a workspace if needed
- This is a maintenance operation, not a destructive one
**Example workflow:**
```bash
# List workspaces
jj workspace list
# Output:
# default: sqxoqmn 7a9a3c5 (empty) (no description set)
# * feature-work: rlzxqmpv 0c4a1b2 Add login feature
# old-bugfix: xyz123ab (empty) (no description set)
# Remove empty workspaces
jj workspace forget default
jj workspace forget old-bugfix
# Verify
jj workspace list
# Output:
# * feature-work: rlzxqmpv 0c4a1b2 Add login feature
```
**What if I don't have multiple workspaces?**
If you only have one workspace (the default), this command won't do anything. Workspaces are optional - they're useful for:
- Working on multiple features simultaneously
- Code review without switching commits
- Parallel development on different branches
Show final state: !`jj workspace list`

77
commands/commit.md Normal file
View File

@@ -0,0 +1,77 @@
---
allowed-tools: Bash(jj log:*), Bash(jj diff:*), Bash(jj commit:*), Bash(jj describe:*), Bash(jj new:*), Bash(jj status:*), Bash(jj file track:*)
argument-hint: [message]
description: Stack a commit with intelligent message generation
model: claude-haiku-4-5
---
!# Determine workflow state
# Check if current commit has a description
has_description=$(jj log -r @ --no-graph -T 'if(description, "has", "none")')
# Check if current commit is empty
is_empty=$(jj log -r @ --no-graph -T 'if(empty, "empty", "has_changes")')
!# Handle workflow logic
if [ "$is_empty" = "empty" ] && [ "$has_description" = "none" ]; then
# Empty commit with no description - need changes first
echo " **Current commit is empty with no description**"
echo ""
jj log -r @ -T 'concat("Current: ", change_id.short(), " (empty)")' --no-graph
echo ""
echo "💡 **Tip:** Make some changes first, then use \`/jj:commit\` to describe and stack"
exit 0
fi
!# Track any untracked files before committing
jj file track . 2>/dev/null || true
!# Determine action based on user argument
if [ -n "$ARGUMENTS" ]; then
# User provided explicit message - use it directly
if [ "$has_description" = "has" ]; then # Current commit already described, create new on top
echo "📦 **Creating new commit:** $ARGUMENTS"
echo ""
jj new -m "$ARGUMENTS" 2>/dev/null || true
echo "✅ **New commit created, ready for changes**"
else # Describe current commit using jj commit (describes @ and creates new working copy)
echo "📝 **Committing changes:** $ARGUMENTS"
echo ""
jj commit -m "$ARGUMENTS" 2>/dev/null || { # Fallback to describe if no changes
jj describe -m "$ARGUMENTS"
echo "💡 **Tip:** No changes to commit, description updated"
}
echo "✅ **Committed and created new working copy**"
fi
exit 0
fi
## Context
- Status: !`jj status`
- Changes: !`jj diff -r @`
## Task
Create commit for changes above. New files already tracked.
**Workflow:**
- Has "plan:" description → Update with actual work: `jj commit -m "message"`
- Has other description → Stack new commit: `jj new -m "message"`
- Needs description → Commit changes: `jj commit -m "message"`
Use conventional commit (feat/fix/refactor/docs/test/chore), under 72 chars, `-m` flag.
Note: `jj commit` describes @ and creates new working copy in one command.
Result: !`jj log -r @ -T 'concat(change_id.short(), ": ", description)' --no-graph`

90
commands/split.md Normal file
View File

@@ -0,0 +1,90 @@
---
allowed-tools: Bash(jj log:*), Bash(jj diff:*), Bash(jj status:*), Bash(jj new:*), Bash(jj move:*), Bash(jj describe:*), Bash(~/bin/jj-ai-desc.py:*)
argument-hint: <pattern>
description: Split unwanted changes into new child commit with AI description
model: claude-haiku-4-5
---
!# Validate pattern argument
if [ -z "$ARGUMENTS" ]; then
echo "❌ **Error: Pattern required**"
echo ""
echo "**Usage:** \`/jj:split <pattern>\`"
echo ""
echo "**Common patterns:**"
echo "- \`test\` - Test and spec files"
echo "- \`docs\` - Documentation (*.md, README, CHANGELOG)"
echo "- \`config\` - Config files (*.json, *.yaml, *.toml)"
echo "- Custom glob patterns (e.g., \`*.md\`, \`src/**/*.test.ts\`)"
echo ""
echo "**What it does:**"
echo "1. Keeps wanted changes in current commit (@)"
echo "2. Moves unwanted (matching pattern) changes to new child commit"
echo "3. Auto-generates description for child commit"
echo ""
echo "**Example:** \`/jj:split test\` - splits test files into new child commit"
exit 0
fi
## Context
- Current status: !`jj status`
- Current commit: !`jj log -r @ --no-graph -T 'concat(change_id.short(), ": ", description)'`
- Changed files: !`jj diff -r @ --summary`
## Your Task
Split unwanted changes matching pattern "$ARGUMENTS" from current commit (@) into a new child commit with an AI-generated description.
**Pattern Expansion:**
- `test` → Match test files: `*test*.{py,js,ts,jsx,tsx,java,go,rs,cpp,c,h}`, `*spec*.{py,js,ts,jsx,tsx}`, `test_*.py`, `*_test.go`, `*Test.java`
- `docs` → Match documentation: `*.md`, `README*`, `CHANGELOG*`, `LICENSE*`, `docs/**/*`
- `config` → Match config files: `*.json`, `*.yaml`, `*.yml`, `*.toml`, `*.ini`, `*.conf`, `.*.rc`, `.*ignore`
- Custom patterns → Use as-is (glob syntax)
**Workflow:**
1. **Identify matching files** - Show which files in current commit match the pattern
2. **Create child commit** - `jj new @` to create empty child where split changes will go
3. **Move matching changes** - `jj move --from @- -p 'glob:pattern'` to move unwanted files from parent to child
4. **Generate description** - Use `~/bin/jj-ai-desc.py @` to analyze split changes and generate commit message
5. **Show result** - Display final commit structure
**Result structure:**
```
@ (new child): unwanted changes with AI description
@- (original): wanted changes, original description preserved
```
**Important notes:**
- Use multiple `-p` flags for multiple patterns: `jj move --from @- -p 'glob:*.md' -p 'glob:README*'`
- Always quote glob patterns: `'glob:pattern'`
- The original commit description stays intact, only the unwanted changes move
- If no files match, inform user and suggest alternatives
- After moving, the AI will analyze what was split and generate an appropriate description
**Example execution:**
```bash
# Split test files
jj new @
jj move --from @- -p 'glob:**/*test*.py' -p 'glob:**/*_test.py'
~/bin/jj-ai-desc.py @
# Split documentation
jj new @
jj move --from @- -p 'glob:*.md' -p 'glob:README*' -p 'glob:docs/**'
~/bin/jj-ai-desc.py @
# Split config files
jj new @
jj move --from @- -p 'glob:*.json' -p 'glob:*.yaml' -p 'glob:*.toml'
~/bin/jj-ai-desc.py @
```
**Final verification:**
Show the result: !`jj log -r '@|@-' -T 'concat(change_id.short(), ": ", description)'`

78
commands/squash.md Normal file
View File

@@ -0,0 +1,78 @@
---
allowed-tools: Bash(jj log:*), Bash(jj diff:*), Bash(jj status:*), Bash(jj squash:*)
argument-hint: [revision]
description: Merge commits in the stack
model: claude-haiku-4-5
---
## Context
- Current status: !`jj status`
- Current commit: !`jj log -r @ --no-graph -T 'concat(change_id.short(), ": ", description)'`
- Parent commit: !`jj log -r @- --no-graph -T 'concat(change_id.short(), ": ", description)'`
- Recent stack: !`jj log -r 'ancestors(@, 5)' -T 'concat(change_id.short(), ": ", description)' --no-graph`
## Your Task
Merge commits in the jujutsu stack.
**Usage Modes:**
1. **Default (no argument):** Merge current commit (@) into its parent (@-)
```bash
jj squash
```
This moves all changes from @ into @-, then abandons @.
2. **With revision:** Merge a specific revision into its parent
```bash
jj squash -r <revision>
```
Useful for cleaning up a specific commit in the stack.
**When to use:**
- Multiple WIP commits for the same feature
- Cleaning up incremental work before sharing
- Combining related changes into a single commit
- Fixing typos or small changes that belong in the parent
**Workflow:**
1. Explain what will be merged (which commits, what changes)
2. Execute the squash operation
3. Show the result with `jj log` and confirm the changes
**Important:**
- Squashing is safe - you can undo with `jj undo`
- Use `jj squash -i` for interactive mode to select specific changes
- Consider if you should update the description after squashing
**Example scenarios:**
**Scenario 1: Merge current WIP into parent**
```bash
# Before: @ = "WIP: fix tests", @- = "Add login feature"
jj squash
# After: @ = "Add login feature" (now includes test fixes)
```
**Scenario 2: Merge specific revision**
```bash
# Merge revision abc123 into its parent
jj squash -r abc123
```
**Scenario 3: Interactive squash**
```bash
# Choose which changes to move
jj squash -i
```
Show result: !`jj log -r 'ancestors(@, 3)' -T 'concat(change_id.short(), ": ", description)' --no-graph`

101
plugin.lock.json Normal file
View File

@@ -0,0 +1,101 @@
{
"$schema": "internal://schemas/plugin.lock.v1.json",
"pluginId": "gh:edmundmiller/dotfiles:config/claude/plugins/jj",
"normalized": {
"repo": null,
"ref": "refs/tags/v20251128.0",
"commit": "54c661e914119cd65cf44548edcdc0133da91c44",
"treeHash": "2c2e037c0445ee9db0f6d75fa6337f1c41ad6947960548eaa75450e1263d588d",
"generatedAt": "2025-11-28T10:16:43.528724Z",
"toolVersion": "publish_plugins.py@0.2.0"
},
"origin": {
"remote": "git@github.com:zhongweili/42plugin-data.git",
"branch": "master",
"commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390",
"repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data"
},
"manifest": {
"name": "jj",
"description": "Autonomous commit stacking and curation workflow for Jujutsu (jj) version control",
"version": "0.2.0"
},
"content": {
"files": [
{
"path": "README.md",
"sha256": "642e20a76c8a8ecf40e33c74e16f5ae06ee56380ef7c52c52e0e5115b87a722c"
},
{
"path": ".claude-plugin/plugin.json",
"sha256": "03098dac7615d8790430b1b30d7589b9b1a5ac3b36a1385e1a812623836c1b30"
},
{
"path": "commands/split.md",
"sha256": "b302e94ff22d37f3bbcc2a4d5ec36d4b5dde25dde4e5344e6cbcdc198e2c74a9"
},
{
"path": "commands/commit.md",
"sha256": "a51c5522463e0f0f4347f70657e87280938199d5c662007193b7886dbd518520"
},
{
"path": "commands/cleanup.md",
"sha256": "5faad0d678b9ca34dafd8ec2115f48330f1e61040849adcc2e452d1e18684c7f"
},
{
"path": "commands/squash.md",
"sha256": "a6eb8c217d2402d743925901c38e508594cc92a7b70e8632adbf78d098d57a37"
},
{
"path": "skills/jj-workflow/SKILL.md",
"sha256": "3916d94fa3fdbabd8a2e4653465c533666734e2b33d44ef82fcccedfc1c5226a"
},
{
"path": "skills/commit-messages/SKILL.md",
"sha256": "2bc7e6f638aa0669c76e144d5fc2313e8041a52f5a4e0674a84e3df69bf7925a"
},
{
"path": "skills/commit-curation/SKILL.md",
"sha256": "dd93c555db3d86f46215b912840a91b16cf1923f6035fcc0cfb41a4c6332ccc6"
},
{
"path": "skills/jj-operations/restoring-operations.md",
"sha256": "368753ecef5dfc47a4a685f13a8dc76634d8334e708e76ea7ec1bb772791826a"
},
{
"path": "skills/jj-operations/operation-patterns.md",
"sha256": "8db893e5431460062913277be01205ee7d1eb8067935d1007ed7e885550a096f"
},
{
"path": "skills/jj-operations/viewing-operations.md",
"sha256": "d7304350dd44b3033bc4d4eb60895b174170acbc743950caa2cb37092a57d060"
},
{
"path": "skills/jj-operations/time-travel.md",
"sha256": "4dc07e67e14f3ab452502b101a2355d4933c9939e855f914b78e00e266e57798"
},
{
"path": "skills/jj-operations/SKILL.md",
"sha256": "57c5ce5bd6c9becdb0765889878a26a3923d04b7827f04021f87127e4ca3b891"
},
{
"path": "skills/jj-spr/SKILL.md",
"sha256": "e822816cda2e1ac3f67f156ee90ca8c70c619eb714e1fcaacfcdff159843dfdc"
},
{
"path": "skills/jj-undo/SKILL.md",
"sha256": "5273d72dc631bbbffa24338b93fa1f1e4eee1202d9701204290d43a724e03e92"
},
{
"path": "skills/jj-conflicts/SKILL.md",
"sha256": "35987e2e1ffc43e138542c468defecb0c0271da067e77b6e87b4bacc84fd96b9"
}
],
"dirSha256": "2c2e037c0445ee9db0f6d75fa6337f1c41ad6947960548eaa75450e1263d588d"
},
"security": {
"scannedAt": null,
"scannerVersion": null,
"flags": []
}
}

View File

@@ -0,0 +1,111 @@
---
name: Curating Jujutsu Commits
description: Help curate and organize commits in jujutsu repositories. Use when working with multiple commits, WIP changes, or preparing work for sharing. Suggests when to split, squash, or reorganize commits based on change patterns.
allowed-tools: Bash(jj log:*), Bash(jj status:*), Bash(jj diff:*)
---
# Curating Jujutsu Commits
## When to Curate
**Suggest curation:**
- Before sharing work (PR, pushing)
- Commits mix unrelated concerns (tests+code, docs+code, config+code)
- WIP, fixup, or temporary commits present
**Don't suggest when:**
- Changes simple and focused
- Single commit, one concern
- Early exploration phase
## Split Patterns
Use `/jj:split <pattern>` when mixing concerns:
**Tests + implementation:**
```
Your changes include both implementation and tests. Consider:
/jj:split test
```
**Docs + code:**
```
Your changes mix code and documentation. Consider:
/jj:split docs
```
**Config + features:**
```
Your changes include configuration. Consider:
/jj:split config
```
**Common patterns:** `test`, `docs`, `config`, `*.{ext}`, custom globs
## Squash Patterns
Use `/jj:squash` when combining commits:
**Multiple WIP commits:**
```
You have multiple WIP commits for same feature. Consider:
/jj:squash
```
Indicators: "WIP", "wip", "fixup", "temp", "checkpoint" messages
**Fixup commits:**
```
This looks like a fixup for your previous commit. Consider:
/jj:squash
```
Indicators: "fix typo", "fix tests", "fix formatting" messages
**Related small changes:**
```
These commits are closely related. Consider:
/jj:squash
```
Indicators: Same feature/scope, same work session
## Curation Workflow
1. Review stack: `jj log`
2. Split mixed concerns: `/jj:split <pattern>`
3. Squash WIP commits: `/jj:squash`
4. Verify: `jj log`, `jj diff -r <commit>`
5. Update descriptions: `/jj:commit` or `jj describe`
## Avoiding Over-Curation
**Don't suggest when:**
- Single purpose changes (all files work toward one goal)
- Tightly coupled changes (splitting breaks logical cohesion)
- Already atomic (commit focused and clear)
- Early exploration phase
**Good single commits:** "Refactor auth module", "Add user profile page" (template+route+tests), "Fix memory leak" (investigation+fix)
## TodoWrite Integration
One commit per major todo completion. Use `jj new` between todos. Don't suggest splitting if commits already align with todo structure.
## When This Skill Activates
- Multiple commits to organize
- Changes mix file types or concerns
- User mentions preparing for PR/sharing
- WIP or fixup commits present
- User asks about organizing commits
- Before suggesting pushing or creating PRs

View File

@@ -0,0 +1,44 @@
---
name: Generating JJ Commit Messages
description: Generate descriptive commit messages for jujutsu repositories. Use when creating commits, describing changes, or when the user asks for commit message help. Follows conventional commit format and project conventions.
allowed-tools: Bash(jj status:*), Bash(jj diff:*), Bash(jj log:*)
---
# Generating JJ Commit Messages
## Format
**Summary line:** `type(scope): brief description` (under 72 chars)
**Body (optional):** Blank line, then detailed explanation with bullets
**Footer:**
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
```
## Conventional Commit Types
| Type | Use Case | Example |
| ------------ | ------------------ | ------------------------------------------ |
| **feat** | New features | `feat(auth): implement JWT authentication` |
| **fix** | Bug fixes | `fix(login): correct password validation` |
| **refactor** | Code restructuring | `refactor(auth): extract token helper` |
| **docs** | Documentation | `docs(api): update auth examples` |
| **test** | Tests | `test(auth): add login flow tests` |
| **chore** | Maintenance | `chore(deps): upgrade to Python 3.12` |
| **style** | Formatting | `style(auth): format with black` |
| **perf** | Performance | `perf(db): optimize query with index` |
| **ci** | CI/CD | `ci: add automated testing workflow` |
| **build** | Build system | `build(nix): update flake inputs` |
## Quick Guidelines
- Use imperative mood: "Add" not "Added"
- Be specific: "Fix memory leak in parser" not "Fix bug"
- Scope is optional but helpful: `feat(auth): ...` or just `feat: ...`
- Keep summary under 72 characters
- Add body with bullets for complex changes

View File

@@ -0,0 +1,425 @@
---
name: jj-conflicts
description: Help users identify, understand, and resolve conflicts in jj repositories. Use when user mentions 'conflict', 'resolve conflicts', 'merge conflict', 'conflicted commits', '2-sided conflict', or encounters conflict-related errors.
allowed-tools:
- Bash(jj status:*)
- Bash(jj log -r 'conflicts()':*)
- Bash(jj resolve:*)
- Bash(jj restore:*)
- Bash(jj diff:*)
- Bash(jj edit:*)
---
# Jj Conflict Resolution
This skill helps you identify and resolve conflicts in jj repositories, with special emphasis on safely using `jj restore` with path specifications.
## Understanding Jj Conflicts
### How Jj Differs from Git
- **Git**: Conflicts block operations; you must resolve before continuing
- **Jj**: Conflicts are stored in commits; you can continue working and resolve later
When jj encounters a conflict, it:
1. Marks the commit with a conflict indicator (× in `jj log`)
2. Stores conflict markers in the affected files
3. Allows you to continue working on descendants
### Types of Conflicts
**"2-sided conflict"**: Two versions of the same content that can't be automatically merged
**"2-sided conflict including 1 deletion"**: One side deleted a file/content, the other modified it
- Common when adding files to `.gitignore` after they were already tracked
- One of the most frequent conflict scenarios
## Identifying Conflicts
### Find All Conflicted Commits
```bash
jj log -r 'conflicts()'
```
This shows all commits with unresolved conflicts. Look for the × marker.
### Check Current Status
```bash
jj status
```
If you're in a conflicted commit, this will show:
```
Warning: There are unresolved conflicts at these paths:
.obsidian/workspace.json 2-sided conflict including 1 deletion
```
### Inspect Specific Conflict
```bash
jj edit <conflicted-commit-id>
jj diff
```
## Resolution Strategies
### Strategy A: Using jj resolve (Recommended for Most Cases)
The `jj resolve` command is purpose-built for conflict resolution:
```bash
# Navigate to conflicted commit
jj edit <commit-id>
# List all conflicts
jj resolve --list
# Accept parent's version (side 1) - "ours"
jj resolve --tool :ours <path>
# Accept child's version (side 2) - "theirs"
jj resolve --tool :theirs <path>
# Use interactive merge tool (if configured)
jj resolve <path>
```
**When to use:**
- Most conflict scenarios
- When you want semantic clarity (`:ours` vs `:theirs`)
- When working with merge tools
### Strategy B: Using jj restore (Safe When Paths Specified)
The `jj restore` command can restore files from any commit:
```bash
# Navigate to conflicted commit
jj edit <commit-id>
# Restore SPECIFIC path from parent
jj restore --from @- <path>
```
**When to use:**
- Accepting parent's version for specific files
- When you want more control over the source (`--from` can be any revision)
- For deletion conflicts (equivalent to `:ours` in resolve)
### ⚠️ CRITICAL: The Path Argument
This is the **most important safety rule** when using `jj restore`:
```bash
# ❌ DANGEROUS - Restores ALL files from parent
# This will LOSE ALL CHANGES in the current commit!
jj restore --from @-
# ✅ SAFE - Restores ONLY the specified path
# All other changes in the commit are preserved
jj restore --from @- .obsidian/
jj restore --from @- src/config.rs
```
**Why this matters:**
- Without a path argument, `jj restore` operates on ALL files
- With a path argument, it operates ONLY on that specific path
- The difference between preserving your work and losing it entirely
### Strategy C: Manual Editing
For complex conflicts, you can edit the conflict markers directly:
```bash
jj edit <commit-id>
# Edit files with conflict markers
# Remove markers and keep desired content
jj diff # Verify your resolution
```
Conflict markers look like:
```
<<<<<<<
Content from side 1 (parent)
%%%%%%%
Common ancestor content
+++++++
Content from side 2 (child)
>>>>>>>
```
### Strategy D: New Commit Then Squash (Jj's Recommended Pattern)
For complex resolutions, jj recommends creating a resolution commit:
```bash
# Create new commit on top of conflicted one
jj new <conflicted-commit-id>
# Resolve using any method above
jj resolve --tool :ours <path>
# Review the resolution
jj diff
# Squash resolution back into parent
jj squash
```
**Benefits:**
- Separates resolution from original changes
- Easy to review resolution before committing
- Can undo resolution easily
## Common Conflict Scenarios
### Scenario 1: Parent Deleted, Child Modified
**Situation:** Parent commit deleted files (e.g., added to `.gitignore`), but child commits still have changes to those files.
**Example:** You added `.obsidian/` to `.gitignore` and untracked it in commit `oo`, but 13 descendant commits still had `.obsidian/` changes.
**Conflict message:**
```
.obsidian/workspace.json 2-sided conflict including 1 deletion
```
**Resolution:** Accept the deletion by restoring from parent
```bash
# Method 1: Using jj resolve (more semantic)
jj edit <conflicted-commit>
jj resolve --tool :ours .obsidian/
# Method 2: Using jj restore (equally correct)
jj edit <conflicted-commit>
jj restore --from @- .obsidian/
```
**For multiple commits:**
```bash
# Process each conflicted commit
for commit in $(jj log -r 'conflicts()' --no-graph -T 'change_id.short(4)'); do
jj edit "$commit"
jj restore --from @- .obsidian/
done
```
### Scenario 2: Both Sides Modified Same Content
**Situation:** Both parent and child modified the same lines in a file.
**Resolution options:**
1. Accept one side: `jj resolve --tool :ours` or `:theirs`
2. Merge manually: Edit conflict markers
3. Use merge tool: `jj resolve <path>` (if configured)
### Scenario 3: Rename Conflicts
**Situation:** One side renamed a file, the other modified it.
**Resolution:** Choose which version to keep, potentially applying changes from other side manually.
## Key Differences: jj restore vs jj resolve
| Aspect | jj resolve | jj restore --from @- <path> |
| -------------------- | --------------------------------- | ------------------------------------------- |
| **Purpose** | Conflict resolution | Generic file restoration |
| **Semantic clarity** | `:ours`/`:theirs` explicit | Less explicit (must know parent/child) |
| **Merge tools** | Supported | Not supported |
| **Flexibility** | Limited to conflict resolution | Can restore from any revision |
| **Safety** | Only operates on conflicted files | **MUST specify paths** or affects all files |
**Both are correct for accepting deletions, but resolve is more semantically clear.**
## Safety Checklist
Before resolving conflicts:
-**Always specify path arguments** when using `jj restore --from`
-**Use `jj diff` to verify changes** before and after resolution
-**Test resolution** with one commit before batch processing
-**Check `jj status`** to confirm conflict is resolved
-**Never use `jj restore --from @-` without paths** unless you intend to reset entire commit
## Real-World Example: Untracking Previously-Committed Files
This documents a real scenario that illustrates the critical importance of path specification:
### The Situation
1. You added `.obsidian/` to `.gitignore` in commit `oo`
2. You untracked `.obsidian/` files in that commit: `jj file untrack .obsidian/`
3. 13 descendant commits still contained `.obsidian/` changes
4. After rebasing: `jj rebase -r 'oo..@' -d oo`
5. Result: All 13 descendant commits now have conflicts
### The Conflicts
Each conflict shows:
```
.obsidian/workspace.json 2-sided conflict including 1 deletion
```
This means:
- Parent (commit `oo`): Deleted `.obsidian/` files
- Child commits: Still have changes to `.obsidian/` files
### The Wrong Approach (What NOT to Do)
```bash
# ❌ WRONG - This was tried first
jj edit <commit-id>
jj restore --from @- # No path specified!
# Result: ALL files restored from parent
# - All task files: DELETED
- All document changes: LOST
# - Only .obsidian/ should have been affected, but EVERYTHING was reset
```
**Why this failed:** Without a path argument, `jj restore --from @-` restores **every file** from the parent, effectively undoing all changes in the commit.
### The Correct Solution
```bash
# ✅ CORRECT - Specify the path
jj edit <commit-id>
jj restore --from @- .obsidian/ # Path specified!
# Result: Only .obsidian/ restored from parent
# - Task files: PRESERVED ✓
# - Document changes: PRESERVED ✓
# - .obsidian/ conflicts: RESOLVED ✓
```
**Or using jj resolve (more semantic):**
```bash
jj edit <commit-id>
jj resolve --tool :ours .obsidian/
```
### Processing All Conflicts
```bash
# Get list of conflicted commits
jj log -r 'conflicts()'
# Process each one with PATHS SPECIFIED
for commit in oymp zzyv knzl xlxr lutt xznz uvnk zosw vzxv utmq xtsk qvot pqnr; do
echo "Resolving $commit"
jj edit "$commit"
jj restore --from @- .obsidian/ # ← The critical path argument
done
# Verify all conflicts resolved
jj log -r 'conflicts()' # Should return empty
```
### Key Takeaway
The difference between these two commands is **losing all your work** vs **safely resolving conflicts**:
```bash
jj restore --from @- # ← Danger: ALL files
jj restore --from @- .obsidian/ # ← Safe: ONLY specified path
```
**Always specify the path when resolving conflicts with `jj restore`.**
## Quick Reference
### Find conflicts
```bash
jj log -r 'conflicts()'
jj status
```
### Resolve with jj resolve
```bash
jj edit <commit-id>
jj resolve --tool :ours <path> # Accept parent's version
jj resolve --tool :theirs <path> # Accept child's version
```
### Resolve with jj restore (MUST SPECIFY PATH)
```bash
jj edit <commit-id>
jj restore --from @- <path> # Accept parent's version for PATH ONLY
```
### Verify resolution
```bash
jj diff
jj status
jj log -r 'conflicts()' # Should not include current commit
```
## Integration with Other Workflows
### After Rebase
Rebasing often creates conflicts:
```bash
jj rebase -r <commits> -d <destination>
# Check for new conflicts
jj log -r 'conflicts()'
# Resolve as needed
```
### Before Push
Always resolve conflicts before pushing:
```bash
# Check for unresolved conflicts
jj log -r 'conflicts() & mine()'
# If any found, resolve them first
# Then proceed with push
```
### With jj-spr
Conflicts can appear when updating stacked PRs:
```bash
jj rebase -d main
# Resolve any conflicts
jj restore --from @- <conflicted-path>
# Update PRs
jj spr update
```
## When to Use This Skill
Invoke this skill when you encounter:
- "There are unresolved conflicts at these paths"
- × markers in `jj log` output
- "2-sided conflict" messages
- Questions about using `jj restore` safely
- Need to accept parent's or child's version in conflicts
- Rebase operations that create conflicts
- Files that were added to `.gitignore` after being tracked

View File

@@ -0,0 +1,123 @@
---
name: Exploring Operation History in Jujutsu
description: Help users explore operation history and time travel in jj. Use when the user explicitly mentions 'operation log', 'op log', 'jj op', or 'operation history'. Covers jj op log, --at-op flag, op restore, and operation exploration.
allowed-tools: Bash(jj op log:*), Bash(jj op show:*), Bash(jj op restore:*), Bash(jj op diff:*), Bash(jj log --at-op:*), Bash(jj status:*), Bash(jj diff --at-op:*), Read(*/jj-operations/*.md)
---
# Exploring Operation History in Jujutsu
## Overview
**The operation log is your safety net.** Every repository-modifying command is recorded with complete snapshots, allowing full time travel and recovery.
**Key insight:** Each operation contains metadata (timestamp, user, command) plus a snapshot of all commit states, bookmarks, and repository structure.
## When to Use Operation Log
**Use operation log when:**
- ✅ You need to understand what you've been doing
- ✅ You want to find a specific past state
- ✅ You need to recover from complex mistakes
- ✅ You're debugging unexpected repository state
- ✅ You want to see history of changes to a commit
**Don't use operation log when:**
- ❌ You just need to undo the last operation (use `jj undo` from jj-undo skill)
- ❌ You're looking at commit history (use `jj log`)
- ❌ You want to see file changes (use `jj diff`)
## Core Capabilities
### 1. Viewing Operations (Read-Only)
Browse operation history and see what changed.
**Commands:** `jj op log`, `jj op show`, `jj op diff`
**When to use:** You want to understand what operations happened, what they changed, or compare repository states.
📚 **See detailed docs:** `viewing-operations.md`
### 2. Time Travel (Read-Only)
View the repository at any past operation without modifying current state.
**Commands:** `--at-op` flag with `jj log`, `jj status`, `jj diff`, etc.
**When to use:** You want to explore past states, compare with current state, or find the right operation to restore.
📚 **See detailed docs:** `time-travel.md`
### 3. Restoring to Past Operations
Jump the entire repository back to a specific operation state.
**Commands:** `jj op restore <op-id>`
**When to use:** You found the right past state and want to return to it, recovering from complex mistakes.
📚 **See detailed docs:** `restoring-operations.md`
### 4. Common Patterns & References
Operation references (@, @-), common workflows, best practices.
**When to use:** You need quick reference or want to learn common patterns.
📚 **See detailed docs:** `operation-patterns.md`
## Quick Command Reference
### Viewing
```bash
jj op log # Show operation history
jj op show <op-id> # Show operation details
jj op diff --from <a> --to <b> # Compare operations
```
### Time Travel (read-only)
```bash
jj log --at-op=<op-id> # View commit history at operation
jj status --at-op=<op-id> # View working copy at operation
```
### Restoring
```bash
jj op restore <op-id> # Jump to specific operation
jj op restore @- # Go back one operation (= jj undo)
```
## Integration with Undo
**Relationship:** Operation log is the foundation, undo is a convenience.
- `jj undo` = `jj op restore @-` (restore to parent operation)
- `jj undo` twice = `jj op restore @--` (go back 2 operations)
**When to choose each:**
- Quick recent mistake → `jj undo` (see jj-undo skill)
- Need to skip multiple operations → `jj op restore`
- Not sure which operation → Explore with `--at-op`, then restore
## Progressive Disclosure
This skill uses progressive disclosure to manage context efficiently:
1. **Start here** for overview and quick reference
2. **Read detailed docs** when you need specific guidance:
- `viewing-operations.md` - How to browse and understand operation log
- `time-travel.md` - How to explore past states without changing anything
- `restoring-operations.md` - How to restore to past operations and recover
- `operation-patterns.md` - Common patterns, references, and best practices
Claude will automatically load the relevant detailed documentation when helping you with specific operation log tasks.
## Remember
**Operation log is your time machine.** Everything is recorded, everything is explorable, everything is restorable. You can't lose work in jj.

View File

@@ -0,0 +1,264 @@
# Operation Patterns and References
This document covers operation references, common patterns, and best practices for working with the operation log.
## Operation References
### Symbolic References
**Current operation:** `@`
```bash
jj op show @ # Show current operation
```
**Parent operations:** `@-` (immediate parent), `@--` (grandparent)
```bash
jj op show @- # Previous operation
jj op restore @- # Go back one operation (like jj undo)
jj op restore @-- # Go back two operations
jj op restore @---- # Go back 4 operations
```
**Note:** No child operation syntax (`@+`) because operations form a tree, not a line.
### Using References in Commands
```bash
# Show operations
jj op show @ # Current
jj op show @- # Previous
jj op show @-- # Two back
# Restore operations
jj op restore @- # = jj undo
jj op restore @--- # Go back 3 operations
# Compare operations
jj op diff --from @--- --to @
```
## Common Patterns
### Pattern: "What Did I Just Do?"
See recent operations and current operation details:
```bash
jj op log --limit 5 # Recent operations
jj op show @ # Current operation details
```
### Pattern: "Find When Things Broke"
Bisect through time to find when things went wrong:
```bash
jj op log # Browse operations
# Bisect through time with --at-op
jj log --at-op=<candidate>
# Find last good state, restore to it
```
### Pattern: "Compare Now vs Then"
See all changes between a past operation and now:
```bash
jj op log # Find old operation
jj op diff --from <old> --to @ # See all changes
```
### Pattern: "Undo Multiple Operations"
Two approaches to go back several operations:
```bash
# Option 1: Multiple undo
jj undo
jj undo
jj undo
# Option 2: Direct restore (faster)
jj op log
jj op restore @--- # Go back 3 operations
```
### Pattern: "Explore Before Committing"
Use time travel to explore safely before restoring:
```bash
# 1. Browse operations
jj op log
# 2. Explore candidates with --at-op
jj log --at-op=abc123 # Candidate 1
jj log --at-op=def456 # Candidate 2
jj log --at-op=ghi789 # Found it!
# 3. Now commit to the restore
jj op restore ghi789
```
### Pattern: "See What Changed Between Two Operations"
Compare repository state between any two operations:
```bash
jj op log # Find two operations of interest
jj op diff --from abc123 --to def456
```
## Best Practices
### When to Use Operation Log
**Use operation log when:**
- ✅ You need to understand what you've been doing
- ✅ You want to find a specific past state
- ✅ You need to recover from complex mistakes
- ✅ You're debugging unexpected repository state
- ✅ You want to see history of changes to a commit
**Don't use operation log when:**
- ❌ You just need to undo the last operation (use `jj undo`)
- ❌ You're looking at commit history (use `jj log`)
- ❌ You want to see file changes (use `jj diff`)
### Exploration First, Restore Second
**Best practice:** Use `--at-op` to explore before using `jj op restore`:
```bash
# ✅ Good: Explore first
jj log --at-op=abc123 # Check if this is right
jj op restore abc123 # Commit to it
# ❌ Risky: Restore without checking
jj op restore abc123 # Hope this is right!
```
### Use Operation References for Recent Operations
For recent operations, use symbolic references instead of IDs:
```bash
# ✅ Good: Clear and concise
jj op restore @- # Go back one
jj op restore @-- # Go back two
# ❌ Verbose: Looking up IDs
jj op log # Find ID
jj op restore abc123def456 # Use ID
```
### Check Status After Restore
Always verify state after restoring:
```bash
jj op restore abc123
jj status # Check working copy
jj log # Check commit history
```
## Integration with Other Workflows
### With jj-undo Skill
**Relationship:** Operation log is the foundation, undo is a convenience.
```bash
# These are equivalent:
jj undo # Simple
jj op restore @- # Explicit
# These are equivalent:
jj undo && jj undo # Multiple undo
jj op restore @-- # Direct restore
```
**When to choose each:**
- Quick recent mistake → `jj undo`
- Need to skip multiple operations → `jj op restore`
- Not sure which operation → Explore with `--at-op`, then restore
### With Stack-Based Workflow
Use operation log to recover from stacking mistakes:
```bash
jj new # Start new commit
jj describe -m "message" # Oops, not ready
jj op log # Find operation before jj new
jj op restore @-- # Go back before new
```
### With Plan-Driven Workflow
Use operation log to recover plan commits:
```bash
jj describe -m "impl: feature" # Oops, lost the plan
jj op log # Find operation with plan
jj op restore abc123 # Restore plan commit
```
## Quick Reference Card
### Viewing Operations
```bash
jj op log # Show operation history
jj op log --limit 20 # Last 20 operations
jj op show <op-id> # Show operation details
jj op show @ # Show current operation
jj op diff --from <a> --to <b> # Compare operations
```
### Time Travel (Read-Only)
```bash
jj log --at-op=<op-id> # View commit history at operation
jj status --at-op=<op-id> # View working copy at operation
jj diff --at-op=<op-id> # View changes at operation
```
### Restoring
```bash
jj op restore <op-id> # Jump to specific operation
jj op restore @- # Go back one (= jj undo)
jj op restore @-- # Go back two operations
jj op restore @--- # Go back three operations
```
### Operation References
```bash
@ # Current operation
@- # Previous operation
@-- # Two operations ago
@--- # Three operations ago
```
## Remember
**Operation log is your time machine:**
- Everything is recorded
- Everything is explorable
- Everything is restorable
- You can't lose work in jj
**Progressive approach:**
1. View operations with `jj op log`
2. Explore safely with `--at-op`
3. Restore confidently with `jj op restore`
4. Verify with `jj status` and `jj log`

View File

@@ -0,0 +1,221 @@
# Restoring to Past Operations
This document covers how to restore the repository to past operations and recover from complex mistakes.
## The `jj op restore` Command
**Purpose:** Return the entire repository to the state at a specific operation.
**Key concept:** This is **actual time travel**. You're changing your repository state, not just viewing.
### What It Does
- Restores all commits to their state at that operation
- Updates bookmarks to their past positions
- Restores working copy to match that operation
- Creates a NEW operation recording this restoration
**Important:** `jj op restore` is itself an operation, so it's also undoable with `jj undo`.
## Basic Restore Workflow
### 1. Find the Operation You Want
```bash
jj op log
```
### 2. Restore to That Operation
```bash
jj op restore abc123def456
```
### 3. Verify the Restoration
```bash
jj status
jj log
```
## Example: Recovering from Bad Squash
```bash
# Oh no, squashed wrong commits!
jj op log # Find operation before squash
# See: xyz789abc123 was before the bad squash
jj op restore xyz789abc123 # Jump back before mistake
# Repository now as it was before squash
```
## Finding the Right Operation to Restore
See `time-travel.md` for exploration techniques using `--at-op` to find the right operation before committing to a restore.
### Strategy 1: By Time (Recent Mistake)
```bash
jj op log --limit 10 # Show last 10 operations
# Look for operation just before mistake
# Restore to that operation
```
### Strategy 2: By Command (Find Specific Action)
```bash
jj op log | grep "squash" # Find all squash operations
jj op log | grep "describe"# Find all describe operations
# Identify the problematic operation
# Restore to operation before it
```
### Strategy 3: By Exploration (Step Through History)
```bash
# Use --at-op to explore without committing
jj op log
jj log --at-op=abc123 # Is this the right state?
jj log --at-op=def456 # Or this one?
jj log --at-op=ghi789 # Found it!
jj op restore ghi789 # Now actually restore
```
## Complex Recovery Scenarios
### Scenario 1: Multiple Bad Operations
**Problem:** Made several mistakes in a row, need to go back before all of them.
**Solution:**
```bash
# 1. Find operations
jj op log --limit 20
# 2. Identify last good operation
jj log --at-op=<candidate> # Explore candidates
# 3. Restore to last good state
jj op restore <last-good-op>
```
### Scenario 2: Not Sure Which Operation to Restore
**Problem:** Complex history, unclear which operation to restore to.
**Solution - Use time travel to explore:**
```bash
# 1. Start with operation log
jj op log
# 2. Use --at-op to peek at different states
jj log --at-op=abc123
jj status --at-op=abc123
jj diff --at-op=abc123
# 3. Try different operations until you find the right one
jj log --at-op=def456
jj log --at-op=ghi789
# 4. When you find it, restore
jj op restore ghi789
```
### Scenario 3: Want to See Specific Change
**Problem:** Need to understand what a particular operation did.
**Solution:**
```bash
# 1. Find the operation
jj op log | grep "squash" # or other command
# 2. Show what it changed
jj op show abc123def456
# 3. Compare before/after
jj log --at-op=abc123@- # Before
jj log --at-op=abc123 # After
# 4. See diff
jj op diff --op abc123
```
### Scenario 4: Concurrent Operations (Advanced)
**Problem:** Multiple jj commands ran concurrently, created divergent operations.
**What happened:** Jj is lock-free, so concurrent operations create separate branches in the operation log.
**Solution:**
```bash
# 1. View operation log - will show divergence
jj op log
# 2. Identify which branch is correct
jj log --at-op=<branch1>
jj log --at-op=<branch2>
# 3. Restore to correct branch
jj op restore <correct-branch>
```
## Safety Considerations
### Restore is Undoable
Since `jj op restore` creates a new operation, you can undo it:
```bash
jj op restore abc123 # Restore to operation
# Oops, that was wrong
jj undo # Undo the restore
```
### What Restore Affects
**Does affect:**
- ✅ All commits and their states
- ✅ Bookmark positions
- ✅ Working copy files (updates to match restored state)
- ✅ Repository structure
**Does NOT affect:**
- ❌ The operation log itself (restore is recorded)
- ❌ Remote repositories until you push
- ❌ Other people's concurrent operations
### You Can't Lose Work
Even after restoring, the "future" operations still exist in the operation log. You can always restore forward again:
```bash
jj op restore abc123 # Go back
# Do some work...
jj op log # See all operations, including "future" ones
jj op restore def456 # Restore to future state
```
## When to Use Restore vs Undo
**Use `jj undo`** (see jj-undo skill):
- Quick recent mistake (1-2 operations ago)
- Simple, immediate reversal
**Use `jj op restore`:**
- Need to jump back multiple operations at once
- Know the specific operation ID you want
- Want to skip over several intermediate operations
- Complex recovery from multiple mistakes
**Relationship:**
- `jj undo` = `jj op restore @-` (restore to parent operation)
- `jj undo` twice = `jj op restore @--` (go back 2 operations)

View File

@@ -0,0 +1,135 @@
# Time Travel: Viewing Past States
This document covers how to explore the repository at past operations without modifying your current state.
## The `--at-op` Flag
**Purpose:** View the repository as it was at any past operation without changing current state.
**Key concept:** This is **read-only time travel**. You're peeking at history, not modifying anything.
## Works with Read-Only Commands
The `--at-op` flag can be used with any read-only jj command:
```bash
jj log --at-op=<op-id> # See commit history at that operation
jj status --at-op=<op-id> # See working copy state
jj diff --at-op=<op-id> # See changes at that time
jj show --at-op=<op-id> # See specific commit at that time
```
**Important:** Working copy is **NOT** modified. You're just viewing how things were.
## Basic Exploration Workflow
### 1. Find Operation of Interest
```bash
jj op log # Browse operation history
```
### 2. View Repo State at That Operation
```bash
jj log --at-op=abc123def456
```
### 3. Compare with Current State
```bash
jj log # Current state
jj log --at-op=abc123 # Past state
```
### 4. See What Changed in Working Copy
```bash
jj diff --at-op=abc123
```
## Exploring to Find Right Restore Point
**Problem:** You know something went wrong, but not sure which operation to restore to.
**Solution:** Use `--at-op` to explore without committing:
```bash
# 1. Start with operation log
jj op log
# 2. Use --at-op to peek at different states
jj log --at-op=abc123 # Is this the right state?
jj status --at-op=abc123 # Check working copy
jj diff --at-op=abc123 # See changes
# 3. Try different operations until you find the right one
jj log --at-op=def456 # Or this one?
jj log --at-op=ghi789 # Found it!
# 4. When you find it, restore (see restoring-operations.md)
jj op restore ghi789 # Now actually restore
```
## Time Travel Patterns
### "Find When Things Broke"
```bash
jj op log # Browse operations
# Bisect through time with --at-op
jj log --at-op=<candidate>
jj log --at-op=<earlier>
jj log --at-op=<evenEarlier>
# Find last good state, then restore to it
```
### "Compare Now vs Then"
```bash
# View current state
jj log
jj status
# View past state
jj log --at-op=abc123
jj status --at-op=abc123
# Compare
jj op diff --from abc123 --to @
```
### "See Commit History Evolution"
```bash
# How did the log look after each operation?
jj log --at-op=abc123 # After operation 1
jj log --at-op=def456 # After operation 2
jj log --at-op=ghi789 # After operation 3
```
## Advantages of Time Travel
**Safe exploration:**
- ✅ No risk of breaking current state
- ✅ Try multiple candidates before committing
- ✅ Understand what changed between operations
- ✅ Make informed decisions about restoring
**When to use:**
- Not sure which operation to restore to
- Want to understand history before taking action
- Debugging complex repository states
- Learning how operations affected the repository
## Important Notes
**Automatic snapshotting is disabled:** When using `--at-op`, jj doesn't snapshot the working copy before the command.
**Read-only only:** You cannot modify the repository while viewing at a past operation. Use `jj op restore` for that (see restoring-operations.md).
**No working copy modification:** Your files on disk don't change. You're viewing metadata about how the repo was structured at that point.

View File

@@ -0,0 +1,139 @@
# Viewing Operations in Jujutsu
This document covers how to browse and understand the operation log using read-only viewing commands.
## Browsing Operation History
### `jj op log` - View All Operations
**Basic usage:**
```bash
jj op log # Show recent operations
jj op log --limit 20 # Show last 20 operations
jj op log --no-graph # Show without graph visualization
```
**What you'll see:**
- Operation ID (12-character hash)
- Timestamp and duration
- Username and hostname
- Command that was executed
- High-level description of changes
**Example output interpretation:**
```
@ abc123def456 user@host 2025-01-05 14:23:45 -08:00
│ jj squash
│ squash commit xyz into abc
◉ 789ghi012jkl user@host 2025-01-05 14:20:12 -08:00
│ jj describe -m "Add feature"
│ describe commit xyz
```
**Reading the log:**
- `@` marks the current operation (where you are now)
- Most recent operations at top
- Each operation shows what command created it
- Graph shows operation relationships
## Exploring What Changed
### `jj op show <op-id>` - See Operation Details
**Purpose:** Understand exactly what a specific operation changed.
**Usage:**
```bash
jj op show abc123def456 # Show what operation did
jj op show @ # Show current operation
jj op show @- # Show previous operation
```
**What you'll see:**
- Operation metadata
- Which commits were modified
- What changed in each commit
- Bookmark movements
- Working copy changes
### `jj op diff` - Compare Repository States
**Purpose:** See differences between two operations or current vs past.
**Usage:**
```bash
# Compare current state with past operation
jj op diff --from abc123 --to @
# Compare two past operations
jj op diff --from abc123 --to def456
# See what operations changed
jj op diff --op abc123
```
**Use cases:**
- Understanding what went wrong between two points
- Seeing cumulative effect of several operations
- Debugging complex history issues
## Finding Operations
### By Time (Recent Mistakes)
```bash
jj op log --limit 10 # Show last 10 operations
# Look for operation just before mistake
```
### By Command (Specific Actions)
```bash
jj op log | grep "squash" # Find all squash operations
jj op log | grep "describe"# Find all describe operations
# Identify the problematic operation
```
### By Description (What You Were Doing)
```bash
# Operation log shows what you ran
jj op log
# Look for descriptions like:
# "snapshot working copy" → Auto-snapshots
# "jj describe" → Commit descriptions
# "jj new" → Stack operations
# "jj squash" → Squash operations
```
## Common Viewing Patterns
### "What Did I Just Do?"
```bash
jj op log --limit 5 # Recent operations
jj op show @ # Current operation details
```
### "What Changed in This Operation?"
```bash
jj op show abc123def456 # Show specific operation details
jj op diff --op abc123 # See the diff
```
### "Compare Two Points in Time"
```bash
jj op log # Find two operations
jj op diff --from abc123 --to def456 # Compare them
```

263
skills/jj-spr/SKILL.md Normal file
View File

@@ -0,0 +1,263 @@
---
name: Submitting Stacked PRs with jj-spr
description: Work with jj-spr for submitting and updating stacked GitHub Pull Requests. Use when the user explicitly mentions 'jj-spr', 'jj spr', 'stack pull request', 'stacked PR', or 'submit for review'. Integrates with jj commit workflow.
allowed-tools: Bash(jj log:*), Bash(jj status:*), Bash(jj diff:*), Bash(jj spr:*), Bash(gh pr:*)
---
# Submitting Stacked PRs with jj-spr
## Purpose
Submit and manage stacked GitHub PRs using jj-spr. Integrates with jj plugin's commit stacking workflow for sharing curated commits as reviewable PRs.
## Integration with jj-workflow
**Local curation:**
```bash
/jj:commit "feat: add login UI"
/jj:split test # Separate concerns
/jj:squash # Clean up WIP commits
```
**Submit to GitHub:**
```bash
jj spr submit # Create PRs for entire stack
```
**The flow:** Curate locally → Submit with `jj spr submit` → Amend commits → Update with `jj spr update`
## Core Commands
### Submit PRs
```bash
jj spr submit # Submit all commits in stack
jj spr submit -r <change-id> # Submit from specific commit upward
jj spr submit -r <id> --no-deps # Submit specific commit only
```
### Update PRs
```bash
jj spr update # Update all PRs with local changes
jj spr update -r <change-id> # Update specific PR
jj spr update --force # Force update (skip checks)
```
### View Status
```bash
jj spr info # Show PR info for commits
jj spr info -r <change-id> # Show info for specific commit
gh pr list # View PRs
gh pr view <pr-number> --web # Open PR in browser
```
## Common Workflows
### Submit Clean Commits
```bash
# 1. Build stack locally
/jj:commit "feat(auth): add login endpoint"
/jj:commit "test(auth): add login tests"
/jj:commit "docs(auth): document auth flow"
# 2. Review and curate
jj log
/jj:split test # Split if needed
/jj:squash # Squash if needed
# 3. Submit
jj spr submit
```
**Result:** Each commit becomes a PR, stacked automatically.
### Respond to Review Feedback
```bash
# 1. Edit specific commit
jj edit <change-id>
# 2. Make changes
# ... edit files ...
# 3. Update description if needed
jj describe -m "feat(auth): add login endpoint
Addressed review feedback:
- Add input validation
- Improve error messages"
# 4. Return to working copy and update PRs
jj new
jj spr update
```
**Result:** PR updated, dependent PRs rebased automatically.
### Add to Existing Stack
```bash
# Add new commits on top
/jj:commit "feat(auth): add password reset"
/jj:commit "test(auth): add reset tests"
# Submit new commits (existing PRs unchanged)
jj spr submit
```
### Fix Bug in Middle of Stack
```bash
# Edit earlier commit
jj edit <change-id>
# Fix bug
# ... make changes ...
# Return and update all affected PRs
jj new @+
jj spr update
```
### Reorder Stack
```bash
# Reorder with rebase
jj rebase -r <commit> -d <new-parent>
# Update PRs
jj spr update
```
### Split Commit After Submitting
```bash
# Edit commit with mixed changes
jj edit <change-id>
# Split
/jj:split "*settings*"
# Return and update
jj new @+
jj spr update
```
**Result:** Original PR split into two new PRs.
## When to Use jj-spr
**Use when:**
- Commits clean and ready for review
- Managing dependent features
- Large feature split into reviewable chunks
- Responding to review feedback
**Consider alternatives when:**
- Single PR (use `jj git push` + `gh pr create`)
- Commits still messy (curate first with `/jj:commit`, `/jj:split`, `/jj:squash`)
- Collaborative feature branch (different workflow needed)
## Best Practices
### Before Submitting
```bash
/jj:split test # Split mixed concerns
/jj:squash # Squash WIP commits
jj log # Verify stack order
nix flake check # Run tests
```
### Commit Guidelines
- **One logical change per commit**: "feat(auth): add JWT validation" ✅ not "add login, logout, and profile" ❌
- **Clear messages**: First line becomes PR title, body becomes description
- **Reviewable size**: Keep commits focused and small
### Stack Management
- Keep stacks shallow (<5 PRs)
- Merge from bottom up
- Note dependencies in PR descriptions
### Handling Feedback
- **Amend commits**, don't add fixup commits
- Update commit messages to reflect changes
- `jj spr update` syncs PR descriptions
## Quick Reference
### Common Patterns
**Submit entire stack:**
```bash
jj spr submit
```
**Update after amending:**
```bash
jj edit <change-id>
# ... make changes ...
jj new
jj spr update
```
**Check stack status:**
```bash
jj log -T 'concat(change_id.short(), ": ", description)'
jj spr info
```
### Troubleshooting
**Wrong base branch:**
```bash
gh pr edit <pr-number> --base <correct-base>
```
**Out of order:**
```bash
jj rebase -r <commit> -d <new-parent>
jj spr update
```
**Conflicts after update:**
```bash
jj rebase -d main
# ... resolve conflicts ...
jj spr update
```
**WIP commits submitted:**
```bash
gh pr close <pr-number>
/jj:squash # Clean up
jj spr submit # Resubmit
```
## When This Skill Activates
Use this Skill when:
- User mentions PRs, pull requests, or GitHub reviews
- User asks about sharing work for review
- Working with stacked or dependent PRs
- Need to update PRs after changes
- Discussing code review workflows
- User mentions amending commits that have PRs

244
skills/jj-undo/SKILL.md Normal file
View File

@@ -0,0 +1,244 @@
---
name: Undoing Operations in Jujutsu
description: Help users undo mistakes and recover from errors in jj. Use when the user explicitly mentions 'jj undo', 'undo operation', or 'restore operation'. Covers quick undo, multiple undo scenarios, and redo workflows.
allowed-tools: Bash(jj undo:*), Bash(jj op log:*), Bash(jj op restore:*), Bash(jj log:*), Bash(jj status:*), Bash(jj diff:*)
---
# Undoing Operations in Jujutsu
## Core Undo Concept
**Everything is undoable in jj.** Every operation is recorded and can be reversed. There's no need to fear making mistakes.
**Key insight:** Jj auto-snapshots the working copy before every operation, so you can always go back.
## Quick Undo: The Most Useful Command
### `jj undo` - Reverse the Last Operation
**When to use:** You just ran a command and immediately realized it was wrong.
**What it does:** Reverses the most recent operation, restoring the repository to its previous state.
**Examples:**
```bash
# Accidentally squashed the wrong commits
jj squash
jj undo # Reverses the squash
# Described a commit with the wrong message
jj describe -m "wrong message"
jj undo # Restores previous description
# Split commits incorrectly
/jj:split test
jj undo # Reverses the split
```
**Important:** `jj undo` affects the repository state, but working copy files update automatically to match.
## Multiple Undo
### Undoing Several Operations
You can run `jj undo` multiple times to step backwards through operations:
```bash
jj undo # Undo most recent operation
jj undo # Undo the one before that
jj undo # Keep going back
```
**Workflow:**
1. Run `jj op log` to see what operations you want to undo
2. Run `jj undo` once for each operation you want to reverse
3. Check `jj status` to verify the result
**Tip:** Each `jj undo` is itself an operation, so you can undo an undo (see Redo section).
## Redo After Undo
### Using Operation Log to Redo
If you undo too many operations, you can "redo" by looking at the operation log:
**Method 1: Undo the undo**
```bash
jj undo # Undoes the last undo operation
```
**Method 2: Restore to specific operation**
```bash
jj op log # Find the operation ID you want
jj op restore <op-id> # Jump to that operation
```
**Example:**
```bash
jj squash # Operation A
jj undo # Operation B (undoes A)
jj undo # Operation C (undoes B, effectively redoing A)
```
## When to Use Different Undo Approaches
### `jj undo` vs `jj op restore` vs `jj abandon`
**Use `jj undo` when:**
- ✅ You want to reverse the most recent operation
- ✅ You need a simple, immediate reversal
- ✅ You want to step back through operations one at a time
- ✅ You're trying things and want an easy undo button
**Use `jj op restore <id>` when:**
- ✅ You need to jump back multiple operations at once
- ✅ You know the specific operation ID you want to restore to
- ✅ You want to skip over several intermediate operations
- ✅ You're recovering from a complex multi-step mistake
**Use `jj abandon` when:**
- ✅ You want to delete specific commits (not operations)
- ✅ You're cleaning up commits, not undoing operations
- ✅ You want the commits gone permanently (though still in op log)
**Key difference:** `jj undo` and `jj op restore` affect operations (what commands you ran), while `jj abandon` affects commits (what changes exist).
## Common Mistake Recovery Patterns
### 1. Wrong Commit Message
```bash
jj describe -m "typo in mesage"
jj undo
jj describe -m "correct message"
```
### 2. Squashed Wrong Commits
```bash
jj squash # Oops, wrong parent
jj undo
# Now squash correctly
```
### 3. Split Incorrectly
```bash
/jj:split test # Split wasn't quite right
jj undo
/jj:split docs # Try different pattern
```
### 4. Created New Commit Too Early
```bash
jj new # Oops, wasn't ready for new commit
jj undo
# Continue working in current commit
```
### 5. Multiple Related Mistakes
```bash
jj undo # Undo most recent
jj undo # Undo the one before
jj undo # Keep going until clean state
# Or use jj op log to find target and jj op restore
```
## Safety Notes
### What Undo Affects
**Does affect:**
- ✅ Commit history and change IDs
- ✅ Bookmark positions
- ✅ Working copy state (updates automatically)
- ✅ Descriptions and metadata
**Does NOT affect:**
- ❌ The operation log itself (undos are recorded)
- ❌ Remote repositories until you push
- ❌ Other people's work in concurrent operations
### Can't Lose Work
**Important:** Even if you undo operations, the changes still exist in the operation log. You can always:
- View old state with `jj log --at-op=<old-op-id>`
- Restore to any previous operation with `jj op restore`
- See all operations with `jj op log`
**Bottom line:** In jj, you can't accidentally lose work. The operation log is your safety net.
## When to Suggest Undo to Users
**Immediately suggest `jj undo` when:**
- User expresses regret about a command
- User says "wait, that was wrong"
- User wants to try a different approach
- An operation produced unexpected results
**Suggest exploring operation log when:**
- User wants to see what they've done
- User needs to go back multiple steps
- User is recovering from complex mistakes
- User asks "what did I do?" or "how do I get back?"
**Proactive help:**
- After complex operations (squash, split), mention undo is available
- When user is learning jj, remind them everything is undoable
- If an operation might be risky, mention undo safety net first
## Integration with Other Workflows
### With `/jj:commit`
```bash
/jj:commit # Claude generates commit message
# If message isn't quite right:
jj undo # Undo the description
/jj:commit # Try again with different context
```
### With Stack-Based Workflow
```bash
jj new # Start new commit
# Realize you're not done with previous commit yet:
jj undo # Go back to previous commit
# Continue working
```
### With Plan-Driven Workflow
```bash
/jj:commit # Replace "plan:" with implementation
# Realize plan needs more work:
jj undo # Restore "plan:" description
# Continue implementing
```
## Quick Reference
**Most common commands:**
- `jj undo` - Reverse last operation (use multiple times to go back further)
- `jj op log` - See what operations can be undone
- `jj status` - Verify state after undo
- `jj log` - See commit history after undo
**Remember:** Everything is recorded, everything is undoable, you can't lose work.

View File

@@ -0,0 +1,93 @@
---
name: Working with Jujutsu Version Control
description: Understand and work with Jujutsu (jj) version control system. Use when the user mentions commits, changes, version control, or working with jj repositories. Helps with stack-based commit workflows, change curation, and jj best practices.
allowed-tools: Bash(jj status:*), Bash(jj log:*), Bash(jj show:*), Bash(jj diff:*)
---
# Working with Jujutsu Version Control
## Core Concepts
**Jujutsu (jj)** - Git-compatible VCS with:
- **Change-based**: Unique IDs persist through rewrites
- **Auto-snapshotting**: Working copy snapshotted before each operation
- **Stack-based**: Build commits in a stack
- **Undoable**: All ops in `jj op log`, use `jj op restore` to time travel
**vs Git:** No staging area, edit any commit (`jj edit`), conflicts stored in commits
## Working Copy (`@`)
Current commit is always `@`:
- `jj log -r @` - Current commit
- `jj log -r @-` - Parent commit
- `jj log -r 'ancestors(@, 5)'` - Recent stack
**State:**
- Empty, no description → Ready for changes
- Has changes, no description → Needs description
- Has description + changes → Can stack with `jj new`
- Has description, no changes → Ready for new work
## Stack-Based Workflow
1. Make changes in `@` (new files tracked automatically via `/jj:commit`)
2. Describe: `jj describe -m "message"` or `/jj:commit`
3. Stack: `jj new`
4. Repeat
**Why stack:** Individual review, easy reordering, incremental shipping, clean history
## Plan-Driven Workflow
1. **Start**: Create "plan:" commit describing intent
2. **Work**: Implement the plan
3. **End**: Replace "plan:" with actual work using `/jj:commit`
**TodoWrite:** One commit per major todo, `jj new` between todos
## Automatic Snapshotting
Every `jj` command auto-snapshots. Use `jj op log`, `jj undo`, or `jj op restore <id>` for time travel.
## When to Suggest Commands
**Viewing state:** `jj status`, `jj log`, `jj show`, `jj diff`
**Creating commits:**
- Use `/jj:commit` (not `jj describe` directly)
- Suggest when user has substantial changes or plan needs updating
**Organizing commits:**
- `/jj:split <pattern>` when mixing concerns (tests+code)
- `/jj:squash` for multiple WIP commits
- Don't suggest for simple, focused changes
**Undoing:** `jj undo`, `jj op restore`, `jj abandon`
## Slash Commands
- `/jj:commit [message]` - Stack commit with message generation
- `/jj:split <pattern>` - Split by pattern (test, docs, config)
- `/jj:squash [revision]` - Merge commits
- `/jj:cleanup` - Remove empty workspaces
## Git Translation
Repository blocks git write commands via hook. Prefer jj equivalents:
- `git status``jj status`
- `git commit``/jj:commit`
- `git log``jj log`
- `git checkout``jj new`
## Best Practices
**Do:** Stack commits, describe clearly (what/why), use plan-driven workflow, leverage `jj op log`, split mixed concerns
**Don't:** Mix git/jj, leave work undescribed, create monolithic commits, forget everything is undoable