Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:17:51 +08:00
commit 70011f3c64
8 changed files with 1940 additions and 0 deletions

462
references/commands.md Normal file
View File

@@ -0,0 +1,462 @@
# Commands Reference
Complete reference for jj commands and their options.
## Table of Contents
- [Repository Setup](#repository-setup)
- [Status and History](#status-and-history)
- [Creating and Editing Commits](#creating-and-editing-commits)
- [History Rewriting](#history-rewriting)
- [Bookmarks (Branches)](#bookmarks-branches)
- [Git Operations](#git-operations)
- [Operation Log](#operation-log)
- [File Operations](#file-operations)
- [Workspaces](#workspaces)
- [Configuration](#configuration)
## Repository Setup
### `jj git clone`
Clone a Git repository:
```bash
jj git clone <url> [destination]
jj git clone --colocate <url> # Allow git commands (default)
jj git clone --no-colocate <url> # jj-only repo
jj git clone --branch <branch> # Clone specific branch
jj git clone --depth <n> # Shallow clone
```
### `jj git init`
Initialize a new repository:
```bash
jj git init # New colocated repo (default)
jj git init --no-colocate # New jj-only repo
jj git init --git-repo <path> # Use existing git repo as backend
```
## Status and History
### `jj status` (alias: `st`)
Show working copy status:
```bash
jj status
jj st [paths...] # Status for specific paths
```
### `jj log`
Show commit history:
```bash
jj log # Default: mutable commits
jj log -r <revset> # Specific revisions
jj log -r '::' # All commits
jj log -n 10 # Limit to 10 commits
jj log -p # Show patches
jj log -s # Summary (files changed)
jj log --stat # Show diffstat
jj log --no-graph # Flat list, no graph
jj log --reversed # Oldest first
jj log -T <template> # Custom template
jj log [paths...] # Commits touching paths
```
### `jj show`
Show commit details:
```bash
jj show # Current working copy
jj show <rev> # Specific revision
jj show -s # Summary only
jj show -p # Patch (default)
jj show --stat # Diffstat
jj show --git # Git-format diff
```
### `jj diff`
Show changes:
```bash
jj diff # Changes in working copy
jj diff -r <rev> # Changes in revision vs parent
jj diff --from <rev> # From specific revision
jj diff --to <rev> # To specific revision
jj diff --from <A> --to <B> # Between two revisions
jj diff -s # Summary
jj diff --stat # Diffstat
jj diff --git # Git format
jj diff --color-words # Word-level diff
jj diff [paths...] # Specific paths only
```
## Creating and Editing Commits
### `jj new`
Create a new commit:
```bash
jj new # New commit on working copy parent
jj new <rev> # New commit on specific revision
jj new <A> <B> # Merge commit with multiple parents
jj new -m "message" # With description
jj new --no-edit # Don't make it working copy
jj new -A <rev> # Insert after revision
jj new -B <rev> # Insert before revision
```
### `jj describe` (alias: `desc`)
Edit commit description:
```bash
jj describe # Edit working copy description
jj describe <rev> # Edit specific revision
jj describe -m "message" # Set message directly
jj describe --stdin # Read from stdin
```
### `jj edit`
Switch working copy to edit existing commit:
```bash
jj edit <rev> # Edit specific revision
```
### `jj commit` (alias: `ci`)
Finalize working copy and create new commit:
```bash
jj commit # Describe and create new
jj commit -m "message" # With message
jj commit -i # Interactive selection
jj commit [paths...] # Only specified paths
```
## History Rewriting
### `jj squash`
Move changes into parent:
```bash
jj squash # All changes to parent
jj squash -r <rev> # From specific revision
jj squash -i # Interactive selection
jj squash [paths...] # Only specific paths
jj squash --from <A> --into <B> # Between arbitrary commits
jj squash -m "message" # Set combined description
jj squash -k # Keep source (don't abandon)
```
### `jj split`
Split commit into two:
```bash
jj split # Interactive split of working copy
jj split -r <rev> # Split specific revision
jj split [paths...] # Put paths in first commit
jj split -i # Interactive mode
jj split -p # Parallel (sibling) commits
jj split -m "message" # First commit message
```
### `jj rebase`
Move commits to different parents:
```bash
# What to rebase:
jj rebase -b <rev> # Branch containing rev (default: -b @)
jj rebase -s <rev> # Source and descendants
jj rebase -r <rev> # Only revision (not descendants)
# Where to rebase:
jj rebase -d <dest> # Onto destination
jj rebase -A <rev> # Insert after
jj rebase -B <rev> # Insert before
# Examples:
jj rebase -d main # Rebase current branch onto main
jj rebase -s X -d Y # Rebase X and descendants onto Y
jj rebase -r X -d Y # Rebase only X onto Y
jj rebase -r X -A Y # Insert X after Y
jj rebase -r X -B Y # Insert X before Y
# Options:
jj rebase --skip-emptied # Abandon commits that become empty
```
### `jj diffedit`
Interactively edit commit contents:
```bash
jj diffedit # Edit working copy
jj diffedit -r <rev> # Edit specific revision
jj diffedit --from <A> --to <B> # Edit diff between revisions
jj diffedit --tool <tool> # Use specific diff editor
jj diffedit --restore-descendants # Preserve descendant content
```
### `jj duplicate`
Copy commits:
```bash
jj duplicate # Duplicate working copy
jj duplicate <revs> # Duplicate specific revisions
jj duplicate -A <rev> # Insert duplicates after
jj duplicate -B <rev> # Insert duplicates before
```
### `jj abandon`
Remove commits (keep content in descendants):
```bash
jj abandon # Abandon working copy
jj abandon <revs> # Abandon specific revisions
jj abandon --retain-bookmarks # Move bookmarks to parents
```
### `jj restore`
Restore files from another revision:
```bash
jj restore # Restore all from parent
jj restore [paths...] # Restore specific paths
jj restore --from <rev> # Source revision
jj restore --into <rev> # Destination revision
jj restore -c <rev> # Undo changes in revision
jj restore -i # Interactive mode
```
### `jj parallelize`
Make commits siblings instead of parent-child:
```bash
jj parallelize <revs> # Make revisions parallel
```
## Bookmarks (Branches)
### `jj bookmark` (alias: `b`)
Manage bookmarks:
```bash
# List
jj bookmark list
jj bookmark list -a # Include all remotes
jj bookmark list -r <revs> # Bookmarks at revisions
# Create/Set
jj bookmark create <name> # At working copy
jj bookmark create <name> -r <rev>
jj bookmark set <name> # Move to working copy
jj bookmark set <name> -r <rev> # Move to revision
jj bookmark set <name> -B # Allow moving backwards
# Modify
jj bookmark move <name> # Move to working copy
jj bookmark move --from <rev> # Move from revision
jj bookmark rename <old> <new>
# Delete
jj bookmark delete <name> # Delete (will push deletion)
jj bookmark forget <name> # Forget (won't push deletion)
# Remote tracking
jj bookmark track <name>@<remote>
jj bookmark untrack <name>@<remote>
```
## Git Operations
### `jj git fetch`
Fetch from remote:
```bash
jj git fetch # From default remote
jj git fetch --remote <name> # From specific remote
jj git fetch --all-remotes # From all remotes
jj git fetch --branch <pattern> # Specific branches
```
### `jj git push`
Push to remote:
```bash
jj git push --bookmark <name> # Push specific bookmark
jj git push --all # Push all bookmarks
jj git push --tracked # Push all tracked
jj git push --deleted # Push deletions
jj git push --change <rev> # Create bookmark from change
jj git push --remote <name> # To specific remote
jj git push --dry-run # Show what would be pushed
```
### `jj git remote`
Manage remotes:
```bash
jj git remote list
jj git remote add <name> <url>
jj git remote remove <name>
jj git remote rename <old> <new>
jj git remote set-url <name> <url>
```
### `jj git import` / `jj git export`
Sync with underlying Git repo (rarely needed in colocated repos):
```bash
jj git import # Import Git changes to jj
jj git export # Export jj changes to Git
```
## Operation Log
### `jj op log`
View operation history:
```bash
jj op log # Full operation log
jj op log -n 10 # Limit entries
jj op log -p # Show patches
jj op log -d # Show operation diffs
```
### `jj undo` / `jj redo`
Undo/redo operations:
```bash
jj undo # Undo last operation
jj redo # Redo after undo
```
### `jj op restore`
Restore to previous state:
```bash
jj op restore <op-id> # Restore to operation
```
### `jj op show`
Show operation details:
```bash
jj op show # Current operation
jj op show <op-id> # Specific operation
jj op show -p # With patches
```
## File Operations
### `jj file`
File-related commands:
```bash
jj file list # List files in working copy
jj file list -r <rev> # Files in specific revision
jj file show <path> # Show file content
jj file show -r <rev> <path> # Content at revision
jj file annotate <path> # Blame (line origins)
jj file chmod x <path> # Make executable
jj file chmod n <path> # Remove executable
jj file track <paths> # Start tracking
jj file untrack <paths> # Stop tracking
```
## Workspaces
### `jj workspace`
Manage multiple working copies:
```bash
jj workspace list # List workspaces
jj workspace add <path> # Add workspace
jj workspace add -r <rev> <path> # At specific revision
jj workspace forget [name] # Remove workspace
jj workspace root # Show workspace root
jj workspace update-stale # Update stale workspace
```
## Configuration
### `jj config`
Manage configuration:
```bash
jj config list # Show all config
jj config get <key> # Get specific value
jj config set --user <key> <val> # Set user config
jj config set --repo <key> <val> # Set repo config
jj config edit --user # Edit user config
jj config edit --repo # Edit repo config
jj config path --user # Show config file path
```
## Utility Commands
### Other useful commands
```bash
jj root # Show repo root
jj version # Show jj version
jj resolve # Resolve conflicts
jj resolve -l # List conflicts
jj evolog # Show change evolution
jj interdiff --from <A> --to <B> # Compare changes of commits
jj next # Move to child commit
jj prev # Move to parent commit
jj fix # Run code formatters
jj sign # Sign commits
jj sparse set --add <path> # Add to sparse checkout
jj sparse set --remove <path> # Remove from sparse
jj util completion <shell> # Generate shell completions
jj util gc # Garbage collect
```
## Global Options
Available on all commands:
```bash
jj -R <path> # Use different repo
jj --at-op <op-id> # Load at operation
jj --ignore-working-copy # Skip working copy snapshot
jj --ignore-immutable # Allow modifying immutable
jj --color <when> # always/never/auto
jj --no-pager # Disable pager
jj --config <key=value> # Override config
jj --config-file <path> # Additional config file
jj --quiet # Less output
jj --debug # Debug output
```

470
references/configuration.md Normal file
View File

@@ -0,0 +1,470 @@
# Configuration Reference
Comprehensive reference for jj configuration options, templates, filesets, and aliases.
## Table of Contents
- [Config Files](#config-files)
- [User Settings](#user-settings)
- [UI Settings](#ui-settings)
- [Aliases](#aliases)
- [Templates](#templates)
- [Filesets](#filesets)
- [Git Settings](#git-settings)
- [Signing](#signing)
## Config Files
jj loads configuration from multiple sources (in order of precedence):
1. **Built-in** - Cannot be edited
2. **User** - `~/.config/jj/config.toml` or `~/.jjconfig.toml`
3. **Repo** - `.jj/repo/config.toml`
4. **Workspace** - `.jj/workspace-config.toml`
5. **Command-line** - `--config key=value`
```bash
jj config path --user # Show user config path
jj config edit --user # Edit user config
jj config edit --repo # Edit repo config
jj config list # Show all config values
jj config get <key> # Get specific value
```
## User Settings
```toml
[user]
name = "Your Name"
email = "your@email.com"
```
## UI Settings
### Basic UI
```toml
[ui]
# Color output: always, never, auto, debug
color = "auto"
# Default command when running 'jj' with no args
default-command = "log"
# Or with arguments:
default-command = ["log", "--reversed"]
# Pager command
pager = "less -FRX"
# Editor for descriptions
editor = "vim"
# Diff format: :color-words, :git, :summary, :stat, :types, :name-only
diff-formatter = ":color-words"
# Movement commands (next/prev) edit instead of creating new commit
movement.edit = false
```
### Colors and Styles
```toml
[colors]
# Simple foreground color
commit_id = "green"
change_id = "magenta"
# Hex colors
bookmark = "#ff1525"
# Full style specification
commit_id = { fg = "green", bg = "black", bold = true }
change_id = { underline = true, italic = true }
# Combined labels (like CSS selectors)
"working_copy commit_id" = { underline = true }
"conflict description" = "red"
# Diff colors
"diff removed" = "red"
"diff added" = "green"
"diff removed token" = { bg = "#221111", underline = false }
"diff added token" = { bg = "#002200", underline = false }
```
### Diff Options
```toml
[diff.color-words]
# Max removed/added alternation to inline (-1 = all)
max-inline-alternation = 3
# Lines of context
context = 3
[diff.git]
context = 3
```
### External Diff Tools
```toml
[ui]
diff-formatter = ["difft", "--color=always", "$left", "$right"]
# Or reference a named tool:
diff-formatter = "difftastic"
[merge-tools.difftastic]
program = "difft"
diff-args = ["--color=always", "$left", "$right"]
diff-invocation-mode = "dir" # or "file-by-file"
```
## Aliases
### Command Aliases
```toml
[aliases]
# Simple alias
l = ["log", "-r", "@::"]
# Complex alias
show-tree = ["log", "-r", "@::", "--no-graph", "-T", "commit_id.short() ++ ' ' ++ description.first_line()"]
# External command (via util exec)
my-script = ["util", "exec", "--", "my-jj-script"]
# Inline script
format = ["util", "exec", "--", "bash", "-c", """
set -euo pipefail
jj fix
""", ""]
```
### Revset Aliases
```toml
[revset-aliases]
# Custom revsets
'wip' = 'description(exact:"") & mine()'
'stacked' = 'trunk()..@'
'recent' = 'ancestors(@, 20) & mine()'
'feature(x)' = 'bookmarks(glob:"feature-" ++ x ++ "*")::'
# Override built-in trunk() detection
'trunk()' = 'latest(remote_bookmarks(exact:"main", exact:"origin") | remote_bookmarks(exact:"master", exact:"origin"))'
# Customize immutable commits
'immutable_heads()' = 'trunk() | tags()'
```
### Template Aliases
```toml
[template-aliases]
# Custom formatting
'format_short_id(id)' = 'id.shortest(8)'
'format_timestamp(ts)' = 'ts.ago()'
# Custom commit format
'my_log' = '''
change_id.short() ++ " " ++
if(description, description.first_line(), "(no description)") ++
if(conflict, " CONFLICT", "")
'''
```
## Templates
Templates are a functional language for customizing output.
### Log Template
```toml
[templates]
log = 'builtin_log_oneline'
# Or custom:
log = '''
separate(" ",
format_short_change_id_with_hidden_and_divergent_info(self),
format_short_commit_id(commit_id),
bookmarks,
tags,
if(conflict, label("conflict", "conflict")),
if(empty, label("empty", "(empty)")),
if(description, description.first_line(), description_placeholder),
) ++ "\n"
'''
```
### Draft Description Template
```toml
[templates]
draft_commit_description = '''
concat(
builtin_draft_commit_description,
"\nJJ: ignore-rest\n",
diff.git(),
)
'''
[template-aliases]
default_commit_description = '''
"
Closes #NNNN
"
'''
```
### Commit Trailers
```toml
[templates]
commit_trailers = '''
format_signed_off_by_trailer(self)
++ if(!trailers.contains_key("Change-Id"), format_gerrit_change_id_trailer(self))
'''
```
### Template Syntax
```
# Literals
"string"
true / false
42
# Operators
x ++ y # Concatenate
x && y # Logical and
x || y # Logical or
!x # Logical not
x == y # Equality
# Conditionals
if(condition, then, else)
# Functions
separate(sep, items...) # Join non-empty with separator
concat(items...) # Join all items
coalesce(items...) # First non-empty
surround(prefix, suffix, content) # Wrap if non-empty
label(name, content) # Apply color label
indent(prefix, content) # Indent lines
fill(width, content) # Word wrap
```
### Commit Methods
Available in log/show templates:
```
self.commit_id()
self.change_id()
self.description()
self.author()
self.committer()
self.parents()
self.bookmarks()
self.tags()
self.working_copies()
self.conflict()
self.empty()
self.immutable()
self.divergent()
self.hidden()
self.mine()
self.contained_in(revset)
self.diff([fileset])
```
## Filesets
Filesets select files for commands like `jj diff`, `jj split`, `jj squash`.
### Patterns
```bash
# Path prefix (default)
jj diff src # Files under src/
# Exact file
jj diff 'file:README.md'
# Glob patterns
jj diff 'glob:*.rs' # .rs in current dir
jj diff 'glob:**/*.rs' # All .rs files
jj diff 'glob-i:*.TXT' # Case-insensitive
# Root-relative (from repo root)
jj diff 'root:src'
jj diff 'root-glob:**/*.rs'
```
### Operators
```bash
# Negation
jj diff '~Cargo.lock' # Everything except Cargo.lock
# Intersection
jj diff 'src & glob:**/*.rs' # Rust files in src/
# Difference
jj diff 'src ~ glob:**/*.rs' # Non-Rust files in src/
# Union
jj diff 'glob:*.rs | glob:*.toml'
```
### Functions
```bash
all() # All files
none() # No files
```
### Examples
```bash
# Diff excluding lock files
jj diff '~Cargo.lock'
# Split: put all except foo in first commit
jj split '~foo'
# List non-Rust files in src
jj file list 'src ~ glob:**/*.rs'
# Squash only specific files
jj squash 'glob:*.md'
```
## Git Settings
```toml
[git]
# Auto-local-bookmark for new remote bookmarks
auto-local-bookmark = true
# Default push/fetch remote
push = "origin"
fetch = "origin"
# Push bookmark naming template
push-bookmark-prefix = "push-"
# Private commits (won't be pushed)
private-commits = "description(glob:'wip:*')"
# Colocate by default
colocate = true
# Shallow clone depth
shallow-clone-depth = 0 # 0 = full clone
# Fetch tags
fetch-tags = "included" # all, included, none
# Abandon unreachable commits from remote
abandon-unreachable-commits = true
```
## Signing
```toml
[signing]
# Enable signing
sign-all = false
# Signing backend: gpg, ssh, none
backend = "gpg"
# GPG settings
[signing.backends.gpg]
program = "gpg"
# Allow expired keys
allow-expired-keys = false
# SSH settings
[signing.backends.ssh]
program = "ssh-keygen"
# Allowed signers file
allowed-signers = "~/.ssh/allowed_signers"
# Key to use
key = "~/.ssh/id_ed25519.pub"
```
## Immutable Commits
```toml
[revset-aliases]
# Default: trunk and tags are immutable
'immutable_heads()' = 'trunk() | tags()'
# More restrictive: only trunk
'immutable_heads()' = 'trunk()'
# Include release branches
'immutable_heads()' = 'trunk() | tags() | bookmarks(glob:"release-*")'
```
## Fix Tools (Formatters)
```toml
[fix.tools.rustfmt]
command = ["rustfmt", "--emit=stdout"]
patterns = ["glob:'**/*.rs'"]
[fix.tools.black]
command = ["black", "-", "--stdin-filename=$path"]
patterns = ["glob:'**/*.py'"]
[fix.tools.prettier]
command = ["prettier", "--stdin-filepath=$path"]
patterns = ["glob:'**/*.{js,ts,jsx,tsx,json,md}'"]
```
## Merge Tools
```toml
[merge-tools.meld]
program = "meld"
merge-args = ["$left", "$base", "$right", "-o", "$output"]
edit-args = ["$left", "$right"]
[merge-tools.vimdiff]
program = "vim"
merge-args = ["-d", "$left", "$base", "$right", "$output"]
merge-tool-edits-conflict-markers = true
[ui]
merge-editor = "meld"
diff-editor = ":builtin"
```
## Snapshot Settings
```toml
[snapshot]
# Max file size to track (bytes)
max-new-file-size = "1MiB"
# Auto-track patterns (default: all)
auto-track = "all()"
# Or selective:
auto-track = "glob:**/*.rs"
# Watchman integration
use-watchman = "if-available"
```
## Debug Settings
```toml
[debug]
# Randomize commit IDs (for testing)
randomness-seed = ""
```

View File

@@ -0,0 +1,380 @@
# Git to jj Command Comparison
This reference maps common Git commands and workflows to their jj equivalents.
## Quick Reference Table
| Git Command | jj Equivalent | Notes |
|-------------|---------------|-------|
| `git init` | `jj git init` | Creates colocated repo by default |
| `git clone` | `jj git clone` | Creates colocated repo by default |
| `git status` | `jj status` | Alias: `jj st` |
| `git log` | `jj log` | Shows graph by default |
| `git log --oneline` | `jj log --no-graph` | Or customize template |
| `git show` | `jj show` | |
| `git diff` | `jj diff` | |
| `git diff --staged` | N/A | No staging area in jj |
| `git add` | N/A | Auto-tracked |
| `git add -p` | `jj split -i` | Interactive commit splitting |
| `git commit` | `jj commit` or `jj new` | Different workflow |
| `git commit --amend` | `jj describe` + changes | Working copy is always amendable |
| `git commit --amend -m` | `jj describe -m "msg"` | |
| `git reset HEAD~` | `jj squash` | Move changes to parent |
| `git reset --hard` | `jj restore` | |
| `git checkout <file>` | `jj restore <file>` | |
| `git checkout <branch>` | `jj new <bookmark>` | Creates new working copy |
| `git switch` | `jj new` | |
| `git branch` | `jj bookmark` | Alias: `jj b` |
| `git branch -d` | `jj bookmark delete` | |
| `git merge` | `jj new <A> <B>` | Creates merge commit |
| `git rebase` | `jj rebase` | More powerful |
| `git rebase -i` | `jj squash -i`, `jj split` | Different approach |
| `git cherry-pick` | `jj new <rev>; jj squash` | Or `jj duplicate` |
| `git revert` | `jj revert` | |
| `git stash` | N/A | Not needed - use `jj new` |
| `git stash pop` | N/A | Use `jj squash` |
| `git fetch` | `jj git fetch` | |
| `git pull` | `jj git fetch` + `jj rebase` | No single command |
| `git push` | `jj git push` | |
| `git blame` | `jj file annotate` | |
| `git reflog` | `jj op log` | More powerful |
| `git tag` | `jj tag` | |
## Workflow Comparisons
### Creating a New Commit
**Git:**
```bash
git add .
git commit -m "message"
```
**jj:**
```bash
# Changes are auto-tracked
jj describe -m "message"
jj new # Start new work
# Or:
jj commit -m "message" # Same effect
```
### Amending the Last Commit
**Git:**
```bash
git add .
git commit --amend
```
**jj:**
```bash
# Changes automatically amend current working copy
# Just edit files, done!
# To change message:
jj describe -m "new message"
```
### Interactive Staging
**Git:**
```bash
git add -p
git commit
```
**jj:**
```bash
# Split current changes into separate commits
jj split -i
# Or squash parts into parent
jj squash -i
```
### Undoing Last Commit (Keep Changes)
**Git:**
```bash
git reset HEAD~
```
**jj:**
```bash
jj squash # Moves changes to parent, abandons if empty
```
### Discarding Changes
**Git:**
```bash
git checkout -- .
git reset --hard
```
**jj:**
```bash
jj restore # Restore from parent
```
### Switching Branches
**Git:**
```bash
git checkout feature
# or
git switch feature
```
**jj:**
```bash
jj new feature # Create working copy on feature
# Or to edit feature directly:
jj edit feature
```
### Creating a Branch
**Git:**
```bash
git checkout -b feature
# or
git switch -c feature
```
**jj:**
```bash
jj bookmark create feature
# Then work - changes go to working copy
```
### Stashing Changes
**Git:**
```bash
git stash
# ... do other work ...
git stash pop
```
**jj:**
```bash
# Not needed! Working copy is already a commit.
# To work on something else:
jj new main # Start new work from main
# ... do other work ...
jj edit <original-change-id> # Go back
```
### Rebasing a Branch
**Git:**
```bash
git checkout feature
git rebase main
```
**jj:**
```bash
jj rebase -b feature -d main
# Or if on feature:
jj rebase -d main
```
### Interactive Rebase
**Git:**
```bash
git rebase -i HEAD~5
```
**jj:**
```bash
# Different approach - use individual commands:
jj squash # Combine commits
jj split # Split commits
jj rebase # Reorder
jj describe # Edit messages
jj abandon # Drop commits
```
### Cherry-picking
**Git:**
```bash
git cherry-pick <commit>
```
**jj:**
```bash
jj new <commit> # Create child of commit
jj rebase -r @ -d main # Move to destination
# Or simpler:
jj duplicate <commit>
jj rebase -r <duplicated> -d main
```
### Resolving Conflicts
**Git:**
```bash
git merge feature
# Conflicts occur
# Edit files
git add .
git commit
```
**jj:**
```bash
jj new main feature # Create merge (may have conflicts)
# Conflicts are recorded in commit
jj log # Shows conflict marker
# Edit files
# Changes auto-commit, conflict resolved
```
### Undoing Operations
**Git:**
```bash
git reflog
git reset --hard HEAD@{2}
```
**jj:**
```bash
jj op log
jj op restore <op-id>
# Or simply:
jj undo
```
### Viewing History at a Point
**Git:**
```bash
git log HEAD@{yesterday}
```
**jj:**
```bash
jj --at-op=<op-id> log
```
## Conceptual Differences
### No Staging Area
Git has a staging area (index) between working directory and commits. jj doesn't:
- **Git**: working directory → staging area → commit
- **jj**: working copy (IS a commit) → new commit
### Working Copy is a Commit
In jj, the working copy is always a commit. Changes are automatically recorded:
- No "dirty" working directory
- No lost changes from checkout
- Can always undo
### Change IDs vs Commit IDs
- **Git**: Only commit hashes (SHA), change when commit is amended
- **jj**: Change IDs (stable) + Commit IDs (change on rewrite)
Use change IDs (`kntqzsqt`) when referring to commits.
### Conflicts as First-Class Citizens
- **Git**: Conflicts block operations, must resolve immediately
- **jj**: Conflicts are recorded in commits, resolve when convenient
### Operations are Atomic
Every jj operation is recorded and reversible:
```bash
jj op log # See all operations
jj undo # Undo last operation
jj op restore # Go to any point
```
### Bookmarks vs Branches
- **Git branches**: Automatically move with commits
- **jj bookmarks**: Named pointers, move explicitly
```bash
# Git: branch moves with HEAD
git commit # branch advances
# jj: bookmark stays unless moved
jj new # bookmark doesn't move
jj bookmark set <name> # explicit move
```
## Common Patterns
### "Pull and Rebase"
**Git:**
```bash
git pull --rebase
```
**jj:**
```bash
jj git fetch
jj rebase -d <remote>@origin # or main@origin
```
### "Push New Branch"
**Git:**
```bash
git push -u origin feature
```
**jj:**
```bash
jj git push --bookmark feature
# Or create bookmark from change:
jj git push --change <change-id>
```
### "Squash Last N Commits"
**Git:**
```bash
git rebase -i HEAD~3
# Mark commits as squash
```
**jj:**
```bash
# Squash into parent repeatedly:
jj squash -r <commit>
jj squash -r <commit>
# Or use revsets:
jj squash --from 'trunk()..@'
```
### "Edit Old Commit"
**Git:**
```bash
git rebase -i <commit>^
# Mark commit as edit
# Make changes
git commit --amend
git rebase --continue
```
**jj:**
```bash
jj edit <commit>
# Make changes (auto-committed)
jj new # Continue with new work
# Descendants auto-rebased!
```

265
references/revsets.md Normal file
View File

@@ -0,0 +1,265 @@
# Revsets Reference
Revsets are a functional language for selecting commits in jj. This reference covers all operators, functions, and patterns.
## Table of Contents
- [Basic Symbols](#basic-symbols)
- [Operators](#operators)
- [Functions](#functions)
- [String Patterns](#string-patterns)
- [Common Patterns](#common-patterns)
## Basic Symbols
| Symbol | Description |
|--------|-------------|
| `@` | Working copy commit |
| `root()` | Repository root (empty commit) |
| `<change_id>` | Commit by change ID (e.g., `kntqzsqt`) |
| `<commit_id>` | Commit by commit hash (prefix ok) |
| `<bookmark>` | Commit at bookmark (e.g., `main`) |
| `<bookmark>@<remote>` | Remote bookmark (e.g., `main@origin`) |
| `<tag>` | Commit at tag |
## Operators
### Parent/Child Navigation
| Operator | Description | Example |
|----------|-------------|---------|
| `x-` | Parents of x | `@-` (parent of working copy) |
| `x+` | Children of x | `main+` (children of main) |
| `x--` | Grandparents | `@--` |
| `x++` | Grandchildren | `main++` |
### Ancestry/Descendant
| Operator | Description | Example |
|----------|-------------|---------|
| `::x` | Ancestors of x (inclusive) | `::@` |
| `x::` | Descendants of x (inclusive) | `main::` |
| `x::y` | DAG path from x to y | `main::@` |
| `:x` | Ancestors of x (exclusive) | `:@` (excludes @) |
| `x:` | Descendants of x (exclusive) | `main:` (excludes main) |
### Range
| Operator | Description | Example |
|----------|-------------|---------|
| `x..y` | Ancestors of y minus ancestors of x | `main..@` |
| `x..` | Descendants of x minus x | `main..` |
| `..y` | Ancestors of y minus root | `..@` |
### Set Operations
| Operator | Description | Example |
|----------|-------------|---------|
| `x \| y` | Union (x or y) | `main \| develop` |
| `x & y` | Intersection (x and y) | `mine() & ::@` |
| `x ~ y` | Difference (x minus y) | `::@ ~ ::main` |
| `~x` | Complement (not x) | `~empty()` |
### Grouping
Use parentheses for grouping: `(x | y) & z`
## Functions
### Commit Selection
| Function | Description |
|----------|-------------|
| `all()` | All commits |
| `none()` | Empty set |
| `visible_heads()` | Visible branch heads |
| `heads(x)` | Commits in x with no descendants in x |
| `roots(x)` | Commits in x with no ancestors in x |
| `latest(x, n)` | Latest n commits from x by committer date |
### Bookmarks and Tags
| Function | Description |
|----------|-------------|
| `bookmarks()` | All local bookmark targets |
| `bookmarks(pattern)` | Bookmarks matching pattern |
| `remote_bookmarks()` | All remote bookmark targets |
| `remote_bookmarks(pattern)` | Remote bookmarks matching pattern |
| `tracked_remote_bookmarks()` | Tracked remote bookmarks |
| `untracked_remote_bookmarks()` | Untracked remote bookmarks |
| `tags()` | All tag targets |
| `tags(pattern)` | Tags matching pattern |
| `trunk()` | Main branch (main, master, trunk) |
### Author/Committer
| Function | Description |
|----------|-------------|
| `author(pattern)` | Commits by matching author name/email |
| `author_date(pattern)` | Commits by author date |
| `committer(pattern)` | Commits by committer |
| `committer_date(pattern)` | Commits by committer date |
| `mine()` | Commits by configured user |
### Content
| Function | Description |
|----------|-------------|
| `description(pattern)` | Match commit description |
| `description(exact:"text")` | Exact description match |
| `empty()` | Empty commits (no file changes) |
| `file(pattern)` | Commits modifying matching files |
| `diff_contains(pattern)` | Commits with matching diff content |
### Conflicts and Status
| Function | Description |
|----------|-------------|
| `conflicts()` | Commits containing conflicts |
| `signed()` | Cryptographically signed commits |
| `working_copies()` | All working copy commits |
### Mutability
| Function | Description |
|----------|-------------|
| `mutable()` | Commits that can be rewritten |
| `immutable()` | Protected commits (trunk, tags) |
| `immutable_heads()` | Heads of immutable commits |
### Ancestry
| Function | Description |
|----------|-------------|
| `ancestors(x)` | Same as `::x` |
| `ancestors(x, depth)` | Ancestors up to depth |
| `descendants(x)` | Same as `x::` |
| `descendants(x, depth)` | Descendants up to depth |
| `connected(x)` | x plus ancestors and descendants within x |
| `reachable(x, domain)` | Commits reachable from x within domain |
### Structure
| Function | Description |
|----------|-------------|
| `parents(x)` | Parents of commits in x |
| `children(x)` | Children of commits in x |
| `present(x)` | x if it exists, else empty |
| `coalesce(x, y)` | x if non-empty, else y |
## String Patterns
Used in functions like `bookmarks()`, `description()`, `author()`:
| Pattern | Description | Example |
|---------|-------------|---------|
| `substring:text` | Contains text (default) | `description("fix")` |
| `exact:text` | Exact match | `description(exact:"")` |
| `glob:pattern` | Glob pattern | `bookmarks(glob:"feature-*")` |
| `regex:pattern` | Regular expression | `author(regex:"^J.*")` |
## Common Patterns
### Working with Current Work
```bash
# My work in progress
jj log -r 'trunk()..@'
# My recent changes
jj log -r 'mine() & ancestors(@, 20)'
# Empty commits I made (WIP markers)
jj log -r 'mine() & empty()'
# Commits with empty descriptions
jj log -r 'description(exact:"")'
```
### Branch Operations
```bash
# Commits on feature branch not on main
jj log -r 'main..feature'
# All commits on any feature branch
jj log -r 'bookmarks(glob:"feature-*")::'
# Diverged commits
jj log -r 'heads(trunk()..)'
```
### Finding Commits
```bash
# Commits touching specific file
jj log -r 'file("src/main.rs")'
# Commits containing "TODO" in diff
jj log -r 'diff_contains("TODO")'
# Commits by specific author
jj log -r 'author("alice@")'
# Commits from last week
jj log -r 'committer_date(after:"1 week ago")'
```
### Conflicts
```bash
# All conflicted commits
jj log -r 'conflicts()'
# Conflicted commits in my branch
jj log -r 'conflicts() & trunk()..@'
```
### Rebasing Patterns
```bash
# Rebase entire branch onto trunk
jj rebase -s 'roots(trunk()..@)' -d trunk()
# Rebase all mutable descendants
jj rebase -s 'roots(mutable())' -d <dest>
# Find commits to squash (empty changes)
jj log -r 'empty() & trunk()..@'
```
### Working Copies (Multiple Workspaces)
```bash
# All working copy commits
jj log -r 'working_copies()'
# Current workspace's working copy
jj log -r '@'
```
## Date Patterns
For `author_date()` and `committer_date()`:
| Pattern | Example |
|---------|---------|
| `after:date` | `author_date(after:"2024-01-01")` |
| `before:date` | `committer_date(before:"yesterday")` |
| Relative | `"1 week ago"`, `"2 days ago"` |
| Absolute | `"2024-06-15"`, `"2024-06-15T10:30:00"` |
## Combining Expressions
Complex queries combine operators and functions:
```bash
# My non-empty commits on feature branch, excluding conflicts
jj log -r '(mine() & feature::@) ~ (empty() | conflicts())'
# Latest 5 commits touching src/ by any author
jj log -r 'latest(file("src/**"), 5)'
# All commits between two tags
jj log -r 'v1.0::v2.0'
```