just playing with tangled
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at gvimdiff 1682 lines 55 kB view raw view rendered
1# Configuration 2 3These are the config settings available to jj/Jujutsu. 4 5 6## Config files and TOML 7 8`jj` loads several types of config settings: 9 10- The built-in settings. These cannot be edited. They can be viewed in the 11 `cli/src/config/` directory in `jj`'s source repo. 12 13- The user settings. These can be edited with `jj config edit --user`. User 14settings are located in [the user config files], which can be found with `jj 15config path --user`. 16 17- The repo settings. These can be edited with `jj config edit --repo` and are 18located in `.jj/repo/config.toml`. 19 20- Settings [specified in the command-line](#specifying-config-on-the-command-line). 21 22These are listed in the order they are loaded; the settings from earlier items 23in the list are overridden by the settings from later items if they disagree. 24Every type of config except for the built-in settings is optional. 25 26You can enable JSON Schema validation in your editor by adding a `$schema` 27reference at the top of your TOML config files. See [JSON Schema 28Support] for details. 29 30See the [TOML site] and the [syntax guide] for a detailed description of the 31syntax. We cover some of the basics below. 32 33[the user config files]: #user-config-files 34[TOML site]: https://toml.io/en/ 35[syntax guide]: https://toml.io/en/v1.0.0 36[JSON Schema Support]: #json-schema-support 37 38The first thing to remember is that the value of a setting (the part to the 39right of the `=` sign) should be surrounded in quotes if it's a string. 40 41### Dotted style and headings 42In TOML, anything under a heading can be dotted instead. For example, 43`user.name = "YOUR NAME"` is equivalent to: 44 45```toml 46[user] 47name = "YOUR NAME" 48``` 49 50For future reference, here are a couple of more complicated examples, 51 52```toml 53# Dotted style 54template-aliases."format_short_id(id)" = "id.shortest(12)" 55colors."commit_id prefix".bold = true 56 57# is equivalent to: 58[template-aliases] 59"format_short_id(id)" = "id.shortest(12)" 60 61[colors] 62"commit_id prefix" = { bold = true } 63``` 64 65The docs below refer to keys in text using dotted notation, but example 66blocks will use heading notation to be unambiguous. If you are confident with TOML 67then use whichever suits you in your config. If you mix dotted keys and headings, 68**you must put the dotted keys before the first heading**. 69 70That's probably enough TOML to keep you out of trouble but the [syntax guide] is 71very short if you ever need to check. 72 73 74## User settings 75 76```toml 77[user] 78name = "YOUR NAME" 79email = "YOUR_EMAIL@example.com" 80``` 81 82Don't forget to change these to your own details! 83 84## UI settings 85 86### Colorizing output 87 88Possible values are `always`, `never`, `debug` and `auto` (default: `auto`). 89`auto` will use color only when writing to a terminal. `debug` will print the 90active labels alongside the regular colorized output. 91 92This setting overrides the `NO_COLOR` environment variable (if set). 93 94```toml 95[ui] 96color = "never" # Turn off color 97``` 98 99### Custom colors and styles 100 101You can customize the colors used for various elements of the UI. For example: 102 103```toml 104[colors] 105commit_id = "green" 106``` 107 108The following colors are available: 109 110* black 111* red 112* green 113* yellow 114* blue 115* magenta 116* cyan 117* white 118* default 119 120All of them but "default" come in a bright version too, e.g. "bright red". The 121"default" color can be used to override a color defined by a parent style 122(explained below). 123 124You can also use a 6-digit hex code for more control over the exact color used: 125 126```toml 127[colors] 128change_id = "#ff1525" 129``` 130 131If you use a string value for a color, as in the examples above, it will be used 132for the foreground color. You can also set the background color, reverse colors 133(swap foreground and background), or make the text bold, italic, or underlined. 134For that, you need to use a table: 135 136```toml 137[colors] 138commit_id = { fg = "green", bg = "#ff1525", bold = true, underline = true } 139change_id = { reverse = true, italic = true } 140``` 141 142The key names are called "labels". The above used `commit_id` as label. You can 143also create rules combining multiple labels. The rules work a bit like CSS 144selectors. For example, if you want to color commit IDs green in general but 145make the commit ID of the working-copy commit also be underlined, you can do 146this: 147 148```toml 149[colors] 150commit_id = "green" 151"working_copy commit_id" = { underline = true } 152``` 153 154Parts of the style that are not overridden - such as the foreground color in the 155example above - are inherited from the style of the parent label. 156 157Which elements can be colored is not yet documented, but see 158the [default color configuration](https://github.com/jj-vcs/jj/blob/main/cli/src/config/colors.toml) 159for some examples of what's possible. 160 161### Default command 162 163When `jj` is run with no explicit subcommand, the value of the 164`ui.default-command` setting will be used instead. Possible values are any valid 165subcommand name, subcommand alias, or user-defined alias (defaults to `"log"`). 166 167```toml 168[ui] 169default-command = ["log", "--reversed"] 170``` 171 172### Default description 173 174The editor content of a commit description can be populated by the 175`draft_commit_description` template. 176 177```toml 178[templates] 179draft_commit_description = ''' 180concat( 181 coalesce(description, "\n"), 182 surround( 183 "\nJJ: This commit contains the following changes:\n", "", 184 indent("JJ: ", diff.stat(72)), 185 ), 186 "\nJJ: ignore-rest\n", 187 diff.git(), 188) 189''' 190``` 191 192The value of the `ui.default-description` setting can also be used in order to 193fill in things like BUG=, TESTED= etc. 194 195```toml 196[ui] 197default-description = "\n\nTESTED=TODO" 198``` 199 200### Diff colors and styles 201 202In color-words and git diffs, word-level hunks are rendered with underline. You 203can override the default style with the following keys: 204 205```toml 206[colors] 207# Highlight hunks with background 208"diff removed token" = { bg = "#221111", underline = false } 209"diff added token" = { bg = "#002200", underline = false } 210# Alternatively, swap colors 211"diff token" = { reverse = true, underline = false } 212``` 213 214### Diff format 215 216```toml 217[ui] 218# Possible values: "color-words" (default), "git", "summary" 219diff.format = "git" 220``` 221 222#### Color-words diff options 223 224In color-words diffs, changed words are displayed inline by default. Because 225it's difficult to read a diff line with many removed/added words, there's a 226threshold to switch to traditional separate-line format. You can also change 227the default number of lines of context shown. 228 229* `max-inline-alternation`: Maximum number of removed/added word alternation to 230 inline. For example, `<added> ... <added>` sequence has 1 alternation, so the 231 line will be inline if `max-inline-alternation >= 1`. `<added> ... <removed> 232 ... <added>` sequence has 3 alternation. 233 234 * `0`: disable inlining, making `--color-words` more similar to `--git` 235 * `1`: inline removes-only or adds-only lines 236 * `2`, `3`, ..: inline up to `2`, `3`, .. alternation 237 * `-1`: inline all lines 238 239 The default is `3`. 240 241 **This parameter is experimental.** The definition is subject to change. 242* `context`: Number of lines of context to show in the diff. The default is `3`. 243 244```toml 245[diff.color-words] 246max-inline-alternation = 3 247context = 3 248``` 249 250#### Git diff options 251 252In git diffs you can change the default number of lines of context shown. 253 254* `context`: Number of lines of context to show in the diff. The default is `3`. 255 256```toml 257[diff.git] 258context = 3 259``` 260 261### Generating diffs by external command 262 263If `ui.diff.tool` is set, the specified diff command will be called instead of 264the internal diff function. 265 266```toml 267[ui] 268# Use Difftastic by default 269diff.tool = ["difft", "--color=always", "$left", "$right"] 270# Use tool named "<name>" (see below) 271diff.tool = "<name>" 272``` 273 274The external diff tool can also be enabled by `diff --tool <name>` argument. 275For the tool named `<name>`, command arguments can be configured as follows. 276 277```toml 278[merge-tools.<name>] 279# program = "<name>" # Defaults to the name of the tool if not specified 280diff-args = ["--color=always", "$left", "$right"] 281``` 282 283- `$left` and `$right` are replaced with the paths to the left and right 284 directories to diff respectively. 285 286By default `jj` will invoke most external tools with a directory containing the left 287and right sides. 288 289For diff tools, the `diff-invocation-mode` config can be used to toggle between 290this behavior and file-by-file invocations: 291 292```toml 293[ui] 294diff.tool = "gvimdiff" 295 296[merge-tools.gvimdiff] 297diff-invocation-mode = "dir" # Or "file-by-file" 298``` 299 300By default `jj` will display a warning when the command exits with a non-success 301error code. The `diff-expected-exit-codes` config can suppress this warning 302message for specific exit codes: 303 304```toml 305[merge-tools.delta] 306diff-expected-exit-codes = [0, 1] 307``` 308 309### Conflict marker style 310 311You can configure which style of conflict markers to use when materializing 312conflicts: 313 314```toml 315[ui] 316# Shows a single snapshot and one or more diffs to apply to it 317conflict-marker-style = "diff" 318# Shows a snapshot for each side and base of the conflict 319conflict-marker-style = "snapshot" 320# Uses Git's "diff3" conflict markers to support tools that depend on it 321conflict-marker-style = "git" 322``` 323 324For more details about these conflict marker styles, see the [conflicts 325page](conflicts.md#conflict-markers). 326 327### Set of immutable commits 328 329You can configure the set of immutable commits via 330`revset-aliases."immutable_heads()"`. The default set of immutable heads is 331`builtin_immutable_heads()`, which in turn is defined as 332`present(trunk()) | tags() | untracked_remote_bookmarks()`. For example, to 333also consider the `release@origin` bookmark immutable: 334 335```toml 336[revset-aliases] 337"immutable_heads()" = "builtin_immutable_heads() | release@origin" 338``` 339 340To prevent rewriting commits authored by other users: 341 342```toml 343# The `trunk().. &` bit is an optimization to scan for non-`mine()` commits 344# only among commits that are not in `trunk()`. 345[revset-aliases] 346"immutable_heads()" = "builtin_immutable_heads() | (trunk().. & ~mine())" 347``` 348 349Ancestors of the configured set are also immutable. The root commit is always 350immutable even if the set is empty. 351 352Immutable commits (other than the root commit) can be rewritten using the 353`--ignore-immutable` CLI flag. 354 355!!! warning 356 357 Using `--ignore-immutable` will allow you to rewrite any commit in the 358 history, and all descendants, without warning. Use this power wisely, and 359 remember `jj undo`. 360 361### Behavior of prev and next commands 362 363If you prefer using an "edit-based" workflow, rather than squashing 364modifications into parent changes, you may find yourself using the `prev` and 365`next` commands with their `--edit` flag often to move between your changes. You 366can avoid having to type the `--edit` flag every time you need it by actually 367making it the default: 368 369```toml 370[ui.movement] 371edit = true 372``` 373 374You can pass the `--no-edit` flag to `prev` and `next` if you find yourself 375needing the original behavior. 376 377## List 378 379### Default Template 380 381You can configure the template used when no `-T` is specified. 382 383- `templates.config_list` for `jj config list` 384 385```toml 386[templates] 387# Use builtin config list template 388config_list = "builtin_config_list" 389``` 390 391If you want to see the config variable origin (type and path) when you do `jj config list` 392you can add this to your config: 393 394```toml 395[templates] 396config_list = "builtin_config_list_detailed" 397``` 398 399 400## Log 401 402### Default revisions 403 404You can configure the revisions `jj log` would show when neither `-r` nor any paths are specified. 405 406```toml 407[revsets] 408# Show commits that are not in `main@origin` 409log = "main@origin.." 410``` 411 412The default value for `revsets.log` is 413`'present(@) | ancestors(immutable_heads().., 2) | present(trunk())'`. 414 415### Default Template 416 417You can configure the template used when no `-T` is specified. 418 419- `templates.log` for `jj log` 420- `templates.op_log` for `jj op log` 421- `templates.show` for `jj show` 422 423```toml 424[templates] 425# Use builtin log template 426log = "builtin_log_compact" 427# Use builtin op log template 428op_log = "builtin_op_log_compact" 429# Use builtin show template 430show = "builtin_log_detailed" 431``` 432 433If you want to see the full description when you do `jj log` you can add this to 434your config: 435 436```toml 437[templates] 438log = "builtin_log_compact_full_description" 439``` 440 441### Graph style 442 443```toml 444[ui] 445# Possible values: "curved" (default), "square", "ascii", "ascii-large" 446graph.style = "square" 447``` 448 449#### Node style 450 451The symbols used to represent commits or operations can be customized via 452templates. 453 454- `templates.log_node` for commits (with `Option<Commit>` keywords) 455- `templates.op_log_node` for operations (with `Operation` keywords) 456 457For example: 458```toml 459[templates] 460log_node = ''' 461coalesce( 462 if(!self, "🮀"), 463 if(current_working_copy, "@"), 464 if(root, "┴"), 465 if(immutable, "●", "○"), 466) 467''' 468op_log_node = 'if(current_operation, "@", "○")' 469``` 470 471### Wrap log content 472 473If enabled, `log`/`evolog`/`op log` content will be wrapped based on 474the terminal width. 475 476```toml 477[ui] 478log-word-wrap = true 479``` 480 481### Display of commit and change ids 482 483Can be customized by the `format_short_id()` template alias. 484 485```toml 486[template-aliases] 487# Highlight unique prefix and show at least 12 characters (default) 488'format_short_id(id)' = 'id.shortest(12)' 489# Just the shortest possible unique prefix 490'format_short_id(id)' = 'id.shortest()' 491# Show unique prefix and the rest surrounded by brackets 492'format_short_id(id)' = 'id.shortest(12).prefix() ++ "[" ++ id.shortest(12).rest() ++ "]"' 493# Always show 12 characters 494'format_short_id(id)' = 'id.short(12)' 495``` 496 497To customize these separately, use the `format_short_commit_id()` and 498`format_short_change_id()` aliases: 499 500```toml 501[template-aliases] 502# Uppercase change ids. `jj` treats change and commit ids as case-insensitive. 503'format_short_change_id(id)' = 'format_short_id(id).upper()' 504``` 505 506Operation ids can be customized by the `format_short_operation_id()` alias: 507 508```toml 509[template-aliases] 510# Always show 12 characters 511'format_short_operation_id(id)' = 'id.short(12)' 512``` 513 514To get shorter prefixes for certain revisions, set `revsets.short-prefixes`: 515 516```toml 517[revsets] 518# Prioritize the current bookmark 519short-prefixes = "(main..@)::" 520``` 521 522### Relative timestamps 523 524Can be customized by the `format_timestamp()` template alias. 525 526```toml 527[template-aliases] 528# Full timestamp in ISO 8601 format 529'format_timestamp(timestamp)' = 'timestamp' 530# Relative timestamp rendered as "x days/hours/seconds ago" 531'format_timestamp(timestamp)' = 'timestamp.ago()' 532``` 533 534`jj op log` defaults to relative timestamps. To use absolute timestamps, you 535will need to modify the `format_time_range()` template alias. 536 537```toml 538[template-aliases] 539'format_time_range(time_range)' = 'time_range.start() ++ " - " ++ time_range.end()' 540``` 541 542### Author format 543 544Can be customized by the `format_short_signature()` template alias. 545 546```toml 547[template-aliases] 548# Full email address (default) 549'format_short_signature(signature)' = 'signature.email()' 550# Both name and email address 551'format_short_signature(signature)' = 'signature' 552# Username part of the email address 553'format_short_signature(signature)' = 'signature.username()' 554``` 555 556### Commit timestamp 557 558Commits have both an "author timestamp" and "committer timestamp". By default, 559jj displays the committer timestamp, but can be changed to show the author 560timestamp instead. 561 562The function must return a timestamp because the return value will likely be 563formatted with `format_timestamp()`. 564 565```toml 566[template-aliases] 567'commit_timestamp(commit)' = 'commit.author().timestamp()' 568``` 569 570### Signature format 571 572Can be enabled with `ui.show-cryptographic-signatures`, and 573customized with `format_short_cryptographic_signature(sig)` and 574`format_detailed_cryptographic_signature(sig)`. 575 576Note that the formatting functions take an `Option<CryptographicSignature>`. 577This allows you to emit a custom message if a signature is not present, but 578will raise an error if you try to access methods on a signature that is not 579available. 580 581```toml 582[ui] 583# default is false 584show-cryptographic-signatures = true 585 586[template-aliases] 587'format_short_cryptographic_signature(sig)' = ''' 588 if(sig, 589 sig.status(), 590 "(no sig)", 591 ) 592''' 593``` 594 595## Allow "large" revsets by default 596 597Certain commands (such as `jj rebase`) can take multiple revset arguments, but 598default to requiring each of those revsets to expand to a *single* revision. 599This restriction can be overridden by prefixing a revset that the user wants to 600be able to expand to more than one revision with the [`all:` 601modifier](revsets.md#the-all-modifier). 602 603Another way you can override this check is by setting 604`ui.always-allow-large-revsets` to `true`. Then, `jj` will allow every one of 605the revset arguments of such commands to expand to any number of revisions. 606 607```toml 608[ui] 609# Assume `all:` prefix before revsets whenever it would make a difference 610always-allow-large-revsets = true 611``` 612 613## Pager 614 615The default pager is can be set via `ui.pager` or the `PAGER` environment 616variable. The priority is as follows (environment variables are marked with 617a `$`): 618 619`ui.pager` > `$PAGER` 620 621`less -FRX` is the default pager in the absence of any other setting, except 622on Windows where it is `:builtin`. 623 624The special value `:builtin` enables usage of the [integrated 625pager](#builtin-pager). 626 627If you are using a standard Linux distro, your system likely already has 628`$PAGER` set and that will be preferred over the built-in. To use the built-in: 629 630```shell 631jj config set --user ui.pager :builtin 632``` 633 634It is possible the default will change to `:builtin` for all platforms in the 635future. 636 637Additionally, paging behavior can be toggled via `ui.paginate` like so: 638 639```toml 640[ui] 641# Enable pagination for commands that support it (default) 642paginate = "auto" 643# Disable all pagination, equivalent to using --no-pager 644paginate = "never" 645``` 646 647### Builtin pager 648 649Our builtin pager is based on 650[`streampager`](https://github.com/markbt/streampager/) but is configured within 651`jj`'s config. It is configured via the `ui.streampager` table. 652 653#### Key bindings 654 655The built-in pager supports both navigation via arrows and Vim-style navigation. 656Beyond that, here are some useful keybindings for the pager: 657 658| Key | Action | 659| :-------------- | :-------------------- | 660| `Ctrl-c` or `q` | Quit | 661| `h` or `F1` | Show all key bindings | 662| `Esc` | Close help or prompt | 663| `\` | Toggle line wrapping | 664| `#` | Toggle line numbers | 665| `Ctrl-r` | Toggle the ruler | 666 667The built-in pager does not support mouse input. 668 669#### Wrapping config 670 671Wrapping performed by the pager happens *in addition to* any 672wrapping that `jj` itself does. 673 674```toml 675[ui.streampager] 676wrapping = "anywhere" # wrap at screen edge (default) 677wrapping = "word" # wrap on word boundaries 678wrapping = "none" # strip long lines, allow scrolling 679 # left and right like `less -S` 680``` 681 682#### Auto-exit, clearing the screen on startup or exit 683 684You can configure whether the pager clears the screen on startup or exit, and 685whether it quits automatically on short inputs. When the pager auto-quits, 686features like word-wrapping are disabled. 687 688```toml 689[ui.streampager] 690# Do not clear screen on exit. Use a full-screen interface for long 691# output only. Like `less -FX`. 692interface = "quit-if-one-page" # (default). 693# Always use a full-screen interface, ask the terminal to clear the 694# screen on exit. Like `less -+FX`. 695interface = "full-screen-clear-output" 696# Use the alternate screen if the input is either long or takes more 697# than 2 seconds to finish. Similar but not identical to `less -F -+X`. 698interface = "quit-quickly-or-clear-output" 699``` 700 701 702### Processing contents to be paged 703 704If you'd like to pass the output through a formatter e.g. 705[`diff-so-fancy`](https://github.com/so-fancy/diff-so-fancy) before piping it 706through a pager you must do it using a subshell as, unlike `git` or `hg`, the 707command will be executed directly. For example: 708 709```toml 710[ui] 711pager = ["sh", "-c", "diff-so-fancy | less -RFX"] 712``` 713 714Some formatters (like [`delta`](https://github.com/dandavison/delta)) require 715git style diffs for formatting. You can configure this style of 716diff as the default with the `ui.diff` setting. For example: 717 718```toml 719[ui] 720pager = "delta" 721 722[ui.diff] 723format = "git" 724``` 725 726## Aliases 727 728You can define aliases for commands, including their arguments. For example: 729 730```toml 731[aliases] 732# `jj l` shows commits on the working-copy commit's (anonymous) bookmark 733# compared to the `main` bookmark 734l = ["log", "-r", "(main..@):: | (main..@)-"] 735``` 736 737This alias syntax can only run a single jj command. However, you may want to 738execute multiple jj commands with a single alias, or run arbitrary scripts that 739complement your version control workflow. This can be done, but be aware of the 740danger: 741 742!!! warning 743 744 The following technique just provides a convenient syntax for running 745 arbitrary code on your system. Using it irresponsibly may cause damage 746 ranging from breaking the behavior of `jj undo` to wiping your file system. 747 Exercise the same amount of caution while writing these aliases as you would 748 when typing commands into the terminal! 749 750 This feature may be removed or replaced by an embedded scripting language in 751 the future. 752 753The command `jj util exec` will simply run any command you pass to it as an 754argument. Additional arguments are passed through. Here are some examples: 755 756```toml 757[aliases] 758my-script = ["util", "exec", "--", "my-jj-script"] 759# ^^^^ 760# This makes sure that flags are passed to your script instead of parsed by jj. 761my-inline-script = ["util", "exec", "--", "bash", "-c", """ 762#!/usr/bin/env bash 763set -euo pipefail 764echo "Look Ma, everything in one file!" 765echo "args: $@" 766""", ""] 767# ^^ 768# This last empty string will become "$0" in bash, so your actual arguments 769# are all included in "$@" and start at "$1" as expected. 770``` 771 772## Editor 773 774The default editor is set via `ui.editor`, though there are several places to 775set it. The priority is as follows (environment variables are marked with 776a `$`): 777 778`$JJ_EDITOR` > `ui.editor` > `$VISUAL` > `$EDITOR` 779 780Pico is the default editor (Notepad on Windows) in the absence of any other 781setting, but you could set it explicitly too. 782 783```toml 784[ui] 785editor = "pico" 786``` 787 788To use NeoVim instead: 789 790```toml 791[ui] 792editor = "nvim" 793``` 794 795For GUI editors you possibly need to use a `-w` or `--wait`. Some examples: 796 797```toml 798[ui] 799editor = "code -w" # VS Code 800editor = "code.cmd -w" # VS Code on Windows 801editor = "bbedit -w" # BBEdit 802editor = "subl -n -w" # Sublime Text 803editor = "mate -w" # TextMate 804editor = ["C:/Program Files/Notepad++/notepad++.exe", 805 "-multiInst", "-notabbar", "-nosession", "-noPlugin"] # Notepad++ 806editor = "idea --temp-project --wait" #IntelliJ 807``` 808 809Obviously, you would only set one line, don't copy them all in! 810 811## Editing diffs 812 813The `ui.diff-editor` setting affects the default tool used for editing diffs 814(e.g. `jj split`, `jj squash -i`). If it is not set, the special value 815`:builtin` is used. It launches a built-in TUI tool (known as [scm-diff-editor]) 816to edit the diff in your terminal. 817 818[scm-diff-editor]: https://github.com/arxanas/scm-record?tab=readme-ov-file#scm-diff-editor 819 820You can try a different tool temporarily by doing e.g. `jj split --tool meld` or 821you can set the option to change the default. This requires that you have an 822appropriate tool installed, see for example [the instructions for using 823Meld](#using-meld-as-a-diff-editor). 824 825**Suggestion:** If possible, it is recommended to try an external diff tool like 826[Meld](#using-meld-as-a-diff-editor) (see below for some other possibilities) 827for splitting commits and other diff editing, in addition to the built-in diff 828editor. It is good to know the capabilities of both. The built-in diff editor 829does not require external tools to be available, is faster for tasks like 830picking hunks, and does not require leaving the terminal. External tools give 831you the flexibility of picking out portions of lines from the diff or even 832arbitrarily editing the text of the files. 833 834If `ui.diff-editor` is a string, e.g. `"meld"`, the arguments will be read from 835the following config keys. 836 837```toml 838[merge-tools.meld] 839# program = "meld" # Defaults to the name of the tool if not specified 840program = "/path/to/meld" # May be necessary if `meld` is not in the PATH 841edit-args = ["--newtab", "$left", "$right"] 842``` 843 844`jj` makes the following substitutions: 845 846- `$left` and `$right` are replaced with the paths to the left and right 847 directories to diff respectively. 848 849- If no `edit-args` are specified, `["$left", "$right"]` are set by default. 850 851Finally, `ui.diff-editor` can be a list that specifies a command and its arguments. 852 853Some examples: 854 855```toml 856[ui] 857# Use merge-tools.meld.edit-args 858diff-editor = "meld" # Or `kdiff3`, or `diffedit3`, ... 859# Specify edit-args inline 860diff-editor = ["/path/to/binary", "--be-helpful", "$left", "$right"] 861# Equivalent to ["binary", "$left", "$right"] arguments by default 862diff-editor = "binary" 863``` 864 865 866### Experimental 3-pane diff editing 867 868We offer two special "3-pane" diff editor configs: 869 870- `meld-3`, which requires installing [Meld](https://meldmerge.org/), and 871- `diffedit3`, which requires installing [`diffedit3`](https://github.com/ilyagr/diffedit3/releases). 872 873`Meld` is a graphical application that is recommended, but can be difficult to 874install in some situations. `diffedit3` is designed to be easy to install and to 875be usable in environments where Meld is difficult to use (e.g. over SSH via port 876forwarding). `diffedit3` starts a local server that can be accessed via a web 877browser, similarly to [Jupyter](https://jupyter.org/). 878 879There is also the `diffedit3-ssh` which is similar to `diffedit3` but does not 880try to open the web browser pointing to the local server (the URL 881printed to the terminal) automatically. `diffedit3-ssh` also always uses ports in between 88217376-17380 and fails if they are all busy. This can be useful when working 883over SSH. Open the fold below for more details of how to set that up. 884 885<details> 886<summary> Tips for using `diffedit3-ssh` over SSH </summary> 887 888To use `diffedit3` over SSH, you need to set up port forwarding. One way to do 889this is to start SSH as follows (copy-paste the relevant lines): 890 891```shell 892ssh -L 17376:localhost:17376 \ 893 -L 17377:localhost:17377 \ 894 -L 17378:localhost:17378 \ 895 -L 17379:localhost:17379 \ 896 -L 17380:localhost:17380 \ 897 myhost.example.com 898``` 899 900`diffedit3-ssh` is set up to use these 5 ports by default. Usually, only the 901first of them will be used. The rest are used if another program happens to use 902one of them, or if you run multiple instances of `diffedit3` at the same time. 903 904Another way is to add a snippet to `~/.ssh/config`: 905 906```ssh-config 907Host myhost 908 User myself 909 Hostname myhost.example.com 910 LocalForward 17376 localhost:17376 911 LocalForward 17377 localhost:17377 912 LocalForward 17378 localhost:17378 913 LocalForward 17379 localhost:17379 914 LocalForward 17380 localhost:17380 915``` 916 917With that configuration, you should be able to simply `ssh myhost`. 918 919</details> 920 921 922Setting either `ui.diff-editor = "meld-3"` or `ui.diff-editor = "diffedit3"` 923will result in the diff editor showing 3 panes: the diff on the left and right, 924and an editing pane in the middle. This allow you to see both sides of the 925original diff while editing. 926 927If you use `ui.diff-editor = "meld-3"`, note that you can still get the 2-pane 928Meld view using `jj diff --tool meld`. `diffedit3` has a button you can use to 929switch to a 2-pane view. 930 931To configure other diff editors in this way, you can include `$output` together 932with `$left` and `$right` in `merge-tools.TOOL.edit-args`. `jj` will replace 933`$output` with the directory where the diff editor will be expected to put the 934result of the user's edits. Initially, the contents of `$output` will be the 935same as the contents of `$right`. 936 937### `JJ-INSTRUCTIONS` 938 939When editing a diff, jj will include a synthetic file called `JJ-INSTRUCTIONS` 940in the diff with instructions on how to edit the diff. Any changes you make to 941this file will be ignored. To suppress the creation of this file, set 942`ui.diff-instructions = false`. 943 944### Using Meld as a diff editor 945 946[Meld](https://meldmerge.org) is a nice and polished free diff editor. It can be 947obtained as follows: 948 949- **Linux:** use your favorite package manager, e.g. `sudo apt install meld`. 950 951- **Windows:** Meld can be downloaded from <https://meldmerge.org/>. 952 953- **Mac OS:** Install Homebrew and run `brew install --cask dehesselle-meld`. 954 This will install both an app in `/Applications/Meld.app` and the command-line 955 `meld` command that `jj` uses. You can read about [more details and other 956 options](https://gist.github.com/ilyagr/1b40f6061d8ad320cee4c12843df1a23) but, 957 as of this writing, this is by far the easiest. 958 959 !!! warning 960 961 Do *not* use the Homebrew `meld` package. 962 It does not work on ARM Macs and may have problems on recent versions of macOS. 963 964`jj` has two diff editing configurations that use Meld: `meld` for a 2-pane view 965and `meld-3` for a [three-pane view](#experimental-3-pane-diff-editing). 966 967There is also a `meld` [merge tool](#3-way-merge-tools-for-conflict-resolution) 968that can be useful, but does not support displaying the merge base while 969merging. 970 971### Using Vim as a diff editor 972 973Using `ui.diff-editor = "vimdiff"` is possible but not recommended. For a better 974experience, you can follow [instructions from the Wiki] to configure the 975[DirDiff Vim plugin] and/or the [vimtabdiff Python script]. 976 977[instructions from the Wiki]: https://github.com/jj-vcs/jj/wiki/Vim#using-vim-as-a-diff-tool 978 979[DirDiff Vim plugin]: https://github.com/will133/vim-dirdiff 980[vimtabdiff Python script]: https://github.com/balki/vimtabdiff 981 982## 3-way merge tools for conflict resolution 983 984The `ui.merge-editor` key specifies the tool used for three-way merge tools 985by `jj resolve`. For example: 986 987```toml 988[ui] 989# Use merge-tools.meld.merge-args 990merge-editor = "meld" # Or "vscode" or "vscodium" or "kdiff3" or "vimdiff" 991# Specify merge-args inline 992merge-editor = ["meld", "$left", "$base", "$right", "-o", "$output"] 993``` 994 995The "vscode", "vscodium", "meld", "kdiff3", and "vimdiff" tools can be used out of the box, 996as long as they are installed. 997 998Using VS Code as a merge tool works well with VS Code's [Remote 999Development](https://code.visualstudio.com/docs/remote/remote-overview) 1000functionality, as long as `jj` is called from VS Code's terminal. 1001 1002### Setting up a custom merge tool 1003 1004To use a different tool named `TOOL`, the arguments to pass to the tool MUST be 1005specified either inline or in the `merge-tools.TOOL.merge-args` key. As an 1006example of how to set this key and other tool configuration options, here is 1007the out-of-the-box configuration of the three default tools. (There is no need 1008to copy it to your config file verbatim, but you are welcome to customize it.) 1009 1010```toml 1011[merge-tools.kdiff3] 1012# program = "kdiff3" # Defaults to the name of the tool if not specified 1013merge-args = ["$base", "$left", "$right", "-o", "$output", "--auto"] 1014[merge-tools.meld] 1015merge-args = ["$left", "$base", "$right", "-o", "$output", "--auto-merge"] 1016 1017[merge-tools.vimdiff] 1018merge-args = ["-f", "-d", "$output", "-M", 1019 "$left", "$base", "$right", 1020 "-c", "wincmd J", "-c", "set modifiable", 1021 "-c", "set write"] 1022program = "vim" 1023merge-tool-edits-conflict-markers = true # See below for an explanation 1024``` 1025 1026`jj` makes the following substitutions: 1027 1028- `$output` (REQUIRED) is replaced with the name of the file that the merge tool 1029 should output. `jj` will read this file after the merge tool exits. 1030 1031- `$left` and `$right` are replaced with the paths to two files containing the 1032 content of each side of the conflict. 1033 1034- `$base` is replaced with the path to a file containing the contents of the 1035 conflicted file in the last common ancestor of the two sides of the conflict. 1036 1037- `$marker_length` is replaced with the length of the conflict markers which 1038 should be used for the file. This can be useful if the merge tool parses 1039 and/or generates conflict markers. Usually, `jj` uses conflict markers of 1040 length 7, but they can be longer if necessary to make parsing unambiguous. 1041 1042### Editing conflict markers with a tool or a text editor 1043 1044By default, the merge tool starts with an empty output file. If the tool puts 1045anything into the output file and exits with the 0 exit code, 1046`jj` assumes that the conflict is fully resolved, while if the tool exits with 1047a non-zero exit code, `jj` assumes that the merge should be cancelled. 1048This is appropriate for most graphical merge tools. 1049 1050For merge tools which try to automatically resolve conflicts without user input, 1051this behavior may not be desired. For instance, some automatic merge tools use 1052an exit code of 1 to indicate that some conflicts were unable to be resolved and 1053that the output file should contain conflict markers. In that case, you could 1054set the config option `merge-tools.TOOL.merge-conflict-exit-codes = [1]` to tell 1055`jj` to expect conflict markers in the output file if the exit code is 1. If a 1056merge tool produces output using Git's "diff3" conflict style, `jj` should be 1057able to parse it correctly, so many Git merge drivers should be usable with `jj` 1058as well. 1059 1060Some tools (e.g. `vimdiff`) can present a multi-way diff but don't resolve 1061conflict themselves. When using such tools, `jj` 1062can help you by populating the output file with conflict markers before starting 1063the merge tool (instead of leaving the output file empty and letting the merge 1064tool fill it in). To do that, set the 1065`merge-tools.vimdiff.merge-tool-edits-conflict-markers = true` option. 1066 1067With this option set, if the output file still contains conflict markers after 1068the conflict is done, `jj` assumes that the conflict was only partially resolved 1069and parses the conflict markers to get the new state of the conflict. The 1070conflict is considered fully resolved when there are no conflict markers left. 1071The conflict marker style can also be customized per tool using the 1072`merge-tools.TOOL.conflict-marker-style` option, which takes the same values as 1073[`ui.conflict-marker-style`](#conflict-marker-style). 1074 1075## Code formatting and other file content transformations 1076 1077The `jj fix` command allows you to efficiently rewrite files in complex commit 1078graphs with no risk of introducing conflicts, using tools like `clang-format` or 1079`prettier`. The tools run as subprocesses that take file content on standard 1080input and repeat it, with any desired changes, on standard output. The file is 1081only rewritten if the subprocess produces a successful exit code. 1082 1083### Enforce coding style rules 1084 1085Suppose you want to use `clang-format` to format your `*.c` and `*.h` files, 1086as well as sorting their `#include` directives. 1087 1088`jj fix` provides the file content anonymously on standard input, but the name 1089of the file being formatted may be important for include sorting or other output 1090like error messages. To address this, you can use the `$path` substitution to 1091provide the name of the file in a command argument. 1092 1093```toml 1094[fix.tools.clang-format] 1095command = ["/usr/bin/clang-format", "--sort-includes", "--assume-filename=$path"] 1096patterns = ["glob:'**/*.c'", 1097 "glob:'**/*.h'"] 1098``` 1099 1100### Sort and remove duplicate lines from a file 1101 1102`jj fix` can also be used with tools that are not considered code formatters. 1103 1104Suppose you have a list of words in a text file in your repository, and you want 1105to keep the file sorted alphabetically and remove any duplicate words. 1106 1107```toml 1108[fix.tools.sort-word-list] 1109command = ["sort", "-u"] 1110patterns = ["word_list.txt"] 1111``` 1112 1113### Execution order of tools 1114 1115If two or more tools affect the same file, they are executed in the ascending 1116lexicographical order of their configured names. This will remain as a tie 1117breaker if other ordering mechanisms are introduced in the future. If you use 1118numbers in tool names to control execution order, remember to include enough 1119leading zeros so that, for example, `09` sorts before `10`. 1120 1121Suppose you want to keep only the 10 smallest numbers in a text file that 1122contains one number on each line. This can be accomplished with `sort` and 1123`head`, but execution order is important. 1124 1125```toml 1126[fix.tools.1-sort-numbers-file] 1127command = ["sort", "-n"] 1128patterns = ["numbers.txt"] 1129 1130[fix.tools.2-truncate-numbers-file] 1131command = ["head", "-n", "10"] 1132patterns = ["numbers.txt"] 1133``` 1134 1135### Disabling and enabling tools 1136 1137Tools can be disabled and enabled with the optional `enabled` config. This 1138allows you to define tools globally but enable them only for specific 1139repositories. 1140 1141In the user configuration, define a disabled tool for running rustfmt: 1142 1143```toml 1144[fix.tools.rustfmt] 1145enabled = false 1146command = ["rustfmt", "--emit", "stdout"] 1147patterns = ["glob:'**/*.rs'"] 1148``` 1149 1150Then to use the tool in a specific repository, set the `enabled` config: 1151 1152```shell 1153$ jj config set --repo fix.tools.rustfmt.enabled true 1154``` 1155 1156## Commit Signing 1157 1158`jj` can be configured to sign and verify the commits it creates using either 1159GnuPG or SSH signing keys. 1160 1161To do this you need to configure a signing backend. 1162 1163Setting the backend to `"none"` disables signing. 1164 1165### GnuPG Signing 1166 1167```toml 1168[signing] 1169behavior = "own" 1170backend = "gpg" 1171## You can set `key` to anything accepted by `gpg -u` 1172## If not set then defaults to the key associated with `user.email` 1173# key = "4ED556E9729E000F" 1174# key = "signing@example.com" 1175``` 1176 1177By default the gpg backend will look for a `gpg` binary on your path. If you want 1178to change the program used or specify a path to `gpg` explicitly you can set: 1179 1180```toml 1181[signing] 1182backends.gpg.program = "gpg2" 1183``` 1184 1185Also by default the gpg backend will consider key expiry when verifying commit signatures. 1186To consider expired keys as valid you can set: 1187 1188```toml 1189[signing] 1190backends.gpg.allow-expired-keys = true 1191``` 1192 1193#### PKCS#12 Certificates 1194 1195PKCS#12 certificates can be used to sign commits using the `gpgsm` backend. 1196 1197```toml 1198[signing] 1199behavior = "own" 1200backend = "gpgsm" 1201## You can set `key` to anything accepted by `gpgsm -u` 1202## If not set then defaults to the key associated with `user.email` 1203# key = "4ED556E9729E000F" 1204# key = "signing@example.com" 1205``` 1206 1207By default the gpgsm backend will look for a `gpgsm` binary on your path. If you want 1208to change the program used or specify a path to `gpgsm` explicitly you can set: 1209 1210```toml 1211[signing] 1212backends.gpgsm.program = "gpgsm" 1213``` 1214 1215Also by default the gpgsm backend will consider key expiry when verifying commit signatures. 1216To consider expired keys as valid you can set: 1217 1218```toml 1219[signing] 1220backends.gpgsm.allow-expired-keys = true 1221``` 1222 1223### SSH Signing 1224 1225```toml 1226[signing] 1227behavior = "own" 1228backend = "ssh" 1229key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGj+J6N6SO+4P8dOZqfR1oiay2yxhhHnagH52avUqw5h" 1230## You can also use a path instead of embedding the key 1231# key = "~/.ssh/id_for_signing.pub" 1232``` 1233 1234By default the ssh backend will look for a `ssh-keygen` binary on your path. If you want 1235to change the program used or specify a path to `ssh-keygen` explicitly you can set: 1236 1237```toml 1238[signing] 1239backends.ssh.program = "/path/to/ssh-keygen" 1240``` 1241 1242When verifying commit signatures the ssh backend needs to be provided with an allowed-signers 1243file containing the public keys of authors whose signatures you want to be able to verify. 1244 1245You can find the format for this file in the 1246[ssh-keygen man page](https://man.openbsd.org/ssh-keygen#ALLOWED_SIGNERS). This can be provided 1247as follows: 1248 1249```toml 1250[signing] 1251backends.ssh.allowed-signers = "/path/to/allowed-signers" 1252``` 1253 1254### Sign commits only on `jj git push` 1255 1256Instead of signing all commits during creation when `signing.behavior` is 1257set to `own`, the `git.sign-on-push` configuration can be used to sign 1258commits only upon running `jj git push`. All mutable unsigned commits 1259being pushed will be signed prior to pushing. This might be preferred if the 1260signing backend requires user interaction or is slow, so that signing is 1261performed in a single batch operation. 1262 1263```toml 1264# Configure signing backend as before, but lazily signing only on push. 1265[signing] 1266behavior = "drop" 1267backend = "ssh" 1268key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGj+J6N6SO+4P8dOZqfR1oiay2yxhhHnagH52avUqw5h" 1269 1270[git] 1271sign-on-push = true 1272``` 1273 1274### Manually signing commits 1275 1276You can use [`jj sign`](./cli-reference.md#jj-sign)/[`jj unsign`](./cli-reference.md#jj-unsign) 1277to sign/unsign commits manually. 1278 1279 1280!!! warning 1281 1282 `jj sign` is always signing commits, even if they are already signed by the 1283 user. While this is cumbersome for users signing via hardware devices, we 1284 cannot reliably check if a commit is already signed without creating a 1285 signature (see [this issue](https://github.com/jj-vcs/jj/issues/5786)). 1286 1287## Commit Signature Verification 1288 1289By default signature verification and display is **disabled** as it incurs a 1290performance cost when rendering medium to large change logs. 1291 1292If you want to display commit signatures in your templates, you can use 1293`commit.signature()` (see [Commit type](./templates.md#commit-type)). The 1294returned [CryptographicSignature 1295Type](./templates.md#cryptographicsignature-type) provides methods to retrieve 1296signature details. 1297 1298## Git settings 1299 1300### Default remotes for `jj git fetch` and `jj git push` 1301 1302By default, if a single remote exists it is used for `jj git fetch` and `jj git 1303push`; however if multiple remotes exist, the default remote is assumed to be 1304named `"origin"`, just like in Git. Sometimes this is undesirable, e.g. when you 1305want to fetch from a different remote than you push to, such as a GitHub fork. 1306 1307To change this behavior, you can modify the [repository 1308configuration](#config-files-and-toml) variable `git.fetch`, which can be a 1309single remote, or a list of remotes to fetch from multiple places: 1310 1311```sh 1312jj config set --repo git.fetch "upstream" 1313jj config set --repo git.fetch '["origin", "upstream"]' 1314``` 1315 1316By default, the specified remote names matches exactly. You can also use a 1317[string pattern](revsets.md#string-patterns) to select remotes using patterns: 1318 1319```sh 1320jj config set --repo git.fetch "glob:*" 1321jj config set --repo git.fetch '["glob:remote*", "glob:upstream*"]' 1322``` 1323 1324Similarly, you can also set the variable `git.push` to cause `jj git push` to 1325push to a different remote: 1326 1327```sh 1328jj config set --repo git.push "github" 1329``` 1330 1331Note that unlike `git.fetch`, `git.push` can currently only be a single remote. 1332This is not a hard limitation, and could be changed in the future if there is 1333demand. 1334 1335### Automatic local bookmark creation 1336 1337When `jj` imports a new remote-tracking bookmark from Git, it can also create a 1338local bookmark with the same name. This feature is disabled by default because it 1339may be undesirable in some repositories, e.g.: 1340 1341- There is a remote with a lot of historical bookmarks that you don't 1342 want to be exported to the co-located Git repo. 1343- There are multiple remotes with conflicting views of that bookmark, 1344 resulting in an unhelpful conflicted state. 1345 1346You can enable this behavior by setting `git.auto-local-bookmark` like so, 1347 1348```toml 1349[git] 1350auto-local-bookmark = true 1351``` 1352 1353This setting is applied only to new remote bookmarks. Existing remote bookmarks 1354can be tracked individually by using `jj bookmark track`/`untrack` commands. 1355 1356```shell 1357# import feature1 bookmark and start tracking it 1358jj bookmark track feature1@origin 1359# delete local gh-pages bookmark and stop tracking it 1360jj bookmark delete gh-pages 1361jj bookmark untrack gh-pages@upstream 1362``` 1363 1364### Abandon commits that became unreachable in Git 1365 1366By default, when `jj` imports refs from Git, it will look for commits that used 1367to be [reachable][reachable] but no longer are reachable. Those commits will 1368then be abandoned, and any descendant commits will be rebased off of them (as 1369usual when commits are abandoned). You can disable this behavior and instead 1370leave the Git-unreachable commits in your repo by setting: 1371 1372```toml 1373[git] 1374abandon-unreachable-commits = false 1375``` 1376 1377[reachable]: https://git-scm.com/docs/gitglossary/#Documentation/gitglossary.txt-aiddefreachableareachable 1378 1379### Prefix for generated bookmarks on push 1380 1381`jj git push --change` generates bookmark names with a prefix of "push-" by 1382default. You can pick a different prefix by setting `git.push-bookmark-prefix`. For 1383example: 1384 1385```toml 1386[git] 1387push-bookmark-prefix = "martinvonz/push-" 1388``` 1389 1390### Set of private commits 1391 1392You can configure the set of private commits by setting `git.private-commits` to 1393a revset. The value is a revset of commits that Jujutsu will refuse to push. If 1394unset, all commits are eligible to be pushed. 1395 1396```toml 1397[git] 1398# Prevent pushing work in progress or anything explicitly labeled "private" 1399private-commits = "description(glob:'wip:*') | description(glob:'private:*')" 1400``` 1401 1402If a commit is in `git.private-commits` but is already on the remote, then it is 1403not considered a private commit. Commits that are immutable are also excluded 1404from the private set. 1405 1406Private commits prevent their descendants from being pushed, since doing so 1407would require pushing the private commit as well. 1408 1409### Git subprocessing behaviour 1410 1411By default, Git remote interactions are handled by spawning a `git` subprocess. 1412If `git` is not on your OS path, or you want to specify a particular binary, 1413you can: 1414 1415```toml 1416[git] 1417executable-path = "/path/to/git" 1418``` 1419 1420Previously, remote interactions were handled by 1421[`libgit2`](https://github.com/libgit2/libgit2) by default, which sometimes 1422caused [SSH problems](https://github.com/jj-vcs/jj/issues/4979) that could not 1423be solved by `jj` directly. If you have any issues with the `git` 1424subprocessing, you can switch back to `libgit2` with: 1425 1426```toml 1427[git] 1428subprocess = false 1429``` 1430 1431Note that `libgit2` support will likely be removed in the future, so you are 1432encouraged to report any issues you experience with the default configuration. 1433 1434## Filesystem monitor 1435 1436In large repositories, it may be beneficial to use a "filesystem monitor" to 1437track changes to the working copy. This allows `jj` to take working copy 1438snapshots without having to rescan the entire working copy. 1439 1440This is governed by the `core.fsmonitor` option. Currently, the valid values are 1441`"none"` or `"watchman"`. 1442 1443### Watchman 1444 1445To configure the Watchman filesystem monitor, set 1446`core.fsmonitor = "watchman"`. Ensure that you have [installed the Watchman 1447executable on your system](https://facebook.github.io/watchman/docs/install). 1448 1449You can configure `jj` to use watchman triggers to automatically create 1450snapshots on filesystem changes by setting 1451`core.watchman.register-snapshot-trigger = true`. 1452 1453You can check whether Watchman is enabled and whether it is installed correctly 1454using `jj debug watchman status`. 1455 1456## Snapshot settings 1457 1458### Paths to automatically track 1459 1460All new files in the working copy that don't match the ignore patterns are 1461tracked by default. You can set the `snapshot.auto-track` to set which paths 1462get automatically tracked when they're added to the working copy. See the 1463[fileset documentation](filesets.md) for the syntax. Files with paths matching 1464[ignore files](working-copy.md#ignored-files) are never tracked automatically. 1465 1466You can use `jj file untrack` to untrack a file while keeping it in the working 1467copy. However, first [ignore](working-copy.md#ignored-files) them or remove them 1468from the `snapshot.auto-track` patterns; otherwise they will be immediately 1469tracked again. 1470 1471### Maximum size for new files 1472 1473By default, as an anti-footgun measure, `jj` will refuse to add new files to the 1474snapshot that are larger than a certain size; the default is 1MiB. This can be 1475changed by setting `snapshot.max-new-file-size` to a different value. For 1476example: 1477 1478```toml 1479[snapshot] 1480max-new-file-size = "10MiB" 1481# the following is equivalent 1482max-new-file-size = 10485760 1483``` 1484 1485The value can be specified using a human readable string with typical suffixes; 1486`B`, `MiB`, `GB`, etc. By default, if no suffix is provided, or the value is a 1487raw integer literal, the value is interpreted as if it were specified in bytes. 1488 1489Files that already exist in the working copy are not subject to this limit. 1490 1491Setting this value to zero will disable the limit entirely. 1492 1493## Ways to specify `jj` config: details 1494 1495### User config files 1496 1497An easy way to find the user config file/directory is: 1498 1499```bash 1500jj config path --user 1501``` 1502 1503On all platforms, the user's global `jj` configurations are by default loaded in 1504the following precedence order (with later configs overriding earlier ones): 1505 1506- `$HOME/.jjconfig.toml` 1507- `<PLATFORM_SPECIFIC>/jj/config.toml` (preferred) 1508- `<PLATFORM_SPECIFIC>/jj/conf.d/*.toml` 1509 1510where `$HOME` represents the user's home directory (`%USERPROFILE%` on Windows), 1511and `<PLATFORM_SPECIFIC>` represents the platform-specific configuration 1512directory shown in the table below. The platform-specific location is 1513recommended for better integration with platform services. 1514 1515The files in the `conf.d` directory are loaded in lexicographic order. This allows 1516configs to be split across multiple files and combines well 1517with [Conditional Variables](#conditional-variables). 1518 1519| Platform | Location of `<PLATFORM_SPECIFIC>` dir | Example config file location | 1520| :------- | :------------------------------------ | :-------------------------------------------------------- | 1521| Linux | `$XDG_CONFIG_HOME` or `$HOME/.config` | `/home/alice/.config/jj/config.toml` | 1522| macOS | `$HOME/Library/Application Support` | `/Users/Alice/Library/Application Support/jj/config.toml` | 1523| Windows | `{FOLDERID_RoamingAppData}` | `C:\Users\Alice\AppData\Roaming\jj\config.toml` | 1524 1525The location of the `jj` user config files/directories can also be overridden with the 1526`JJ_CONFIG` environment variable. If it is not empty, it will be used instead 1527of any configuration files in the default locations. If it is a path to a TOML 1528file, then that file will be loaded instead. If it is a path to a directory, 1529then all the TOML files in that directory will be loaded in lexicographic order 1530and merged. Multiple paths can be specified by separating them with a 1531platform-specific path separator (`:` on Unix-like systems, `;` on Windows). 1532 1533For example, the following could be used to run `jj` without loading any user configs: 1534 1535```bash 1536JJ_CONFIG= jj log # Ignores any settings specified in the config file. 1537``` 1538 1539### JSON Schema Support 1540 1541Many popular editors support TOML file syntax highlighting and validation. To 1542enable schema validation in your editor, add this line at the top of your TOML 1543config files: 1544 1545```toml 1546"$schema" = "https://jj-vcs.github.io/jj/latest/config-schema.json" 1547``` 1548 1549This enables features like: 1550 1551- Autocomplete for config keys 1552- Type checking of values 1553- Documentation on hover 1554- Validation of settings 1555 1556Here are some popular editors with TOML schema validation support: 1557 1558- VS Code 1559 - Install [Even Better TOML](https://marketplace.visualstudio.com/items?itemName=tamasfe.even-better-toml) 1560 1561- Neovim/Vim 1562 - Use with [nvim-lspconfig](https://github.com/neovim/nvim-lspconfig) and [taplo](https://github.com/tamasfe/taplo) 1563 1564- JetBrains IDEs (IntelliJ, PyCharm, etc) 1565 - Install [TOML](https://plugins.jetbrains.com/plugin/8195-toml) plugin 1566 1567- Emacs 1568 - Install [lsp-mode](https://github.com/emacs-lsp/lsp-mode) and [toml-mode](https://github.com/dryman/toml-mode.el) 1569 - Configure [taplo](https://github.com/tamasfe/taplo) as the LSP server 1570 1571### Specifying config on the command-line 1572 1573You can use one or more `--config`/`--config-file` options on the command line 1574to specify additional configuration settings. This overrides settings defined in 1575config files or environment variables. For example, 1576 1577```shell 1578# Must not have spaces around the `=` 1579jj --config ui.color=always --config ui.diff-editor=meld split 1580``` 1581 1582Config value should be specified as a TOML expression. If string value isn't 1583enclosed by any TOML constructs (such as array notation), quotes can be omitted. 1584Here is an example with more advanced TOML constructs: 1585 1586```shell 1587# Single quotes and the '\' are interpreted by the shell and assume a Unix shell 1588# Double quotes are passed to jj and are parsed as TOML syntax 1589jj log --config \ 1590 'template-aliases."format_timestamp(timestamp)"="""timestamp.format("%Y-%m-%d %H:%M %:::z")"""' 1591``` 1592 1593To load an entire TOML document, use `--config-file`: 1594 1595```shell 1596jj --config-file=extra-config.toml log 1597``` 1598 1599### Conditional variables 1600 1601You can conditionally enable config variables by using `--when`. 1602 1603#### Using `[[--scope]]` tables 1604 1605Variables defined in `[[--scope]]` tables are expanded to the root table. 1606`--when` specifies the condition to enable the scope table. 1607 1608If no conditions are specified, the table is always enabled. If multiple 1609conditions are specified, their intersection is used. 1610 1611```toml 1612[user] 1613name = "YOUR NAME" 1614email = "YOUR_DEFAULT_EMAIL@example.com" 1615 1616# override user.email if the repository is located under ~/oss 1617[[--scope]] 1618--when.repositories = ["~/oss"] 1619[--scope.user] 1620email = "YOUR_OSS_EMAIL@example.org" 1621 1622# disable pagination for `jj status`, use `delta` for `jj diff` and `jj show` 1623[[--scope]] 1624--when.commands = ["status"] 1625[--scope.ui] 1626paginate = "never" 1627[[--scope]] 1628--when.commands = ["diff", "show"] 1629[--scope.ui] 1630pager = "delta" 1631``` 1632 1633#### Using multiple files 1634 1635`--when` can also be used on the top level of a TOML file, which is convenient 1636when splitting your config across multiple files. 1637The behavior of conditions are the same as when using `[[--scope]]` tables. 1638 1639```toml 1640# In $XDG_CONFIG_HOME/jj/config.toml 1641[user] 1642name = "YOUR NAME" 1643email = "YOUR_DEFAULT_EMAIL@example.com" 1644``` 1645 1646```toml 1647# In $XDG_CONFIG_HOME/jj/conf.d/work.toml 1648--when.repositories = ["~/the/work/repo"] 1649 1650[user] 1651email = "YOUR_WORK_EMAIL@workplace.com" 1652 1653[revset-aliases] 1654work = "heads(::@ ~ description(exact:''))::" 1655 1656[aliases] 1657wip = ["log", "-r", "work"] 1658``` 1659 1660#### Available condition keys 1661 1662* `--when.repositories`: List of paths to match the repository path prefix. 1663 1664 Paths should be absolute. Each path component (directory or file name, drive 1665 letter, etc.) is compared case-sensitively on all platforms. A path starting 1666 with `~` is expanded to the home directory. On Windows, directory separator may 1667 be either `\` or `/`. (Beware that `\` needs escape in double-quoted strings.) 1668 1669 Use `jj root` to see the workspace root directory. Note that the repository path 1670 is in the main workspace if you're using multiple workspaces with `jj 1671 workspace`. 1672 1673 1674* `--when.commands`: List of subcommands to match. 1675 1676 Subcommands are space-separated and matched by prefix. 1677 1678 ```toml 1679 --when.commands = ["file"] # matches `jj file show`, `jj file list`, etc 1680 --when.commands = ["file show"] # matches `jj file show` but *NOT* `jj file list` 1681 --when.commands = ["file", "log"] # matches `jj file` *OR* `jj log` (or subcommand of either) 1682 ```