just playing with tangled
at ig/vimdiffwarn 589 lines 21 kB view raw view rendered
1# Revsets 2 3Jujutsu supports a functional language for selecting a set of revisions. 4Expressions in this language are called "revsets" (the idea comes from 5[Mercurial](https://www.mercurial-scm.org/repo/hg/help/revsets)). The language 6consists of symbols, operators, and functions. 7 8Most `jj` commands accept a revset (or multiple). Many commands, such as 9`jj diff -r <revset>` expect the revset to resolve to a single commit; it is 10an error to pass a revset that resolves to more than one commit (or zero 11commits) to such commands. 12 13The words "revisions" and "commits" are used interchangeably in this document. 14 15Most revsets search only the [visible commits](glossary.md#visible-commits). 16Other commits are only included if you explicitly mention them (e.g. by commit 17ID or a Git ref pointing to them). 18 19## Symbols 20 21The `@` expression refers to the working copy commit in the current workspace. 22Use `<workspace name>@` to refer to the working-copy commit in another 23workspace. Use `<name>@<remote>` to refer to a remote-tracking bookmark. 24 25A full commit ID refers to a single commit. A unique prefix of the full commit 26ID can also be used. It is an error to use a non-unique prefix. 27 28A full change ID refers to all visible commits with that change ID (there is 29typically only one visible commit with a given change ID). A unique prefix of 30the full change ID can also be used. It is an error to use a non-unique prefix. 31 32Use [single or double quotes][string-literals] to prevent a symbol from being 33interpreted as an expression. For example, `"x-"` is the symbol `x-`, not the 34parents of symbol `x`. Taking shell quoting into account, you may need to use 35something like `jj log -r '"x-"'`. 36 37[string-literals]: templates.md#string-literals 38 39### Priority 40 41Jujutsu attempts to resolve a symbol in the following order: 42 431. Tag name 442. Bookmark name 453. Git ref 464. Commit ID or change ID 47 48## Operators 49 50The following operators are supported. `x` and `y` below can be any revset, not 51only symbols. 52 53* `x-`: Parents of `x`, can be empty. 54* `x+`: Children of `x`, can be empty. 55* `x::`: Descendants of `x`, including the commits in `x` itself. Shorthand for 56 `x::visible_heads()`. 57* `x..`: Revisions that are not ancestors of `x`. Shorthand for 58 `x..visible_heads()`. 59* `::x`: Ancestors of `x`, including the commits in `x` itself. Shorthand for 60 `root()::x`. 61* `..x`: Ancestors of `x`, including the commits in `x` itself, but excluding 62 the root commit. Shorthand for `root()..x`. Equivalent to `::x ~ root()`. 63* `x::y`: Descendants of `x` that are also ancestors of `y`. Equivalent 64 to `x:: & ::y`. This is what `git log` calls `--ancestry-path x..y`. 65* `x..y`: Ancestors of `y` that are not also ancestors of `x`. Equivalent to 66 `::y ~ ::x`. This is what `git log` calls `x..y` (i.e. the same as we call it). 67* `::`: All visible commits in the repo. Shorthand for 68 `root()::visible_heads()`. Equivalent to `all()`. 69* `..`: All visible commits in the repo, but excluding the root commit. 70 Shorthand for `root()..visible_heads()`. Equivalent to `~root()`. 71* `~x`: Revisions that are not in `x`. 72* `x & y`: Revisions that are in both `x` and `y`. 73* `x ~ y`: Revisions that are in `x` but not in `y`. 74* `x | y`: Revisions that are in either `x` or `y` (or both). 75 76(listed in order of binding strengths) 77 78You can use parentheses to control evaluation order, such as `(x & y) | z` or 79`x & (y | z)`. 80 81<!-- The following format will be understood by the web site generator, and will 82 generate a folded section that can be unfolded at will. --> 83 84??? examples 85 86 Given this history: 87 ``` 88 o D 89 |\ 90 | o C 91 | | 92 o | B 93 |/ 94 o A 95 | 96 o root() 97 ``` 98 99 **Operator** `x-` 100 101 * `D-` ⇒ `{C,B}` 102 * `B-` ⇒ `{A}` 103 * `A-` ⇒ `{root()}` 104 * `root()-` ⇒ `{}` (empty set) 105 * `none()-` ⇒ `{}` (empty set) 106 * `(D|A)-` ⇒ `{C,B,root()}` 107 * `(C|B)-` ⇒ `{A}` 108 109 **Operator** `x+` 110 111 * `D+` ⇒ `{}` (empty set) 112 * `B+` ⇒ `{D}` 113 * `A+` ⇒ `{B,C}` 114 * `root()+` ⇒ `{A}` 115 * `none()+` ⇒ `{}` (empty set) 116 * `(C|B)+` ⇒ `{D}` 117 * `(B|root())+` ⇒ `{D,A}` 118 119 **Operator** `x::` 120 121 * `D::` ⇒ `{D}` 122 * `B::` ⇒ `{D,B}` 123 * `A::` ⇒ `{D,C,B,A}` 124 * `root()::` ⇒ `{D,C,B,A,root()}` 125 * `none()::` ⇒ `{}` (empty set) 126 * `(C|B)::` ⇒ `{D,C,B}` 127 128 **Operator** `x..` 129 130 * `D..` ⇒ `{}` (empty set) 131 * `B..` ⇒ `{D,C}` (note that, unlike `B::`, this includes `C`) 132 * `A..` ⇒ `{D,C,B}` 133 * `root()..` ⇒ `{D,C,B,A}` 134 * `none()..` ⇒ `{D,C,B,A,root()}` 135 * `(C|B)..` ⇒ `{D}` 136 137 **Operator** `::x` 138 139 * `::D` ⇒ `{D,C,B,A,root()}` 140 * `::B` ⇒ `{B,A,root()}` 141 * `::A` ⇒ `{A,root()}` 142 * `::root()` ⇒ `{root()}` 143 * `::none()` ⇒ `{}` (empty set) 144 * `::(C|B)` ⇒ `{C,B,A,root()}` 145 146 **Operator** `..x` 147 148 * `..D` ⇒ `{D,C,B,A}` 149 * `..B` ⇒ `{B,A}` 150 * `..A` ⇒ `{A}` 151 * `..root()` ⇒ `{}` (empty set) 152 * `..none()` ⇒ `{}` (empty set) 153 * `..(C|B)` ⇒ `{C,B,A}` 154 155 **Operator** `x::y` 156 157 * `D::D` ⇒ `{D}` 158 * `B::D` ⇒ `{D,B}` (note that, unlike `B..D`, this includes `B` and excludes `C`) 159 * `A::D` ⇒ `{D,C,B,A}` 160 * `root()::D` ⇒ `{D,C,B,A,root()}` 161 * `none()::D` ⇒ `{}` (empty set) 162 * `D::B` ⇒ `{}` (empty set) 163 * `(C|B)::(C|B)` ⇒ `{C,B}` 164 165 **Operator** `x..y` 166 167 * `D..D` ⇒ `{}` (empty set) 168 * `B..D` ⇒ `{D,C}` (note that, unlike `B::D`, this includes `C` and excludes `B`) 169 * `A..D` ⇒ `{D,C,B}` 170 * `root()..D` ⇒ `{D,C,B,A}` 171 * `none()..D` ⇒ `{D,C,B,A,root()}` 172 * `D..B` ⇒ `{}` (empty set) 173 * `(C|B)..(C|B)` ⇒ `{}` (empty set) 174 175## Functions 176 177You can also specify revisions by using functions. Some functions take other 178revsets (expressions) as arguments. 179 180* `parents(x)`: Same as `x-`. 181 182* `children(x)`: Same as `x+`. 183 184* `ancestors(x[, depth])`: `ancestors(x)` is the same as `::x`. 185 `ancestors(x, depth)` returns the ancestors of `x` limited to the given 186 `depth`. 187 188* `descendants(x[, depth])`: `descendants(x)` is the same as `x::`. 189 `descendants(x, depth)` returns the descendants of `x` limited to the given 190 `depth`. 191 192* `reachable(srcs, domain)`: All commits reachable from `srcs` within 193 `domain`, traversing all parent and child edges. 194 195* `connected(x)`: Same as `x::x`. Useful when `x` includes several commits. 196 197* `all()`: All visible commits in the repo. 198 199* `none()`: No commits. This function is rarely useful; it is provided for 200 completeness. 201 202* `bookmarks([pattern])`: All local bookmark targets. If `pattern` is specified, 203 this selects the bookmarks whose name match the given [string 204 pattern](#string-patterns). For example, `bookmarks(push)` would match the 205 bookmarks `push-123` and `repushed` but not the bookmark `main`. If a bookmark is 206 in a conflicted state, all its possible targets are included. 207 208* `remote_bookmarks([bookmark_pattern[, [remote=]remote_pattern]])`: All remote 209 bookmarks targets across all remotes. If just the `bookmark_pattern` is 210 specified, the bookmarks whose names match the given [string 211 pattern](#string-patterns) across all remotes are selected. If both 212 `bookmark_pattern` and `remote_pattern` are specified, the selection is 213 further restricted to just the remotes whose names match `remote_pattern`. 214 215 For example, `remote_bookmarks(push, ri)` would match the bookmarks 216 `push-123@origin` and `repushed@private` but not `push-123@upstream` or 217 `main@origin` or `main@upstream`. If a bookmark is in a conflicted state, all 218 its possible targets are included. 219 220 While Git-tracking bookmarks can be selected by `<name>@git`, these bookmarks 221 aren't included in `remote_bookmarks()`. 222 223* `tracked_remote_bookmarks([bookmark_pattern[, [remote=]remote_pattern]])`: All 224 targets of tracked remote bookmarks. Supports the same optional arguments as 225 `remote_bookmarks()`. 226 227* `untracked_remote_bookmarks([bookmark_pattern[, [remote=]remote_pattern]])`: 228 All targets of untracked remote bookmarks. Supports the same optional arguments 229 as `remote_bookmarks()`. 230 231* `tags([pattern])`: All tag targets. If `pattern` is specified, 232 this selects the tags whose name match the given [string 233 pattern](#string-patterns). For example, `tags(v1)` would match the 234 tags `v123` and `rev1` but not the tag `v2`. If a tag is 235 in a conflicted state, all its possible targets are included. 236 237* `git_refs()`: All Git ref targets as of the last import. If a Git ref 238 is in a conflicted state, all its possible targets are included. 239 240* `git_head()`: The Git `HEAD` target as of the last import. 241 242* `visible_heads()`: All visible heads (same as `heads(all())`). 243 244* `root()`: The virtual commit that is the oldest ancestor of all other commits. 245 246* `heads(x)`: Commits in `x` that are not ancestors of other commits in `x`. 247 Note that this is different from 248 [Mercurial's](https://repo.mercurial-scm.org/hg/help/revsets) `heads(x)` 249 function, which is equivalent to `x ~ x-`. 250 251* `roots(x)`: Commits in `x` that are not descendants of other commits in `x`. 252 Note that this is different from 253 [Mercurial's](https://repo.mercurial-scm.org/hg/help/revsets) `roots(x)` 254 function, which is equivalent to `x ~ x+`. 255 256* `latest(x[, count])`: Latest `count` commits in `x`, based on committer 257 timestamp. The default `count` is 1. 258 259* `fork_point(x)`: The fork point of all commits in `x`. The fork point is the 260 common ancestor(s) of all commits in `x` which do not have any descendants 261 that are also common ancestors of all commits in `x`. It is equivalent to 262 the revset `heads(::x_1 & ::x_2 & ... & ::x_N)`, where `x_{1..N}` are commits 263 in `x`. If `x` resolves to a single commit, `fork_point(x)` resolves to `x`. 264 265* `merges()`: Merge commits. 266 267* `description(pattern)`: Commits that have a description matching the given 268 [string pattern](#string-patterns). 269 270 A non-empty description is usually terminated with newline character. For 271 example, `description(exact:"")` matches commits without description, and 272 `description(exact:"foo\n")` matches commits with description `"foo\n"`. 273 274* `subject(pattern)`: Commits that have a subject matching the given [string 275 pattern](#string-patterns). A subject is the first line of the description 276 (without newline character.) 277 278* `author(pattern)`: Commits with the author's name or email matching the given 279 [string pattern](#string-patterns). Equivalent to `author_name(pattern) | 280 author_email(pattern)`. 281 282* `author_name(pattern)`: Commits with the author's name matching the given 283 [string pattern](#string-patterns). 284 285* `author_email(pattern)`: Commits with the author's email matching the given 286 [string pattern](#string-patterns). 287 288* `author_date(pattern)`: Commits with author dates matching the specified [date 289 pattern](#date-patterns). 290 291* `mine()`: Commits where the author's email matches the email of the current 292 user. Equivalent to `author_email(exact-i:<user-email>)` 293 294* `committer(pattern)`: Commits with the committer's name or email matching the 295 given [string pattern](#string-patterns). Equivalent to 296 `committer_name(pattern) | committer_email(pattern)`. 297 298* `committer_name(pattern)`: Commits with the committer's name matching the 299 given [string pattern](#string-patterns). 300 301* `committer_email(pattern)`: Commits with the committer's email matching the 302 given [string pattern](#string-patterns). 303 304* `committer_date(pattern)`: Commits with committer dates matching the specified 305 [date pattern](#date-patterns). 306 307* `empty()`: Commits modifying no files. This also includes `merges()` without 308 user modifications and `root()`. 309 310* `files(expression)`: Commits modifying paths matching the given [fileset 311 expression](filesets.md). 312 313 Paths are relative to the directory `jj` was invoked from. A directory name 314 will match all files in that directory and its subdirectories. 315 316 For example, `files(foo)` will match files `foo`, `foo/bar`, `foo/bar/baz`. 317 It will *not* match `foobar` or `bar/foo`. 318 319 Some file patterns might need quoting because the `expression` must also be 320 parsable as a revset. For example, `.` has to be quoted in `files(".")`. 321 322* `diff_contains(text[, files])`: Commits containing diffs matching the given 323 `text` pattern line by line. 324 325 The search paths can be narrowed by the `files` expression. All modified files 326 are scanned by default, but it is likely to change in future version to 327 respect the command line path arguments. 328 329 For example, `diff_contains("TODO", "src")` will search revisions where "TODO" 330 is added to or removed from files under "src". 331 332* `conflicts()`: Commits with conflicts. 333 334* `present(x)`: Same as `x`, but evaluated to `none()` if any of the commits 335 in `x` doesn't exist (e.g. is an unknown bookmark name.) 336 337* `coalesce(revsets...)`: Commits in the first revset in the list of `revsets` 338 which does not evaluate to `none()`. If all revsets evaluate to `none()`, then 339 the result of `coalesce` will also be `none()`. 340 341* `working_copies()`: The working copy commits across all the workspaces. 342 343* `at_operation(op, x)`: Evaluates `x` at the specified [operation][]. For 344 example, `at_operation(@-, visible_heads())` will return all heads which were 345 visible at the previous operation. 346 347[operation]: glossary.md#operation 348 349??? examples 350 351 Given this history: 352 ``` 353 o E 354 | 355 | o D 356 |/| 357 | o C 358 | | 359 o | B 360 |/ 361 o A 362 | 363 o root() 364 ``` 365 366 **function** `reachable()` 367 368 * `reachable(E, A..)` ⇒ `{E,D,C,B}` 369 * `reachable(D, A..)` ⇒ `{E,D,C,B}` 370 * `reachable(C, A..)` ⇒ `{E,D,C,B}` 371 * `reachable(B, A..)` ⇒ `{E,D,C,B}` 372 * `reachable(A, A..)` ⇒ `{}` (empty set) 373 374 **function** `connected()` 375 376 * `connected(E|A)` ⇒ `{E,B,A}` 377 * `connected(D|A)` ⇒ `{D,C,B,A}` 378 * `connected(A)` ⇒ `{A}` 379 380 **function** `heads()` 381 382 * `heads(E|D)` ⇒ `{E,D}` 383 * `heads(E|C)` ⇒ `{E,C}` 384 * `heads(E|B)` ⇒ `{E}` 385 * `heads(E|A)` ⇒ `{E}` 386 * `heads(A)` ⇒ `{A}` 387 388 **function** `roots()` 389 390 * `roots(E|D)` ⇒ `{E,D}` 391 * `roots(E|C)` ⇒ `{E,C}` 392 * `roots(E|B)` ⇒ `{B}` 393 * `roots(E|A)` ⇒ `{A}` 394 * `roots(A)` ⇒ `{A}` 395 396 **function** `fork_point()` 397 398 * `fork_point(E|D)` ⇒ `{B}` 399 * `fork_point(E|C)` ⇒ `{A}` 400 * `fork_point(E|B)` ⇒ `{B}` 401 * `fork_point(E|A)` ⇒ `{A}` 402 * `fork_point(D|C)` ⇒ `{C}` 403 * `fork_point(D|B)` ⇒ `{A}` 404 * `fork_point(B|C)` ⇒ `{A}` 405 * `fork_point(A)` ⇒ `{A}` 406 * `fork_point(none())` ⇒ `{}` 407 408## String patterns 409 410Functions that perform string matching support the following pattern syntax (the 411quotes are optional): 412 413* `"string"` or `substring:"string"`: Matches strings that contain `string`. 414* `exact:"string"`: Matches strings exactly equal to `string`. 415* `glob:"pattern"`: Matches strings with Unix-style shell [wildcard 416 `pattern`](https://docs.rs/glob/latest/glob/struct.Pattern.html). 417* `regex:"pattern"`: Matches substrings with [regular 418 expression `pattern`](https://docs.rs/regex/latest/regex/#syntax). 419 420You can append `-i` after the kind to match case‐insensitively (e.g. 421`glob-i:"fix*jpeg*"`). 422 423## Date patterns 424 425Functions that perform date matching support the following pattern syntax: 426 427* `after:"string"`: Matches dates exactly at or after the given date. 428* `before:"string"`: Matches dates before, but not including, the given date. 429 430Date strings can be specified in several forms, including: 431 432* 2024-02-01 433* 2024-02-01T12:00:00 434* 2024-02-01T12:00:00-08:00 435* 2024-02-01 12:00:00 436* 2 days ago 437* 5 minutes ago 438* yesterday 439* yesterday 5pm 440* yesterday 10:30 441* yesterday 15:30 442 443## Aliases 444 445New symbols and functions can be defined in the config file, by using any 446combination of the predefined symbols/functions and other aliases. 447 448Alias functions can be overloaded by the number of parameters. However, builtin 449function will be shadowed by name, and can't co-exist with aliases. 450 451For example: 452 453```toml 454[revset-aliases] 455'HEAD' = '@-' 456'user()' = 'user("me@example.org")' 457'user(x)' = 'author(x) | committer(x)' 458``` 459 460### Built-in Aliases 461 462The following aliases are built-in and used for certain operations. These functions 463are defined as aliases in order to allow you to overwrite them as needed. 464See [revsets.toml](https://github.com/jj-vcs/jj/blob/main/cli/src/config/revsets.toml) 465for a comprehensive list. 466 467* `trunk()`: Resolves to the head commit for the trunk bookmark of the remote 468 named `origin` or `upstream`. The bookmarks `main`, `master`, and `trunk` are 469 tried. If more than one potential trunk commit exists, the newest one is 470 chosen. If none of the bookmarks exist, the revset evaluates to `root()`. 471 472 When working with an existing Git repository (via `jj git clone` or 473 `jj git init`), `trunk()` will be overridden at the repository level 474 to the default bookmark of the remote `origin`. 475 476 You can [override](./config.md) this as appropriate. If you do, make sure it 477 always resolves to exactly one commit. For example: 478 479 ```toml 480 [revset-aliases] 481 'trunk()' = 'your-bookmark@your-remote' 482 ``` 483 484* `builtin_immutable_heads()`: Resolves to 485 `present(trunk()) | tags() | untracked_remote_bookmarks()`. It is used as the 486 default definition for `immutable_heads()` below. It is not recommended to 487 redefine this alias. Prefer to redefine `immutable_heads()` instead. 488 489* `immutable_heads()`: Resolves to 490 `present(trunk()) | tags() | untracked_remote_bookmarks()` by default. It is 491 actually defined as `builtin_immutable_heads()`, and can be overridden as 492 required. See [here](config.md#set-of-immutable-commits) for details. 493 494* `immutable()`: The set of commits that `jj` treats as immutable. This is 495 equivalent to `::(immutable_heads() | root())`. It is not recommended to redefine 496 this alias. Note that modifying this will *not* change whether a commit is immutable. 497 To do that, edit `immutable_heads()`. 498 499* `mutable()`: The set of commits that `jj` treats as mutable. This is 500 equivalent to `~immutable()`. It is not recommended to redefined this alias. 501 Note that modifying this will *not* change whether a commit is immutable. 502 To do that, edit `immutable_heads()`. 503 504 505## The `all:` modifier 506 507Certain commands (such as `jj rebase`) can take multiple revset arguments, and 508each of these may resolve to one-or-many revisions. By default, `jj` will not 509allow revsets that resolve to more than one revision &mdash; a so-called "large 510revset" &mdash; and will ask you to confirm that you want to proceed by 511prefixing it with the `all:` modifier. 512 513If you set the `ui.always-allow-large-revsets` option to `true`, `jj` will 514behave as though the `all:` modifier was used every time it would matter. 515 516An `all:` modifier before a revset expression does not otherwise change its 517meaning. Strictly speaking, it is not part of the revset language. The notation 518is similar to the modifiers like `glob:` allowed before [string 519patterms](#string-patterns). 520 521For example, `jj rebase -r w -d xyz+` will rebase `w` on top of the child of 522`xyz` as long as `xyz` has exactly one child. 523 524If `xyz` has more than one child, the `all:` modifier is *not* specified, and 525`ui.always-allow-large-revsets` is `false` (the default), `jj rebase -r w -d 526xyz+` will return an error. 527 528If `ui.always-allow-large-revsets` was `true`, the above command would act as if 529`all:` was set (see the next paragraph). 530 531With the `all:` modifier, `jj rebase -r w -d all:xyz+` will make `w` into a merge 532commit if `xyz` has more than one child. The `all:` modifier confirms that the 533user expected `xyz` to have more than one child. 534 535A more useful example: if `w` is a merge commit, `jj rebase -s w -d all:w- -d 536xyz` will add `xyz` to the list of `w`'s parents. 537 538## Examples 539 540Show the parent(s) of the working-copy commit (like `git log -1 HEAD`): 541 542```shell 543jj log -r @- 544``` 545 546Show all ancestors of the working copy (like plain `git log`) 547 548```shell 549jj log -r ::@ 550``` 551 552Show commits not on any remote bookmark: 553 554```shell 555jj log -r 'remote_bookmarks()..' 556``` 557 558Show commits not on `origin` (if you have other remotes like `fork`): 559 560```shell 561jj log -r 'remote_bookmarks(remote=origin)..' 562``` 563 564Show the initial commits in the repo (the ones Git calls "root commits"): 565 566```shell 567jj log -r 'root()+' 568``` 569 570Show some important commits (like `git --simplify-by-decoration`): 571 572```shell 573jj log -r 'tags() | bookmarks()' 574``` 575 576Show local commits leading up to the working copy, as well as descendants of 577those commits: 578 579 580```shell 581jj log -r '(remote_bookmarks()..@)::' 582``` 583 584Show commits authored by "martinvonz" and containing the word "reset" in the 585description: 586 587```shell 588jj log -r 'author(martinvonz) & description(reset)' 589```