# Jujutsu Revsets - Complete Reference Revsets are a functional language in jujutsu for selecting and querying commits. This document provides comprehensive coverage of revset syntax, symbols, operators, functions, and practical usage patterns. ## Overview The revset language (inspired by Mercurial) enables powerful commit selection across jujutsu commands. Expressions in this language are called "revsets" and are fundamental to working effectively with jujutsu. The language consists of: - **Symbols** - References to specific commits or sets of commits - **Operators** - Ways to traverse and combine commit sets - **Functions** - Queries and filters for finding commits ## Core Symbols ### Working Copy References #### `@` The current working copy commit. ```bash jj log -r @ # Show working copy commit jj diff -r @ # Diff of working copy jj new @- # Create new commit on parent of @ ``` #### `@` Working copy in a named workspace. ```bash jj log -r main@ # Working copy in "main" workspace jj diff -r feature@ # Working copy in "feature" workspace ``` ### Remote References #### `@` Remote-tracking bookmark. ```bash jj log -r main@origin # Remote tracking branch jj rebase -d main@origin # Rebase onto remote main jj diff --from main@origin --to @ # Compare to remote ``` ### Commit Identifiers #### Change IDs and Commit IDs Full hexadecimal IDs or unique prefixes. ```bash jj log -r k # Unique prefix jj log -r kmkuslsw # Longer prefix jj log -r kmkuslswpqwq # Full change ID jj show a1b2c3d # Commit ID prefix ``` **Resolution order:** Tags → Bookmarks → Git refs → Commit IDs ### Special Symbols #### `root()` The root commit (virtual commit at base of history). ```bash jj log -r root() # Show root commit jj log -r ::@ # All ancestors including root ``` ## Operators Operators traverse commit history and combine commit sets. ### Ancestry Operators #### `x-` (Parents) Immediate parent(s) of x. ```bash jj log -r @- # Parent of working copy jj log -r @-- # Grandparent jj show @- # Show parent commit jj edit @- # Edit parent commit ``` Multiple parents (merge commits): ```bash jj log -r @-+ # Children of all parents (siblings) ``` #### `x+` (Children) Immediate children of x. ```bash jj log -r @+ # Children of working copy jj log -r main@origin+ # Children of remote main ``` #### `::x` (Ancestors) All ancestors of x, including x itself. ```bash jj log -r ::@ # All ancestors of working copy jj log -r ::main # All ancestors of main jj log -r ::@- # Ancestors up to parent ``` #### `x::` (Descendants) All descendants of x, including x itself. ```bash jj log -r @:: # Working copy and all descendants jj log -r main:: # main and its descendants ``` #### `x::y` (DAG Range) Commits reachable from y through ancestor relationships with x. ```bash jj log -r main::@ # Commits from main to @ jj log -r @-::@ # Just @ (parent to working copy) ``` #### `::x` with depth Ancestors with limited depth. ```bash jj log -r ancestors(@, 5) # Last 5 ancestors jj log -r ancestors(@, 1) # Just parent (same as @-) ``` ### Range Operators #### `..x` (Ancestors excluding root) Ancestors of x, excluding the root commit. ```bash jj log -r ..@ # Ancestors of @ without root jj log -r ..main # History up to main ``` #### `x..` (Non-ancestors) x and its descendants, excluding ancestors. ```bash jj log -r @.. # Working copy and descendants jj log -r main.. # Everything not ancestral to main ``` #### `x..y` (Range) Commits in y but not in x (y's descendants minus x's ancestors). ```bash jj log -r main..@ # Commits added since main jj log -r @-..@ # Just @ (changes since parent) jj log -r @..main # Commits in main not in @ ``` ### Set Operators #### `x | y` (Union) Commits in either x or y (or both). ```bash jj log -r '@- | @' # Parent and working copy jj log -r 'main | feature' # Both branches jj log -r 'bookmarks() | tags()' # All bookmarks and tags ``` #### `x & y` (Intersection) Commits in both x and y. ```bash jj log -r 'author(alice) & description(bug)' # Alice's bug fixes jj log -r 'mine() & ::main' # My commits in main's history ``` #### `x ~ y` (Difference) Commits in x but not in y. ```bash jj log -r 'all() ~ main' # All commits except main jj log -r '@:: ~ @' # Descendants excluding working copy jj log -r 'mine() ~ ::main' # My commits not yet in main ``` #### `~x` (Complement) All commits except those in x. ```bash jj log -r '~@' # Everything except working copy jj log -r '~main::' # Everything not descended from main ``` ### Operator Precedence From highest to lowest: 1. `-` (parents), `+` (children) 2. `::`, `..` (DAG ranges) 3. `~` (negation/complement) 4. `&` (intersection) 5. `~` (set difference) 6. `|` (union) Use parentheses to override: ```bash jj log -r '(main | feature) & author(alice)' jj log -r 'main::(@ | feature)' ``` ## Functions Functions query and filter commits based on various criteria. ### Traversal Functions #### `ancestors(x[, depth])` All ancestors of x, optionally limited by depth. ```bash jj log -r 'ancestors(@)' # All ancestors jj log -r 'ancestors(@, 5)' # 5 generations back jj log -r 'ancestors(main, 10)' # 10 commits before main ``` #### `descendants(x)` All descendants of x, including x. ```bash jj log -r 'descendants(main)' # main and everything after jj log -r 'descendants(@-)' # Parent and its descendants ``` #### `connected(x)` Commits connected to x through parents and children. ```bash jj log -r 'connected(@)' # Connected component containing @ ``` #### `reachable(x, domain)` Commits in domain that are reachable from x. ```bash jj log -r 'reachable(@, all())' # All reachable from @ ``` ### Set Functions #### `all()` All commits in the repository. ```bash jj log -r 'all()' # Entire history jj log -r 'all() ~ ::main' # Everything not in main's history ``` #### `none()` Empty set (no commits). ```bash jj log -r 'none()' # No output jj log -r 'none() | @' # Just @ (contrived example) ``` #### `heads(x)` Commits in x that have no children in x. ```bash jj log -r 'heads(all())' # All branch tips jj log -r 'heads(main::)' # Tips descended from main ``` #### `roots(x)` Commits in x that have no parents in x. ```bash jj log -r 'roots(main..@)' # First commits after branching from main jj log -r 'roots(bookmarks())' # Root commits of bookmarked branches ``` #### `latest(x[, count])` Latest (newest) commits from x, optionally limited. ```bash jj log -r 'latest(all())' # Most recent commit jj log -r 'latest(all(), 10)' # 10 most recent commits jj log -r 'latest(author(alice), 5)' # Alice's 5 latest commits ``` ### Bookmark and Tag Functions #### `bookmarks([pattern])` Commits pointed to by bookmarks, optionally filtered by pattern. ```bash jj log -r 'bookmarks()' # All bookmarked commits jj log -r 'bookmarks(main)' # Main bookmark jj log -r 'bookmarks(glob:feature-*)' # Feature branches ``` Pattern types: `substring:`, `exact:`, `glob:`, `regex:` (append `-i` for case-insensitive) #### `remote_bookmarks([pattern[, [remote=]pattern]])` Remote-tracking bookmarks, optionally filtered. ```bash jj log -r 'remote_bookmarks()' # All remote bookmarks jj log -r 'remote_bookmarks(main)' # main on all remotes jj log -r 'remote_bookmarks(main, origin)' # main@origin jj log -r 'remote_bookmarks(glob:feature-*, origin)' # Feature branches on origin ``` #### `tags([pattern])` Commits with tags, optionally filtered. ```bash jj log -r 'tags()' # All tagged commits jj log -r 'tags(v1.0.0)' # Specific tag jj log -r 'tags(glob:v1.*)' # All v1.x tags ``` #### `git_refs()` All Git references. ```bash jj log -r 'git_refs()' # All Git refs ``` #### `git_head()` Git's HEAD reference. ```bash jj log -r 'git_head()' # Show Git HEAD ``` #### `tracked_remote_bookmarks([bookmark_pattern[, [remote=]remote_pattern]])` Bookmarks with remote tracking configured. ```bash jj log -r 'tracked_remote_bookmarks()' # All tracked bookmarks jj log -r 'tracked_remote_bookmarks(main)' # Tracked main branches ``` #### `untracked_remote_bookmarks([bookmark_pattern[, [remote=]remote_pattern]])` Remote bookmarks without local tracking. ```bash jj log -r 'untracked_remote_bookmarks()' # Untracked remotes ``` ### Author and Committer Functions #### `author(pattern)` Commits where author matches pattern. ```bash jj log -r 'author(alice)' # Alice's commits jj log -r 'author("Alice Smith")' # Exact name jj log -r 'author(glob:*@example.com)' # By email domain jj log -r 'author(regex:^A)' # Names starting with A ``` Pattern matching supports: `substring:`, `exact:`, `glob:`, `regex:` (with `-i` suffix for case-insensitive) #### `committer(pattern)` Commits where committer matches pattern. ```bash jj log -r 'committer(bot)' # Commits by bot jj log -r 'committer(glob:*@github.com)' # GitHub committers ``` #### `mine()` Commits authored or committed by the current user. ```bash jj log -r 'mine()' # All my commits jj log -r 'mine() & ::main' # My commits in main jj log -r 'mine() ~ ::main' # My commits not in main ``` ### Description Functions #### `description(pattern)` Commits with description matching pattern. ```bash jj log -r 'description(bug)' # Commits mentioning "bug" jj log -r 'description(exact:Fix bug #123)' # Exact match jj log -r 'description(glob:*BREAKING*)' # Contains "BREAKING" jj log -r 'description(regex:^fix:)' # Conventional commit fixes ``` #### `subject(pattern)` Commits with first line of description matching pattern. ```bash jj log -r 'subject(feat:)' # Feature commits jj log -r 'subject(glob:*WIP*)' # WIP commits ``` ### File Functions #### `files(pattern)` Commits modifying files matching pattern. ```bash jj log -r 'files(glob:*.rs)' # Commits changing Rust files jj log -r 'files(src/main.rs)' # Commits changing specific file jj log -r 'files(glob:**/test_*)' # Commits changing test files ``` Uses fileset syntax (see filesets.md). #### `diff_contains(pattern[, [files=]fileset])` Commits with diff containing pattern, optionally in specific files. ```bash jj log -r 'diff_contains(TODO)' # Commits adding/removing TODO jj log -r 'diff_contains(bug, files=glob:*.rs)' # "bug" in Rust files jj log -r 'diff_contains(regex:\bfix\b)' # Word "fix" in diff ``` ### State Functions #### `empty()` Commits with no changes (empty diffs). ```bash jj log -r 'empty()' # All empty commits jj log -r 'mine() & empty()' # My empty commits jj abandon $(jj log -r 'empty()' -T commit_id --no-graph) # Remove empty commits ``` #### `conflict()` Commits with unresolved conflicts. ```bash jj log -r 'conflict()' # Find conflicted commits jj resolve $(jj log -r 'conflict()' -T commit_id --no-graph | head -1) # Resolve first ``` #### `immutable()` Commits considered immutable (configured in settings). ```bash jj log -r 'immutable()' # Show immutable commits jj log -r 'all() ~ immutable()' # Only mutable commits ``` #### `present(x)` Returns x if it exists, otherwise empty set. ```bash jj log -r 'present(some-branch)' # Branch if it exists jj rebase -d 'present(main) | @-' # Use main if exists, else parent ``` Useful for scripting to avoid errors when references don't exist. ### Visibility Functions #### `visible_heads()` Commits that are visible heads. ```bash jj log -r 'visible_heads()' # All visible heads ``` #### `immutable_heads()` Heads of immutable commits. ```bash jj log -r 'immutable_heads()' # Immutable heads ``` ## Pattern Matching String patterns in functions support multiple matching modes. ### Pattern Prefixes - `substring:` - Default, matches if pattern appears anywhere - `exact:` - Exact match only - `glob:` - Unix-style glob patterns - `regex:` - Regular expression matching Add `-i` suffix for case-insensitive matching: - `substring-i:`, `exact-i:`, `glob-i:`, `regex-i:` ### Examples ```bash # Substring (default) jj log -r 'author(alice)' jj log -r 'author(substring:alice)' # Equivalent # Exact match jj log -r 'author(exact:Alice Smith)' jj log -r 'description(exact:Fix bug #123)' # Glob patterns jj log -r 'author(glob:*@example.com)' jj log -r 'bookmarks(glob:feature-*)' jj log -r 'files(glob:**/*.rs)' # Regular expressions jj log -r 'description(regex:^feat:)' jj log -r 'author(regex:\d+\+.*@users.noreply.github.com)' # Case-insensitive jj log -r 'author(substring-i:ALICE)' jj log -r 'description(glob-i:*breaking*)' ``` ## Practical Examples ### Finding Commits ```bash # Recent work jj log -r 'latest(mine(), 10)' # My 10 most recent commits # Commits by criteria jj log -r 'author(alice) & description(bug)' # Alice's bug fixes jj log -r 'mine() & conflict()' # My conflicted commits jj log -r 'files(glob:*.rs) & description(perf)' # Rust performance commits # Branch comparisons jj log -r 'main..@' # My commits not in main jj log -r 'main..feature' # Commits in feature not in main jj log -r 'main@origin..' # All commits not pushed ``` ### Working with Branches ```bash # View all branches jj log -r 'bookmarks()' # Active development branches jj log -r 'heads(all()) ~ remote_bookmarks()' # Branches needing updates jj log -r 'bookmarks() ~ ::remote_bookmarks(main, origin)' # Merged branches jj log -r 'bookmarks() & ::main' ``` ### History Analysis ```bash # Commits touching specific files jj log -r 'files(src/auth.rs)' # Recent changes to tests jj log -r 'latest(files(glob:**/*_test.rs), 20)' # Commits between tags jj log -r 'tags(v1.0.0)..tags(v2.0.0)' # Commits not yet tagged jj log -r 'heads(all()) ~ ::tags()' ``` ### Commit Cleanup ```bash # Find empty commits jj log -r 'empty()' # Find WIP commits jj log -r 'description(glob:*WIP*)' # Commits needing attention jj log -r 'conflict() | empty() | description(glob:*TODO*)' ``` ### Working with Remotes ```bash # Commits not pushed jj log -r 'mine() ~ ::remote_bookmarks()' # Remote updates jj log -r 'remote_bookmarks() ~ ::bookmarks()' # Diverged branches jj log -r '(main ~ ::main@origin) | (main@origin ~ ::main)' ``` ## Complex Queries ### Multi-Criteria Searches ```bash # My recent bug fixes in Rust code jj log -r ' latest( mine() & description(glob:*fix*|*bug*) & files(glob:**/*.rs), 20 ) ' # Commits by team members on feature branches jj log -r ' (author(alice) | author(bob) | author(carol)) & bookmarks(glob:feature-*):: ~ ::main ' # Risky commits (large changes, no tests) jj log -r ' files(glob:src/**/*.rs) ~ files(glob:**/*_test.rs) & description(regex:(?i)\b(refactor|rewrite)\b) ' ``` ### Conditional Selection ```bash # Use main@origin if it exists, otherwise main jj rebase -d 'present(main@origin) | main' # Latest stable release or head jj log -r 'present(tags(glob:v*.*.0)) | heads(all())' ``` ### Graph Queries ```bash # All commits between branches jj log -r 'main::feature ~ (::main | feature::)' # Divergent changes jj log -r '(main ~ ::feature) | (feature ~ ::main)' # Common ancestors jj log -r '::main & ::feature' ``` ## Best Practices ### 1. Start Simple, Then Refine ```bash # Start broad jj log -r 'mine()' # Add date constraints jj log -r 'latest(mine(), 20)' # Add content filter jj log -r 'latest(mine() & description(feature), 20)' ``` ### 2. Use Readable Multi-Line Queries ```bash # Hard to read jj log -r 'latest(mine() & (description(bug) | description(fix)) & files(glob:src/**/*.rs) ~ ::main, 10)' # Readable jj log -r ' latest( mine() & (description(bug) | description(fix)) & files(glob:src/**/*.rs) ~ ::main, 10 ) ' ``` ### 3. Create Aliases for Common Queries Edit config with `jj config edit --user`: ```toml [revset-aliases] # My commits not in main work = "mine() ~ ::main" # Commits needing attention attention = "conflict() | empty() | description(glob:*WIP*) | description(glob:*TODO*)" # Recent changes recent = "latest(all(), 20)" # Unpushed work unpushed = "mine() ~ ::remote_bookmarks()" ``` Use in commands: ```bash jj log -r work jj log -r attention jj log -r recent ``` ### 4. Use `present()` for Robustness ```bash # Fails if branch doesn't exist jj rebase -d some-branch # Safe version jj rebase -d 'present(some-branch) | @-' ``` ### 5. Combine with Templates for Insight ```bash # Show commit IDs of specific commits jj log -r 'conflict()' -T commit_id --no-graph # Count commits jj log -r 'mine() ~ ::main' --no-graph | wc -l # Custom format for scripting jj log -r 'latest(mine(), 5)' -T 'commit_id ++ " " ++ description.first_line() ++ "\n"' ``` ## Troubleshooting ### No Commits Matched ```bash # Check individual parts jj log -r 'author(alice)' # Does author filter work? jj log -r 'description(bug)' # Does description filter work? jj log -r 'author(alice) & description(bug)' # Combine # Verify symbols exist jj bookmark list # Check bookmark names jj log -r 'bookmarks()' # See all bookmarks ``` ### Unexpected Results ```bash # Use `all()` to understand set size jj log -r 'all() ~ ::main' # Everything not in main # Break down complex queries jj log -r 'mine()' # Step 1 jj log -r 'mine() ~ ::main' # Step 2 jj log -r 'latest(mine() ~ ::main, 10)' # Step 3 ``` ### Performance Issues ```bash # Large repositories may be slow with broad queries jj log -r 'all()' # Can be slow # Optimize by limiting scope jj log -r 'latest(all(), 100)' # Faster jj log -r '::@' # Just ancestors jj log -r 'ancestors(@, 50)' # Limited depth ``` ## Integration with Commands Revsets work with most jujutsu commands: ### Viewing History ```bash jj log -r '' # Show log jj show -r '' # Show details jj diff -r '' # Show changes jj evolog -r '' # Show evolution log ``` ### Modifying Commits ```bash jj edit # Edit commit jj squash -r # Squash commit jj abandon # Abandon commits jj describe -r # Set description ``` ### Rebasing ```bash jj rebase -d # Rebase destination jj rebase -r -d # Rebase specific commit jj rebase -s -d # Rebase source and descendants ``` ### Branching ```bash jj bookmark set -r # Set bookmark jj new # New commit on base ``` ## Summary Revsets are the foundation of powerful commit selection in jujutsu: - **Symbols**: `@`, `root()`, commit IDs, bookmarks, tags - **Operators**: `-/+` (parents/children), `::` (ancestors/descendants), `|/&/~` (set operations) - **Functions**: `mine()`, `author()`, `description()`, `files()`, `conflict()`, `empty()`, etc. - **Patterns**: `substring:`, `exact:`, `glob:`, `regex:` (with `-i` for case-insensitive) - **Best practices**: Start simple, use aliases, combine with templates - **Integration**: Works across all jujutsu commands For file-based filtering, see filesets.md. For output customization, see templating.md. Master revsets to unlock jujutsu's full potential for commit management and history navigation.