Initial commit
This commit is contained in:
112
skills/working-with-jj/SKILL.md
Normal file
112
skills/working-with-jj/SKILL.md
Normal file
@@ -0,0 +1,112 @@
|
||||
---
|
||||
name: working-with-jj
|
||||
description: Expert guidance for using JJ (Jujutsu) version control system. Use when working with JJ, whatever the subject. Operations, revsets, templates, TODO commit workflows, debugging change evolution, etc. Covers JJ commands, template system, evolog, operations log, and specific JJ workflows.
|
||||
---
|
||||
|
||||
# JJ (Jujutsu) Version Control Helper
|
||||
|
||||
## Core Principles
|
||||
|
||||
- **Change IDs** (immutable) vs **Commit IDs** (content-based hashes that change
|
||||
on edit)
|
||||
- **Operations log** - every operation can be undone with `jj op restore`
|
||||
- **No staging area** - working copy auto-snapshots
|
||||
- **Conflicts don't block** - resolve later
|
||||
- **Commits are lightweight** - edit freely
|
||||
|
||||
## Essential Commands
|
||||
|
||||
```bash
|
||||
jj log -r <revset> # View history
|
||||
jj evolog -r <rev> --git # Change evolution (with diffs)
|
||||
jj new <base> # Create revision and edit it
|
||||
jj new --no-edit <base> # Create without switching (for TODOs)
|
||||
jj edit <rev> # Switch to editing revision
|
||||
jj desc -r <rev> -m "text" # Set description
|
||||
|
||||
jj diff # Changes in @
|
||||
jj diff -r <rev> # Changes in revision
|
||||
jj restore <path> # Discard changes to file
|
||||
jj restore --from <rev> <path> # Restore from another revision
|
||||
|
||||
jj split -r <rev> # Split into multiple commits
|
||||
jj squash # Squash @ into parent
|
||||
jj squash --into <dest> # Squash @ into specific revision
|
||||
jj absorb # Auto-squash into right ancestors
|
||||
|
||||
jj rebase -s <src> -d <dest> # Rebase with descendants
|
||||
jj rebase -r <rev> -d <dest> # Rebase single revision only
|
||||
```
|
||||
|
||||
## Quick Revset Reference
|
||||
|
||||
```bash
|
||||
@, @-, @-- # Working copy, parent, grandparent
|
||||
::@ # Ancestors
|
||||
mine() # Your changes
|
||||
conflict() # Has conflicts
|
||||
description(substring:"text") # Match description
|
||||
A | B, A & B, A ~ B # Union, intersection, difference
|
||||
```
|
||||
|
||||
See `references/revsets.md` for comprehensive revset patterns.
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
### 1. Use `-r` not `--revisions`
|
||||
|
||||
```bash
|
||||
jj log -r xyz # ✅
|
||||
jj log --revisions xyz # ❌
|
||||
```
|
||||
|
||||
### 2. Use `--no-edit` for parallel branches
|
||||
|
||||
```bash
|
||||
jj new parent -m "A"; jj new parent -m "B" # ❌ B is child of A!
|
||||
jj new --no-edit parent -m "A"; jj new --no-edit parent -m "B" # ✅ Both children of parent
|
||||
```
|
||||
|
||||
### 3. Quote revsets in shell
|
||||
|
||||
```bash
|
||||
jj log -r 'description(substring:"[todo]")' # ✅
|
||||
```
|
||||
|
||||
## Scripts
|
||||
|
||||
Helper scripts in `scripts/`. Add to PATH or invoke directly.
|
||||
|
||||
| Script | Purpose |
|
||||
| ----------------------------------------- | -------------------------------------- |
|
||||
| `jj-show-desc [REV]` | Get description only |
|
||||
| `jj-show-detailed [REV]` | Detailed info with git diff |
|
||||
| `jj-todo-create <PARENT> <TITLE> [DESC]` | Create TODO (stays on @) |
|
||||
| `jj-todo-done [NEXT_REV]` | Complete current TODO, start next |
|
||||
| `jj-flag-update <REV> <TO_FLAG>` | Update status flag (auto-detects current) |
|
||||
| `jj-find-flagged [FLAG]` | Find flagged revisions |
|
||||
| `jj-parallel-todos <PARENT> <T1> <T2>...` | Create parallel TODOs |
|
||||
| `jj-desc-transform <REV> <CMD...>` | Pipe description through command |
|
||||
| `jj-batch-desc <SED_FILE> <REV...>` | Batch transform descriptions |
|
||||
| `jj-checkpoint [NAME]` | Record op ID before risky operations |
|
||||
|
||||
These scripts are notably useful if you are working using a _"TODO Commit
|
||||
Workflow"_: see `references/todo-workflow.md` for structured TODO planning,
|
||||
parallel task DAGs, and AI-assisted workflows.
|
||||
|
||||
## Recovery
|
||||
|
||||
```bash
|
||||
jj op log # Find operation before problem
|
||||
jj op restore <op-id> # Restore to that state
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- `references/todo-workflow.md` - Structured TODO planning, parallel DAGs, AI
|
||||
workflows
|
||||
- `references/revsets.md` - Full revset syntax and patterns
|
||||
- `references/templates.md` - Template language and custom output
|
||||
- `references/git-remotes.md` - Bookmarks, push/fetch, remote workflows
|
||||
- `references/command-syntax.md` - Command flag details
|
||||
- `references/batch-operations.md` - Complex batch transformations
|
||||
165
skills/working-with-jj/references/batch-operations.md
Normal file
165
skills/working-with-jj/references/batch-operations.md
Normal file
@@ -0,0 +1,165 @@
|
||||
# Batch Operations on Multiple Revisions
|
||||
|
||||
## Problem
|
||||
|
||||
When you need to update descriptions for multiple revisions (e.g., replacing line number references with labels), bash syntax and piping can be tricky.
|
||||
|
||||
## Anti-Pattern
|
||||
|
||||
```bash
|
||||
# ❌ This will fail with syntax errors
|
||||
for rev in unxn mktt stnq; do
|
||||
jj log -r $rev | sed 's/L123/label/' | jj desc -r $rev --stdin
|
||||
done
|
||||
|
||||
# Issues:
|
||||
# 1. Missing -n1 --no-graph -T description (gets full log output)
|
||||
# 2. Unquoted variables ($rev) can break with special chars
|
||||
# 3. Complex pipes in one-liners are fragile
|
||||
```
|
||||
|
||||
## Pattern 1: Intermediate Files (Recommended)
|
||||
|
||||
```bash
|
||||
# ✅ Robust pattern using temporary files
|
||||
for rev in unxn mktt stnq rwyq roww; do
|
||||
# Extract description to file
|
||||
jj log -r "$rev" -n1 --no-graph -T description > /tmp/desc_${rev}_old.txt
|
||||
|
||||
# Transform using sed/awk/etc
|
||||
sed -f /tmp/replacements.sed /tmp/desc_${rev}_old.txt > /tmp/desc_${rev}_new.txt
|
||||
|
||||
# Apply back to revision
|
||||
jj desc -r "$rev" --stdin < /tmp/desc_${rev}_new.txt
|
||||
done
|
||||
|
||||
echo "✅ All descriptions updated"
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- Each step is visible and debuggable
|
||||
- Can inspect intermediate files if something goes wrong
|
||||
- Easy to retry individual revisions
|
||||
- Works with complex transformations
|
||||
|
||||
## Pattern 2: One Command at a Time
|
||||
|
||||
```bash
|
||||
# ✅ Alternative: Sequential approach
|
||||
jj log -r unxn -n1 --no-graph -T description | \
|
||||
sed 's/L123/@label/' > /tmp/desc_unxn.txt
|
||||
jj desc -r unxn --stdin < /tmp/desc_unxn.txt
|
||||
|
||||
jj log -r mktt -n1 --no-graph -T description | \
|
||||
sed 's/L123/@label/' > /tmp/desc_mktt.txt
|
||||
jj desc -r mktt --stdin < /tmp/desc_mktt.txt
|
||||
|
||||
# etc.
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- Even more explicit
|
||||
- Easy to stop/resume
|
||||
- Perfect for copy-paste execution
|
||||
|
||||
## Pattern 3: Using sed Script File
|
||||
|
||||
```bash
|
||||
# Create reusable sed script
|
||||
cat > /tmp/replacements.sed << 'EOF'
|
||||
s/L596-617/@types-de-cartes/g
|
||||
s/L1242-1253/@carte-eglise/g
|
||||
s/L659-665/@couts-marche/g
|
||||
EOF
|
||||
|
||||
# Apply to all revisions
|
||||
for rev in unxn mktt stnq; do
|
||||
jj log -r "$rev" -n1 --no-graph -T description | \
|
||||
sed -f /tmp/replacements.sed | \
|
||||
jj desc -r "$rev" --stdin
|
||||
done
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- Reusable transformation logic
|
||||
- Easy to test sed script independently
|
||||
- Cleaner loop body
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
### 1. Missing Template Specification
|
||||
|
||||
```bash
|
||||
# ❌ Wrong: gets formatted log output
|
||||
jj log -r xyz | sed 's/old/new/'
|
||||
|
||||
# ✅ Correct: extract just description
|
||||
jj log -r xyz -n1 --no-graph -T description | sed 's/old/new/'
|
||||
```
|
||||
|
||||
### 2. Unquoted Variables
|
||||
|
||||
```bash
|
||||
# ❌ Breaks with special characters in rev names
|
||||
for rev in a b c; do
|
||||
jj log -r $rev # Unquoted
|
||||
done
|
||||
|
||||
# ✅ Always quote
|
||||
for rev in a b c; do
|
||||
jj log -r "$rev" # Quoted
|
||||
done
|
||||
```
|
||||
|
||||
### 3. Fragile One-Liners
|
||||
|
||||
```bash
|
||||
# ❌ Hard to debug, fragile
|
||||
for rev in a b c; do jj log -r $rev -n1 --no-graph -T description | sed 's/x/y/' | jj desc -r $rev --stdin; done
|
||||
|
||||
# ✅ Readable, debuggable
|
||||
for rev in a b c; do
|
||||
jj log -r "$rev" -n1 --no-graph -T description | \
|
||||
sed 's/x/y/' > /tmp/desc_${rev}.txt
|
||||
jj desc -r "$rev" --stdin < /tmp/desc_${rev}.txt
|
||||
done
|
||||
```
|
||||
|
||||
## Real-World Example
|
||||
|
||||
Replacing all line number references with Typst labels across 10 revisions:
|
||||
|
||||
```bash
|
||||
# 1. Create sed replacement script
|
||||
cat > /tmp/sed_replacements.txt << 'EOF'
|
||||
s/5F\.typ L596-617/5F.typ @types-de-cartes/g
|
||||
s/5F\.typ L1242-1253/5F.typ @carte-eglise-en-pierre/g
|
||||
s/5F\.typ L659-665/5F.typ @couts-marche/g
|
||||
# ... etc
|
||||
EOF
|
||||
|
||||
# 2. Process each revision
|
||||
for rev in unxn mktt stnq rwyq roww wltq syun zkru mszz ovrv; do
|
||||
jj log -r "$rev" -n1 --no-graph -T description | \
|
||||
sed -f /tmp/sed_replacements.txt > "/tmp/desc_${rev}_new.txt"
|
||||
jj desc -r "$rev" --stdin < "/tmp/desc_${rev}_new.txt"
|
||||
done
|
||||
|
||||
# 3. Verify one result
|
||||
jj log -r mktt -n1 --no-graph -T description | head -5
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
Always verify the results after batch operations:
|
||||
|
||||
```bash
|
||||
# Quick check: first line of each description
|
||||
for rev in unxn mktt stnq; do
|
||||
echo "=== $rev ==="
|
||||
jj log -r "$rev" -n1 --no-graph -T description | head -3
|
||||
done
|
||||
|
||||
# Or use jj log with custom template
|
||||
jj log -r 'unxn | mktt | stnq' -T 'change_id.shortest(4) ++ " " ++ description.first_line() ++ "\n"'
|
||||
```
|
||||
211
skills/working-with-jj/references/command-syntax.md
Normal file
211
skills/working-with-jj/references/command-syntax.md
Normal file
@@ -0,0 +1,211 @@
|
||||
# JJ Command Syntax Reference
|
||||
|
||||
## The `-r` Flag Confusion
|
||||
|
||||
JJ commands are **inconsistent** with flag naming, which can be confusing:
|
||||
|
||||
### Commands Using `-r` (Most Common)
|
||||
|
||||
```bash
|
||||
jj log -r <revset> # ✅ Short form only
|
||||
jj desc -r <revset> # ✅ Short form only
|
||||
jj show -r <revset> # ✅ Short form only
|
||||
jj rebase -r <revset> # ✅ Short form only
|
||||
jj edit -r <revset> # ✅ Short form only (no --revision)
|
||||
```
|
||||
|
||||
**Rule:** For most commands, use `-r` and **never** `--revisions` or `--revision`.
|
||||
|
||||
### Why This Matters
|
||||
|
||||
```bash
|
||||
# ❌ Common mistake: trying long form
|
||||
jj desc --revisions xyz
|
||||
# Error: unexpected argument '--revisions' found
|
||||
|
||||
jj log --revision xyz
|
||||
# Error: unexpected argument '--revision' found
|
||||
|
||||
# ✅ Always use short form
|
||||
jj desc -r xyz
|
||||
jj log -r xyz
|
||||
```
|
||||
|
||||
## Command Patterns
|
||||
|
||||
### Reading Revision Info
|
||||
|
||||
```bash
|
||||
# Get description only (for processing)
|
||||
jj log -r <rev> -n1 --no-graph -T description
|
||||
|
||||
# Get detailed info (human-readable)
|
||||
jj log -r <rev> -n1 --no-graph -T builtin_log_detailed
|
||||
|
||||
# Get compact one-liner
|
||||
jj log -r <rev> -T 'change_id.shortest(4) ++ " " ++ description.first_line()'
|
||||
```
|
||||
|
||||
**Key flags:**
|
||||
- `-n1`: Limit to 1 revision
|
||||
- `--no-graph`: No ASCII art graph
|
||||
- `-T <template>`: Output template
|
||||
- `-r <revset>`: Which revision(s)
|
||||
|
||||
### Modifying Revisions
|
||||
|
||||
```bash
|
||||
# Change description from string
|
||||
jj desc -r <rev> -m "New description"
|
||||
|
||||
# Change description from stdin (for scripts)
|
||||
echo "New description" | jj desc -r <rev> --stdin
|
||||
|
||||
# Change description from file
|
||||
jj desc -r <rev> --stdin < /path/to/description.txt
|
||||
|
||||
# Pipeline pattern
|
||||
jj log -r <rev> -n1 --no-graph -T description | \
|
||||
sed 's/old/new/' | \
|
||||
jj desc -r <rev> --stdin
|
||||
```
|
||||
|
||||
**Key insight:** `--stdin` is essential for scripted modifications.
|
||||
|
||||
### Creating Revisions
|
||||
|
||||
```bash
|
||||
# Create and edit immediately (moves @)
|
||||
jj new <parent> -m "Description"
|
||||
|
||||
# Create without editing (@ stays put) - IMPORTANT for parallel branches
|
||||
jj new --no-edit <parent> -m "Description"
|
||||
|
||||
# Create with multiple parents (merge)
|
||||
jj new --no-edit <parent1> <parent2> -m "Merge point"
|
||||
```
|
||||
|
||||
**Critical distinction:**
|
||||
- Without `--no-edit`: Your working copy (@) moves to the new revision
|
||||
- With `--no-edit`: New revision created, but @ stays where it was
|
||||
|
||||
## Revset Syntax
|
||||
|
||||
### Basic Revsets
|
||||
|
||||
```bash
|
||||
@ # Working copy
|
||||
<change-id> # Specific revision (e.g., abc, unxn)
|
||||
<commit-id> # By commit hash
|
||||
```
|
||||
|
||||
### Operators
|
||||
|
||||
```bash
|
||||
<rev>::<rev> # Range (from..to, inclusive)
|
||||
<rev>.. # All descendants
|
||||
..<rev> # All ancestors
|
||||
|
||||
# Examples
|
||||
zyxu::@ # All revisions from zyxu to current
|
||||
roww:: # roww and all its descendants
|
||||
::@ # All ancestors of @
|
||||
```
|
||||
|
||||
### Functions
|
||||
|
||||
```bash
|
||||
description(glob:"pattern") # Match description
|
||||
description(exact:"text") # Exact match
|
||||
mine() # Your commits
|
||||
```
|
||||
|
||||
### Combining
|
||||
|
||||
```bash
|
||||
# Union (OR)
|
||||
rev1 | rev2
|
||||
|
||||
# Intersection (AND)
|
||||
rev1 & rev2
|
||||
|
||||
# Example: Your changes in current branch
|
||||
mine() & ::@
|
||||
```
|
||||
|
||||
## Shell Quoting
|
||||
|
||||
Revsets often need quoting because they contain special characters:
|
||||
|
||||
```bash
|
||||
# ❌ Shell interprets glob
|
||||
jj log -r description(glob:"[todo]*")
|
||||
|
||||
# ✅ Single quotes (safest)
|
||||
jj log -r 'description(glob:"[todo]*")'
|
||||
|
||||
# ✅ Double quotes with escaping
|
||||
jj log -r "description(glob:\"[todo]*\")"
|
||||
```
|
||||
|
||||
**Rule:** When in doubt, use single quotes around revsets.
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Update Multiple Revisions
|
||||
|
||||
```bash
|
||||
# Pattern: Extract → Transform → Apply
|
||||
for rev in a b c; do
|
||||
jj log -r "$rev" -n1 --no-graph -T description > /tmp/desc.txt
|
||||
# ... transform /tmp/desc.txt ...
|
||||
jj desc -r "$rev" --stdin < /tmp/desc.txt
|
||||
done
|
||||
```
|
||||
|
||||
### Find and Update
|
||||
|
||||
```bash
|
||||
# Find all [todo] revisions
|
||||
jj log -r 'description(glob:"[todo]*")'
|
||||
|
||||
# Update specific one
|
||||
jj log -r xyz -n1 --no-graph -T description | \
|
||||
sed 's/\[todo\]/[wip]/' | \
|
||||
jj desc -r xyz --stdin
|
||||
```
|
||||
|
||||
### Create Parallel Branches
|
||||
|
||||
```bash
|
||||
# All branch from same parent
|
||||
parent=xyz
|
||||
jj new --no-edit "$parent" -m "[todo] Branch A"
|
||||
jj new --no-edit "$parent" -m "[todo] Branch B"
|
||||
jj new --no-edit "$parent" -m "[todo] Branch C"
|
||||
```
|
||||
|
||||
## Debugging
|
||||
|
||||
```bash
|
||||
# Did my command work?
|
||||
jj log -r <rev> -T 'change_id ++ " " ++ description.first_line()'
|
||||
|
||||
# View full description
|
||||
jj log -r <rev> -n1 --no-graph -T description
|
||||
|
||||
# Check revision graph
|
||||
jj log -r '<parent>::' -T builtin_log_compact
|
||||
```
|
||||
|
||||
## Quick Reference Card
|
||||
|
||||
| Task | Command |
|
||||
|------|---------|
|
||||
| View description | `jj log -r <rev> -n1 --no-graph -T description` |
|
||||
| Set description | `jj desc -r <rev> -m "text"` |
|
||||
| Set from stdin | `jj desc -r <rev> --stdin` |
|
||||
| Create (edit) | `jj new <parent> -m "text"` |
|
||||
| Create (no edit) | `jj new --no-edit <parent> -m "text"` |
|
||||
| Range query | `jj log -r '<from>::<to>'` |
|
||||
| Find pattern | `jj log -r 'description(glob:"pat*")'` |
|
||||
168
skills/working-with-jj/references/git-remotes.md
Normal file
168
skills/working-with-jj/references/git-remotes.md
Normal file
@@ -0,0 +1,168 @@
|
||||
# Working with Git Remotes
|
||||
|
||||
JJ coexists with Git. The `.git` directory is the source of truth for remotes.
|
||||
|
||||
## Basic Workflow
|
||||
|
||||
```bash
|
||||
# 1. Fetch latest from remotes
|
||||
jj git fetch
|
||||
|
||||
# 2. Rebase your work onto updated main
|
||||
jj rebase -d 'main@origin'
|
||||
|
||||
# 3. Make changes...
|
||||
|
||||
# 4. Point a bookmark at your work
|
||||
jj bookmark set my-feature -r @
|
||||
|
||||
# 5. Push to remote
|
||||
jj git push --bookmark my-feature
|
||||
```
|
||||
|
||||
## Bookmarks vs Git Branches
|
||||
|
||||
JJ "bookmarks" = Git "branches". They're just named pointers to revisions.
|
||||
|
||||
```bash
|
||||
jj bookmark list # List all bookmarks
|
||||
jj bookmark create <name> -r <rev> # Create new bookmark
|
||||
jj bookmark set <name> -r <rev> # Move existing bookmark
|
||||
jj bookmark delete <name> # Delete bookmark
|
||||
```
|
||||
|
||||
**Key insight:** Unlike Git, you don't need to "be on a branch" to work. Just edit any revision directly.
|
||||
|
||||
## Remote Bookmarks
|
||||
|
||||
Remote bookmarks have the form `name@remote`:
|
||||
|
||||
```bash
|
||||
main@origin # Remote main on origin
|
||||
feature@upstream # Remote feature on upstream
|
||||
```
|
||||
|
||||
### Tracking
|
||||
|
||||
```bash
|
||||
jj bookmark track main@origin # Start tracking remote bookmark
|
||||
jj bookmark untrack main@origin # Stop tracking
|
||||
```
|
||||
|
||||
Tracked bookmarks automatically update on `jj git fetch`.
|
||||
|
||||
### Local vs Remote
|
||||
|
||||
After fetch, `main` (local) and `main@origin` (remote) may differ:
|
||||
|
||||
```bash
|
||||
# See the difference
|
||||
jj log -r '::main ~ ::main@origin' # Local commits not in remote
|
||||
jj log -r '::main@origin ~ ::main' # Remote commits not in local
|
||||
|
||||
# Update local to match remote
|
||||
jj bookmark set main -r 'main@origin'
|
||||
```
|
||||
|
||||
## Pushing
|
||||
|
||||
```bash
|
||||
jj git push --bookmark <name> # Push specific bookmark
|
||||
jj git push --all # Push all bookmarks
|
||||
jj git push --change <rev> # Create/push bookmark for revision
|
||||
```
|
||||
|
||||
### Push Errors
|
||||
|
||||
**"bookmark moved unexpectedly"**: Someone else pushed. Fetch and rebase:
|
||||
|
||||
```bash
|
||||
jj git fetch
|
||||
jj rebase -d 'main@origin'
|
||||
jj git push --bookmark my-feature
|
||||
```
|
||||
|
||||
**"would delete remote bookmark"**: Remote has bookmark you don't. Either:
|
||||
|
||||
```bash
|
||||
jj git push --bookmark <name> --allow-delete # Delete remote
|
||||
# or
|
||||
jj bookmark track <name>@origin # Keep tracking it
|
||||
```
|
||||
|
||||
## Fetching
|
||||
|
||||
```bash
|
||||
jj git fetch # Fetch all remotes
|
||||
jj git fetch --remote origin # Fetch specific remote
|
||||
```
|
||||
|
||||
After fetch, rebase onto updated remote:
|
||||
|
||||
```bash
|
||||
jj rebase -d 'main@origin'
|
||||
```
|
||||
|
||||
## Cloning
|
||||
|
||||
```bash
|
||||
jj git clone <url> [path] # Clone Git repo into JJ
|
||||
jj git clone --colocate <url> # Colocated: .git + .jj together
|
||||
```
|
||||
|
||||
### Colocated Repos
|
||||
|
||||
Colocated repos have both `.git` and `.jj` at the root. Git and JJ see the same history.
|
||||
|
||||
```bash
|
||||
# Convert existing Git repo to colocated JJ
|
||||
cd existing-git-repo
|
||||
jj git init --colocate
|
||||
```
|
||||
|
||||
## Import/Export
|
||||
|
||||
JJ auto-imports from Git on most operations. Manual control:
|
||||
|
||||
```bash
|
||||
jj git import # Import Git refs → JJ
|
||||
jj git export # Export JJ bookmarks → Git refs
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Start feature from latest main
|
||||
|
||||
```bash
|
||||
jj git fetch
|
||||
jj new 'main@origin' -m "Start feature X"
|
||||
```
|
||||
|
||||
### Rebase feature onto updated main
|
||||
|
||||
```bash
|
||||
jj git fetch
|
||||
jj rebase -s <feature-root> -d 'main@origin'
|
||||
```
|
||||
|
||||
### Push new feature for review
|
||||
|
||||
```bash
|
||||
jj bookmark create my-feature -r @
|
||||
jj git push --bookmark my-feature
|
||||
```
|
||||
|
||||
### Update PR after review
|
||||
|
||||
```bash
|
||||
# Make changes...
|
||||
jj bookmark set my-feature -r @
|
||||
jj git push --bookmark my-feature
|
||||
```
|
||||
|
||||
### Delete remote branch after merge
|
||||
|
||||
```bash
|
||||
jj bookmark delete my-feature
|
||||
jj git push --bookmark my-feature --allow-delete
|
||||
```
|
||||
143
skills/working-with-jj/references/revsets.md
Normal file
143
skills/working-with-jj/references/revsets.md
Normal file
@@ -0,0 +1,143 @@
|
||||
# Revsets Reference
|
||||
|
||||
Revsets are JJ's query language for selecting revisions.
|
||||
|
||||
```bash
|
||||
jj help -k revsets # Official documentation
|
||||
```
|
||||
|
||||
## Basic Selectors
|
||||
|
||||
```bash
|
||||
@ # Working copy
|
||||
@- # Parent of @
|
||||
@-- # Grandparent
|
||||
root() # Root commit (empty ancestor)
|
||||
<change-id> # By change ID (e.g., abc, xyzmno)
|
||||
<commit-id> # By commit hash
|
||||
```
|
||||
|
||||
## Ancestry Operators
|
||||
|
||||
```bash
|
||||
::@ # All ancestors of @ (inclusive)
|
||||
@:: # All descendants of @ (inclusive)
|
||||
@-:: # Descendants of parent (siblings and their children)
|
||||
<from>::<to> # Range from..to (inclusive both ends)
|
||||
|
||||
# Exclusive variants
|
||||
@- # Immediate parents only
|
||||
@+ # Immediate children only
|
||||
```
|
||||
|
||||
## Filter Functions
|
||||
|
||||
```bash
|
||||
mine() # Your changes (by author)
|
||||
heads(all()) # All head revisions (no children)
|
||||
roots(<revset>) # Roots of given revset
|
||||
empty() # Empty revisions (no diff)
|
||||
conflict() # Revisions with unresolved conflicts
|
||||
immutable() # Immutable revisions (usually main, tags)
|
||||
mutable() # Mutable revisions
|
||||
|
||||
# Text matching
|
||||
description(substring:"text") # Match in description
|
||||
description(exact:"text") # Exact description match
|
||||
author(substring:"name") # Match author name/email
|
||||
committer(substring:"name") # Match committer
|
||||
|
||||
# File-based
|
||||
file("path/to/file") # Revisions that modified this file
|
||||
file("glob:src/*.rs") # Glob pattern matching
|
||||
```
|
||||
|
||||
## Set Operations
|
||||
|
||||
```bash
|
||||
A | B # Union: revisions in A OR B
|
||||
A & B # Intersection: revisions in A AND B
|
||||
A ~ B # Difference: revisions in A but NOT in B
|
||||
~A # Complement: all revisions NOT in A
|
||||
```
|
||||
|
||||
## Useful Patterns
|
||||
|
||||
### Working with branches
|
||||
|
||||
```bash
|
||||
# Your work on current line
|
||||
mine() & ::@
|
||||
|
||||
# What's on this branch but not in main
|
||||
::@ ~ ::main
|
||||
|
||||
# Heads of your work (tips)
|
||||
heads(mine())
|
||||
|
||||
# All your unmerged work
|
||||
mine() ~ ::main
|
||||
```
|
||||
|
||||
### Finding specific changes
|
||||
|
||||
```bash
|
||||
# Changes to a specific file
|
||||
file("src/lib.rs")
|
||||
|
||||
# Your changes to src/ directory
|
||||
file("src/") & mine()
|
||||
|
||||
# Empty TODO commits
|
||||
empty() & description(substring:"[todo]")
|
||||
|
||||
# Commits with conflicts
|
||||
conflict()
|
||||
```
|
||||
|
||||
### Navigation
|
||||
|
||||
```bash
|
||||
# Recent commits (last 10 by default in log)
|
||||
@ | @- | @-- | @---
|
||||
|
||||
# All siblings (same parent as @)
|
||||
@-:: ~ @::
|
||||
|
||||
# Common ancestor of two revisions
|
||||
heads(::A & ::B)
|
||||
```
|
||||
|
||||
### Remote tracking
|
||||
|
||||
```bash
|
||||
# Remote main
|
||||
main@origin
|
||||
|
||||
# What's in remote but not local
|
||||
::main@origin ~ ::main
|
||||
|
||||
# What's local but not pushed
|
||||
::main ~ ::main@origin
|
||||
```
|
||||
|
||||
## Quoting in Shell
|
||||
|
||||
Revsets with special characters need shell quoting:
|
||||
|
||||
```bash
|
||||
# ❌ Shell interprets parentheses and quotes
|
||||
jj log -r description(substring:"[todo]")
|
||||
|
||||
# ✅ Single quotes protect everything
|
||||
jj log -r 'description(substring:"[todo]")'
|
||||
|
||||
# ✅ Double quotes with escaping
|
||||
jj log -r "description(substring:\"[todo]\")"
|
||||
|
||||
# ✅ Simple revsets don't need quotes
|
||||
jj log -r mine
|
||||
jj log -r @-
|
||||
```
|
||||
|
||||
**Rule:** When in doubt, wrap the entire revset in single quotes.
|
||||
177
skills/working-with-jj/references/templates.md
Normal file
177
skills/working-with-jj/references/templates.md
Normal file
@@ -0,0 +1,177 @@
|
||||
# Templates Reference
|
||||
|
||||
Templates control JJ's output formatting.
|
||||
|
||||
```bash
|
||||
jj help -k templates # Official documentation
|
||||
```
|
||||
|
||||
## Built-in Templates
|
||||
|
||||
```bash
|
||||
# For jj log
|
||||
builtin_log_compact # Default compact view
|
||||
builtin_log_detailed # Full details with diff
|
||||
builtin_log_oneline # Single line per revision
|
||||
|
||||
# For jj evolog
|
||||
builtin_evolog_compact # Default evolution log
|
||||
|
||||
# For jj op log
|
||||
builtin_op_log_compact # Operation log
|
||||
```
|
||||
|
||||
## Context Separation
|
||||
|
||||
**Critical:** Different commands have different template contexts.
|
||||
|
||||
### Log Templates (revision context)
|
||||
|
||||
```bash
|
||||
# Direct access to revision properties
|
||||
change_id # Full change ID
|
||||
change_id.short() # Short form (default 12 chars)
|
||||
change_id.shortest() # Shortest unique prefix
|
||||
commit_id # Git commit hash
|
||||
description # Full description
|
||||
description.first_line() # First line only
|
||||
author # Author info
|
||||
author.name() # Author name
|
||||
author.email() # Author email
|
||||
author.timestamp() # Author timestamp
|
||||
committer # Committer info (same methods)
|
||||
empty # Boolean: is empty?
|
||||
conflict # Boolean: has conflicts?
|
||||
```
|
||||
|
||||
### Evolog Templates (commit context)
|
||||
|
||||
```bash
|
||||
# Must go through commit object
|
||||
commit.change_id()
|
||||
commit.commit_id()
|
||||
commit.description()
|
||||
commit.author()
|
||||
# etc.
|
||||
```
|
||||
|
||||
### Op Log Templates (operation context)
|
||||
|
||||
```bash
|
||||
self.id() # Operation ID
|
||||
self.id().short(12) # Short operation ID
|
||||
self.description() # What the operation did
|
||||
self.time() # When it happened
|
||||
self.user() # Who did it
|
||||
```
|
||||
|
||||
## Template Language
|
||||
|
||||
### String Concatenation
|
||||
|
||||
```bash
|
||||
# Use ++ to join strings
|
||||
change_id.shortest(8) ++ " " ++ description.first_line()
|
||||
```
|
||||
|
||||
### Conditionals
|
||||
|
||||
```bash
|
||||
# if(condition, then, else)
|
||||
if(conflict, "⚠️ ", "")
|
||||
if(empty, "(empty)", description.first_line())
|
||||
```
|
||||
|
||||
### Methods
|
||||
|
||||
```bash
|
||||
# Strings
|
||||
description.first_line()
|
||||
description.lines() # List of lines
|
||||
"text".contains("x")
|
||||
"text".starts_with("x")
|
||||
|
||||
# IDs
|
||||
change_id.short() # Default length
|
||||
change_id.short(6) # Specific length
|
||||
change_id.shortest() # Minimum unique
|
||||
change_id.shortest(4) # Minimum 4 chars
|
||||
|
||||
# Timestamps
|
||||
timestamp.ago() # "2 hours ago"
|
||||
timestamp.format("%Y-%m-%d") # Custom format
|
||||
```
|
||||
|
||||
### Special Output
|
||||
|
||||
```bash
|
||||
# JSON output (for scripting)
|
||||
jj log -T "json(self)"
|
||||
|
||||
# Diff statistics
|
||||
diff.stat(72) # Stat with max width
|
||||
|
||||
# Labels for coloring
|
||||
label("keyword", "text")
|
||||
```
|
||||
|
||||
## Useful Custom Templates
|
||||
|
||||
### Compact one-liner
|
||||
|
||||
```bash
|
||||
jj log -T 'change_id.shortest(8) ++ " " ++ description.first_line() ++ "\n"'
|
||||
```
|
||||
|
||||
### With status indicators
|
||||
|
||||
```bash
|
||||
jj log -T '
|
||||
change_id.shortest(8)
|
||||
++ if(conflict, " ⚠️", "")
|
||||
++ if(empty, " ∅", "")
|
||||
++ " " ++ description.first_line()
|
||||
++ "\n"
|
||||
'
|
||||
```
|
||||
|
||||
### Files changed
|
||||
|
||||
```bash
|
||||
jj log -T 'change_id.shortest(8) ++ "\n" ++ diff.stat(72)'
|
||||
```
|
||||
|
||||
### For scripting (parseable)
|
||||
|
||||
```bash
|
||||
# Tab-separated
|
||||
jj log -T 'change_id.short() ++ "\t" ++ description.first_line() ++ "\n"' --no-graph
|
||||
|
||||
# JSON
|
||||
jj log -T "json(self)" --no-graph
|
||||
```
|
||||
|
||||
### Operation IDs for checkpoints
|
||||
|
||||
```bash
|
||||
jj op log -T 'self.id().short(12) ++ " " ++ self.description() ++ "\n"' --no-graph -n5
|
||||
```
|
||||
|
||||
## Config File Templates
|
||||
|
||||
Define reusable templates in `~/.jjconfig.toml`:
|
||||
|
||||
```toml
|
||||
[templates]
|
||||
log = 'change_id.shortest(8) ++ " " ++ description.first_line()'
|
||||
|
||||
[template-aliases]
|
||||
'format_short_id(id)' = 'id.shortest(8)'
|
||||
```
|
||||
|
||||
Then use with:
|
||||
|
||||
```bash
|
||||
jj log -T log
|
||||
# or reference alias in other templates
|
||||
```
|
||||
294
skills/working-with-jj/references/todo-workflow.md
Normal file
294
skills/working-with-jj/references/todo-workflow.md
Normal file
@@ -0,0 +1,294 @@
|
||||
# TODO Commit Workflow
|
||||
|
||||
Empty revisions as TODO markers enable structured development with clear milestones. Descriptions act as specifications for what to implement.
|
||||
|
||||
## Core Concept
|
||||
|
||||
```bash
|
||||
# Create empty TODO (stays on current @)
|
||||
jj-todo-create @ "Feature X" "Detailed specs of what to implement"
|
||||
|
||||
# Later, work on it
|
||||
jj edit <todo-change-id>
|
||||
|
||||
# Update status as you progress
|
||||
jj-flag-update @ wip
|
||||
```
|
||||
|
||||
## Status Flags
|
||||
|
||||
Use description prefixes to track status at a glance:
|
||||
|
||||
| Flag | Meaning |
|
||||
|------|---------|
|
||||
| `[todo]` | Not started, empty revision |
|
||||
| `[wip]` | Work in progress |
|
||||
| `[untested]` | Implementation done, tests missing |
|
||||
| `[broken]` | Tests failing, needs fixing |
|
||||
| `[review]` | Needs review (tricky code, design choice) |
|
||||
| (none) | Complete |
|
||||
|
||||
### Updating Flags
|
||||
|
||||
```bash
|
||||
# Using script (auto-detects current flag)
|
||||
jj-flag-update @ wip
|
||||
jj-flag-update @ untested
|
||||
jj-flag-update @ done # "done" removes the flag
|
||||
|
||||
# Manual (what the script does)
|
||||
jj log -r @ -n1 --no-graph -T description | sed 's/\[todo\]/[wip]/' | jj desc -r @ --stdin
|
||||
```
|
||||
|
||||
### Finding Flagged Revisions
|
||||
|
||||
```bash
|
||||
jj-find-flagged # All flagged
|
||||
jj-find-flagged todo # Only [todo]
|
||||
jj-find-flagged wip # Only [wip]
|
||||
|
||||
# Manual
|
||||
jj log -r 'description(substring:"[todo]")'
|
||||
```
|
||||
|
||||
## Basic Workflow
|
||||
|
||||
### 1. Plan: Create TODO Chain
|
||||
|
||||
```bash
|
||||
# Create linear chain of tasks
|
||||
jj-todo-create @ "Task 1: Setup data model"
|
||||
jj-todo-create <T1-id> "Task 2: Implement core logic"
|
||||
jj-todo-create <T2-id> "Task 3: Add API endpoints"
|
||||
jj-todo-create <T3-id> "Task 4: Write tests"
|
||||
```
|
||||
|
||||
### 2. Work: Edit Each TODO
|
||||
|
||||
```bash
|
||||
# Read the specs
|
||||
jj-show-desc <task-id>
|
||||
|
||||
# Start working on it
|
||||
jj edit <task-id>
|
||||
jj-flag-update @ wip
|
||||
|
||||
# ... implement ...
|
||||
|
||||
# Mark progress
|
||||
jj-flag-update @ untested
|
||||
```
|
||||
|
||||
### 3. Complete and Move to Next
|
||||
|
||||
```bash
|
||||
# After validation passes, complete current and start next TODO
|
||||
jj-todo-done
|
||||
|
||||
# If there are multiple next TODOs (parallel branches), it will list them:
|
||||
# Multiple next TODOs available. Choose one:
|
||||
# abc123 [todo] Widget A
|
||||
# def456 [todo] Widget B
|
||||
#
|
||||
# Then specify which one:
|
||||
jj-todo-done abc123
|
||||
```
|
||||
|
||||
The script handles the full transition: marks current as done, edits the next revision, sets it to `[wip]`, and prints its description so you can start working.
|
||||
|
||||
## Parallel Tasks (DAG)
|
||||
|
||||
Create branches that can be worked independently:
|
||||
|
||||
```bash
|
||||
# Linear foundation
|
||||
jj-todo-create @ "Task 1: Core infrastructure"
|
||||
jj-todo-create <T1-id> "Task 2: Base components"
|
||||
|
||||
# Parallel branches from Task 2
|
||||
jj-parallel-todos <T2-id> "Widget A" "Widget B" "Widget C"
|
||||
|
||||
# Merge point (all three must complete first)
|
||||
jj new --no-edit <A-id> <B-id> <C-id> -m "[todo] Integration"
|
||||
```
|
||||
|
||||
**Result:**
|
||||
```
|
||||
[todo] Integration
|
||||
/ | \
|
||||
Widget A Widget B Widget C
|
||||
\ | /
|
||||
Task 2: Base
|
||||
|
|
||||
Task 1: Core
|
||||
```
|
||||
|
||||
No rebasing needed - parents specified directly!
|
||||
|
||||
## Writing Good TODO Descriptions
|
||||
|
||||
### Structure
|
||||
|
||||
```
|
||||
[todo] Short title (< 50 chars)
|
||||
|
||||
## Context
|
||||
Why this task exists, what problem it solves.
|
||||
|
||||
## Requirements
|
||||
- Specific requirement 1
|
||||
- Specific requirement 2
|
||||
|
||||
## Implementation notes
|
||||
Any hints, constraints, or approaches to consider.
|
||||
|
||||
## Acceptance criteria
|
||||
How to know when this is done.
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
```
|
||||
[todo] Implement user authentication
|
||||
|
||||
## Context
|
||||
Users need to log in to access their data. Using JWT tokens
|
||||
for stateless auth.
|
||||
|
||||
## Requirements
|
||||
- POST /auth/login accepts email + password
|
||||
- Returns JWT token valid for 24h
|
||||
- POST /auth/refresh extends token
|
||||
- Invalid credentials return 401
|
||||
|
||||
## Implementation notes
|
||||
- Use bcrypt for password hashing
|
||||
- Store refresh tokens in Redis
|
||||
- See auth.md for token format spec
|
||||
|
||||
## Acceptance criteria
|
||||
- All auth endpoints return correct status codes
|
||||
- Tokens expire correctly
|
||||
- Rate limiting prevents brute force
|
||||
```
|
||||
|
||||
## Documenting Implementation Deviations
|
||||
|
||||
When implementation differs from specs, document it:
|
||||
|
||||
```bash
|
||||
# After implementing, add implementation notes
|
||||
jj desc -r @ -m "$(jj-show-desc @)
|
||||
|
||||
## Implementation
|
||||
- Used argon2 instead of bcrypt (more secure)
|
||||
- Added /auth/logout endpoint (not in original spec)
|
||||
- Rate limit: 5 attempts per minute (was unspecified)
|
||||
"
|
||||
```
|
||||
|
||||
This creates an audit trail of decisions.
|
||||
|
||||
## AI-Assisted TODO Workflow
|
||||
|
||||
TODOs work great with AI assistants:
|
||||
|
||||
### Setup Phase (Human)
|
||||
|
||||
```bash
|
||||
# Human creates the plan
|
||||
jj-todo-create @ "Refactor auth module" "
|
||||
## Requirements
|
||||
- Extract auth logic from handlers
|
||||
- Create AuthService class
|
||||
- Add unit tests
|
||||
- Update API docs
|
||||
"
|
||||
```
|
||||
|
||||
### Execution Phase (AI)
|
||||
|
||||
```bash
|
||||
# AI reads the task
|
||||
jj-show-desc <todo-id>
|
||||
|
||||
# AI checkpoints before starting
|
||||
jj-checkpoint "before-auth-refactor"
|
||||
|
||||
# AI edits the revision
|
||||
jj edit <todo-id>
|
||||
jj-flag-update @ wip
|
||||
|
||||
# ... AI implements ...
|
||||
|
||||
# AI marks complete
|
||||
jj-flag-update @ untested
|
||||
```
|
||||
|
||||
### Review Phase (Human)
|
||||
|
||||
```bash
|
||||
# Human reviews what AI did
|
||||
jj evolog -r <todo-id> --git
|
||||
|
||||
# If bad, restore checkpoint
|
||||
jj op restore <checkpoint-op-id>
|
||||
|
||||
# If good but needs splitting
|
||||
jj split -r <todo-id>
|
||||
```
|
||||
|
||||
## Tips
|
||||
|
||||
### Keep TODOs Small
|
||||
|
||||
Each TODO should be completable in one focused session. If it's too big, split into multiple TODOs.
|
||||
|
||||
### Use `--no-edit` Religiously
|
||||
|
||||
When creating TODOs, always use `jj-todo-create` or `jj new --no-edit`. Otherwise @ moves and you lose your place.
|
||||
|
||||
### Validate Between Steps
|
||||
|
||||
After completing each TODO, run your project's validation (typecheck, lint, tests) before moving to the next:
|
||||
|
||||
```bash
|
||||
# Verify current work (use your project's commands)
|
||||
make check # or: cargo build, pnpm tsc, go build, etc.
|
||||
|
||||
# Then complete and move to next
|
||||
jj-todo-done
|
||||
```
|
||||
|
||||
This catches errors early when context is fresh, rather than debugging cascading failures at the end.
|
||||
|
||||
### Watch for Hidden Dependencies
|
||||
|
||||
When planning TODOs that touch service/module layers (especially with dependency injection), dependencies between components may not be obvious until you validate. A component might require a service you're modifying or replacing.
|
||||
|
||||
If a later TODO fails due to missing dependencies from an earlier one, don't forget to edit the description to make clear the extra work you had to do which wasn't in the specs.
|
||||
|
||||
The upfront planning helps surface these, but some will only appear at validation time.
|
||||
|
||||
### Check DAG Before Starting
|
||||
|
||||
```bash
|
||||
# Visualize the plan
|
||||
jj log -r '<first-todo>::'
|
||||
```
|
||||
|
||||
### Reorder if Needed
|
||||
|
||||
If you realize task order is wrong:
|
||||
|
||||
```bash
|
||||
# Move Task B to be after Task C instead of Task A
|
||||
jj rebase -r <B-id> -d <C-id>
|
||||
```
|
||||
|
||||
### Abandon Obsolete TODOs
|
||||
|
||||
```bash
|
||||
# If a TODO is no longer needed
|
||||
jj abandon <todo-id>
|
||||
```
|
||||
29
skills/working-with-jj/scripts/jj-batch-desc
Executable file
29
skills/working-with-jj/scripts/jj-batch-desc
Executable file
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env bash
|
||||
# Apply transformation to multiple revisions
|
||||
# Usage: jj-batch-desc <SED_SCRIPT_FILE> <REV1> [REV2...]
|
||||
# Example: jj-batch-desc /tmp/replacements.sed abc xyz mno
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -lt 2 ]]; then
|
||||
echo "Usage: jj-batch-desc <SED_SCRIPT_FILE> <REV1> [REV2...]" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sed_script="$1"
|
||||
shift
|
||||
|
||||
if [[ ! -f "$sed_script" ]]; then
|
||||
echo "Error: sed script not found: $sed_script" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for rev in "$@"; do
|
||||
echo "Processing $rev..."
|
||||
tmpfile="/tmp/jj_desc_${rev}_$$.txt"
|
||||
jj log -r "$rev" -n1 --no-graph -T description > "$tmpfile"
|
||||
sed -f "$sed_script" "$tmpfile" | jj desc -r "$rev" --stdin
|
||||
rm -f "$tmpfile"
|
||||
done
|
||||
|
||||
echo "✅ Processed $# revision(s)"
|
||||
18
skills/working-with-jj/scripts/jj-checkpoint
Normal file
18
skills/working-with-jj/scripts/jj-checkpoint
Normal file
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
# Create a named checkpoint before risky operations
|
||||
# Usage: jj-checkpoint [NAME]
|
||||
# Later restore with: jj op restore <op-id>
|
||||
# NAME defaults to "checkpoint"
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
name="${1:-checkpoint}"
|
||||
|
||||
# Get current operation ID
|
||||
op_id=$(jj op log -n1 --no-graph -T 'self.id().short(12)')
|
||||
|
||||
echo "📍 Checkpoint '$name' at operation: $op_id"
|
||||
echo " Restore with: jj op restore $op_id"
|
||||
echo ""
|
||||
echo " Current state:"
|
||||
jj log -r @ -n1 -T 'change_id.shortest(8) ++ " " ++ description.first_line()'
|
||||
17
skills/working-with-jj/scripts/jj-desc-transform
Executable file
17
skills/working-with-jj/scripts/jj-desc-transform
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env bash
|
||||
# Transform revision description through a command
|
||||
# Usage: jj-desc-transform <REV> <COMMAND...>
|
||||
# Example: jj-desc-transform @ sed 's/foo/bar/'
|
||||
# Example: jj-desc-transform mxyz awk '/^##/{print; next} {print " "$0}'
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -lt 2 ]]; then
|
||||
echo "Usage: jj-desc-transform <REV> <COMMAND...>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rev="$1"
|
||||
shift
|
||||
|
||||
jj log -r "$rev" -n1 --no-graph -T description | "$@" | jj desc -r "$rev" --stdin
|
||||
16
skills/working-with-jj/scripts/jj-find-flagged
Executable file
16
skills/working-with-jj/scripts/jj-find-flagged
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
# Find revisions with status flags
|
||||
# Usage: jj-find-flagged [FLAG]
|
||||
# FLAG: todo, wip, untested, broken, review (omit for all flagged)
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
flag="${1:-}"
|
||||
|
||||
if [[ -n "$flag" ]]; then
|
||||
# Use substring match instead of glob for specific flag
|
||||
jj log -r "description(substring:\"[${flag}]\")"
|
||||
else
|
||||
# All flagged revisions - match common flags
|
||||
jj log -r 'description(substring:"[todo]") | description(substring:"[wip]") | description(substring:"[untested]") | description(substring:"[broken]") | description(substring:"[review]")'
|
||||
fi
|
||||
52
skills/working-with-jj/scripts/jj-flag-update
Executable file
52
skills/working-with-jj/scripts/jj-flag-update
Executable file
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env bash
|
||||
# Update status flag in revision description
|
||||
# Usage: jj-flag-update <REV> <TO_FLAG>
|
||||
# TO_FLAG is: todo, wip, untested, broken, review, or "done" (removes flag)
|
||||
# Example: jj-flag-update @ wip
|
||||
# Example: jj-flag-update mxyz done
|
||||
#
|
||||
# Automatically detects the current flag and replaces it.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -ne 2 ]]; then
|
||||
echo "Usage: jj-flag-update <REV> <TO_FLAG>" >&2
|
||||
echo "Flags: todo, wip, untested, broken, review, done (done removes flag)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rev="$1"
|
||||
to_flag="$2"
|
||||
|
||||
# Get current description
|
||||
desc=$(jj log -r "$rev" -n1 --no-graph -T description)
|
||||
|
||||
# Detect current flag
|
||||
current_flag=""
|
||||
for flag in todo wip untested broken review; do
|
||||
if [[ "$desc" =~ ^\[${flag}\] ]]; then
|
||||
current_flag="$flag"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ -z "$current_flag" ]]; then
|
||||
if [[ "$to_flag" == "done" ]]; then
|
||||
# No flag to remove, nothing to do
|
||||
exit 0
|
||||
else
|
||||
# No current flag - prepend the new one
|
||||
echo "[${to_flag}] ${desc}" | jj desc -r "$rev" --stdin
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Build sed pattern
|
||||
if [[ "$to_flag" == "done" ]]; then
|
||||
# Remove the flag (and trailing space)
|
||||
sed_pattern="s/\[${current_flag}\] //"
|
||||
else
|
||||
sed_pattern="s/\[${current_flag}\]/[${to_flag}]/"
|
||||
fi
|
||||
|
||||
echo "$desc" | sed "$sed_pattern" | jj desc -r "$rev" --stdin
|
||||
20
skills/working-with-jj/scripts/jj-parallel-todos
Executable file
20
skills/working-with-jj/scripts/jj-parallel-todos
Executable file
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env bash
|
||||
# Create multiple parallel TODO branches from same parent
|
||||
# Usage: jj-parallel-todos <PARENT> <TITLE1> <TITLE2> [TITLE3...]
|
||||
# Example: jj-parallel-todos @ "Widget A" "Widget B" "Widget C"
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -lt 2 ]]; then
|
||||
echo "Usage: jj-parallel-todos <PARENT> <TITLE1> <TITLE2> [TITLE3...]" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
parent="$1"
|
||||
shift
|
||||
|
||||
for title in "$@"; do
|
||||
jj new --no-edit "$parent" -m "[todo] ${title}"
|
||||
done
|
||||
|
||||
echo "✅ Created $# parallel TODO branches from $parent"
|
||||
9
skills/working-with-jj/scripts/jj-show-desc
Executable file
9
skills/working-with-jj/scripts/jj-show-desc
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
# Get revision description only (for reading or piping)
|
||||
# Usage: jj-show-desc [REV]
|
||||
# REV defaults to @
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
rev="${1:-@}"
|
||||
jj log -r "$rev" -n1 --no-graph -T description
|
||||
9
skills/working-with-jj/scripts/jj-show-detailed
Executable file
9
skills/working-with-jj/scripts/jj-show-detailed
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
# Show detailed revision info with diff
|
||||
# Usage: jj-show-detailed [REV]
|
||||
# REV defaults to @
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
rev="${1:-@}"
|
||||
jj log -r "$rev" -n1 --no-graph -T builtin_log_detailed --git
|
||||
25
skills/working-with-jj/scripts/jj-todo-create
Executable file
25
skills/working-with-jj/scripts/jj-todo-create
Executable file
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env bash
|
||||
# Create empty TODO revision without editing (stays on current @)
|
||||
# Usage: jj-todo-create <PARENT> <TITLE> [DESCRIPTION]
|
||||
# Example: jj-todo-create @ "implement feature X" "detailed specs here"
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -lt 2 ]]; then
|
||||
echo "Usage: jj-todo-create <PARENT> <TITLE> [DESCRIPTION]" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
parent="$1"
|
||||
title="$2"
|
||||
description="${3:-}"
|
||||
|
||||
if [[ -n "$description" ]]; then
|
||||
msg="[todo] ${title}
|
||||
|
||||
${description}"
|
||||
else
|
||||
msg="[todo] ${title}"
|
||||
fi
|
||||
|
||||
jj new --no-edit "$parent" -m "$msg"
|
||||
64
skills/working-with-jj/scripts/jj-todo-done
Executable file
64
skills/working-with-jj/scripts/jj-todo-done
Executable file
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env bash
|
||||
# Complete current TODO and optionally start the next one
|
||||
# Usage: jj-todo-done [NEXT_REV]
|
||||
#
|
||||
# If NEXT_REV is provided, starts working on that revision.
|
||||
# If not provided, lists possible next TODOs (children of current) and exits.
|
||||
#
|
||||
# Example:
|
||||
# jj-todo-done # Complete current, show next options
|
||||
# jj-todo-done abc123 # Complete current, start working on abc123
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPTS_DIR="$(dirname "$0")"
|
||||
|
||||
# Mark current as done (auto-detects current flag)
|
||||
"$SCRIPTS_DIR/jj-flag-update" @ done
|
||||
|
||||
current=$(jj log -r @ --no-graph -T 'change_id.shortest(8)')
|
||||
|
||||
# Find children that are TODOs (have any flag)
|
||||
children=$(jj log -r "children(@) & description(substring:\"[todo]\")" --no-graph -T 'change_id.shortest(8) ++ "\n"' 2>/dev/null || true)
|
||||
|
||||
if [[ -n "${1:-}" ]]; then
|
||||
# User specified next revision
|
||||
next="$1"
|
||||
jj edit "$next"
|
||||
"$SCRIPTS_DIR/jj-flag-update" @ wip
|
||||
echo ""
|
||||
echo "📋 Starting TODO:"
|
||||
echo "─────────────────"
|
||||
"$SCRIPTS_DIR/jj-show-desc" @
|
||||
elif [[ -z "$children" ]]; then
|
||||
echo "✅ Completed: $current"
|
||||
echo ""
|
||||
echo "No pending TODO children found. You may be done with this chain!"
|
||||
echo ""
|
||||
echo "Check remaining TODOs with:"
|
||||
echo " jj-find-flagged todo"
|
||||
elif [[ $(echo "$children" | wc -l) -eq 1 ]]; then
|
||||
# Single child - start it automatically
|
||||
next=$(echo "$children" | tr -d '[:space:]')
|
||||
echo "✅ Completed: $current"
|
||||
echo ""
|
||||
jj edit "$next"
|
||||
"$SCRIPTS_DIR/jj-flag-update" @ wip
|
||||
echo ""
|
||||
echo "📋 Starting TODO:"
|
||||
echo "─────────────────"
|
||||
"$SCRIPTS_DIR/jj-show-desc" @
|
||||
else
|
||||
# Multiple children - list them for user to choose
|
||||
echo "✅ Completed: $current"
|
||||
echo ""
|
||||
echo "Multiple next TODOs available. Choose one:"
|
||||
echo ""
|
||||
while IFS= read -r child; do
|
||||
[[ -z "$child" ]] && continue
|
||||
title=$(jj log -r "$child" --no-graph -T 'description.first_line()' 2>/dev/null || echo "(no description)")
|
||||
echo " $child $title"
|
||||
done <<< "$children"
|
||||
echo ""
|
||||
echo "Run: jj-todo-done <change-id>"
|
||||
fi
|
||||
Reference in New Issue
Block a user