How to Contribute
Policies
We'd love to accept your patches and contributions to this project. There are just a few small guidelines you need to follow.
Contributor License Agreement
Contributions to this project must be accompanied by a Contributor License Agreement. You (or your employer) retain the copyright to your contribution; this simply gives us permission to use and redistribute your contributions as part of the project. Head over to https://cla.developers.google.com/ to see whether you have already signed the CLA or to sign it.
You generally only need to submit a CLA once, so if you've already submitted one (even if it was for a different project), you probably don't need to do it again. In other words, the Google CLA is not scoped to a specific project. If you sign the Google CLA, it applies to other Google open-source projects as well (including future projects).
Commit guidelines
Unlike many GitHub projects (but like many VCS projects), we care more about the contents of commits than about the contents of PRs. We review each commit separately, and we don't squash-merge the PR (so please manually squash any fixup commits before sending for review).
Each commit should ideally do one thing. For example, if you need to refactor a
function in order to add a new feature cleanly, put the refactoring in one
commit and the new feature in a different commit. If the refactoring itself
consists of many parts, try to separate out those into separate commits. You can
use jj split to do it if you didn't realize ahead of time how it should be
split up. Include tests and documentation in the same commit as the code they
test and document.
The commit message should describe the changes in the commit;
the PR description can even be empty, but feel free to include a personal
message. We don't use Conventional Commits and instead start the commit
message with <topic>: rather than like chore: , feat: and fix: .
This means if you modified a command in the CLI, use its name as the topic, e.g.
next/prev: <your-modification> or conflicts: <your-modification>. We don't
currently have a specific guidelines on what to write in the topic field, but
the reviewers will help you provide a topic if you have difficulties choosing
it. How to Write a Git Commit Message is a good
guide if you're new to writing good commit messages. We are not particularly
strict about the style, but please do explain the reason for the change unless
it's obvious. If the PR closes an open issue or feature request for the
project, include the Closes #<issue-number> or Fixes #<issue-number> in
the commit description.
If you have been invited to the jj-vcs/ organization feel free to create
branches directly in the repo, ideally prefixed by your name or username. This
allows other people to directly check out your work and possibly integrate them
in their custom builds of jj.
Code reviews
All submissions, including submissions by project members, require review. We use GitHub pull requests for this purpose. Consult GitHub Help for more information on using pull requests.
The project unfortunately has a shortage of reviewers (a common problem in open-source projects). To maximize the chances of getting a timely review, do what you can to provide reviewers (and other future readers) with the necessary context. For example, if you're adding a new feature, explain why that feature is useful, how it works from the user's point of view, how it's designed, and what the limitations of your design are. If you have considered other designs, it may be useful to mention them. Another way of speeding up reviews is to review others' PRs so the maintainers don't need to spend as much time on them.
When you address comments on a PR, don't make the changes in a commit on top (as
is typical on GitHub). Instead, please make the changes in the appropriate
commit. You can do that by creating a new commit on top of the initial commit
(jj new <commit>) and then squash in the changes when you're done (jj squash).
jj git push
will automatically force-push the bookmark.
Mark conversation threads as resolved when you have addressed them. If you realize that a comment requires non-trivial changes, write a reply instead and ask your reviewer to take another look after updating the code.
When your first PR has been approved, we typically invite you to the
jj-vcs/contributors team to give you contributor access,
so you can address any remaining minor comments and then merge the PR yourself
when you're ready.
If your employer pays anyone (not necessarily you) to contribute to Jujutsu, please make sure your GitHub username is recorded. To avoid conflicts of interest, please don't merge a PR that has only been approved by someone from the same organization. Similarly, as a reviewer, there is no need to approve your coworkers' PRs, since the author should await an approval from someone else anyway. It is of course still appreciated if you review and comment on their PRs. Also, if the PR seems completely unrelated to your company's interests, do feel free to approve it.
Community Guidelines
This project follows Google's Open Source Community Guidelines.
Deprecations and Removals
If your PR removes or renames an option, a command, or config option don't
remove it immediately. Instead implement a warning that the command, command
option, or config option is deprecated and will be removed in
jj v<current> + 6. Also add a // TODO: remove in jj<version+6>+ comment so
other contributors can remove it later. As we currently release monthly this
translates to a six month deprecation period. This is something the project
does to not break workflows and gives users the the option to
provide feedback on features we plan to remove or supersede with other
approaches.
Changes to the repo format (everything which is in .jj/) are more disruptive.
We aim to be backwards-compatible for at least a year (12 releases). Also
consider if it's worth being forwards-compatible (i.e making sure that the last
N versions of jj can read the new format). Examples of such changes are moving
repo-level configuration out of the repository or deriving the evolog from the
op-log.
Some things are required to be supported for even longer but that is in the end
a maintainer decision. Some examples of this were the jj checkout/merge
commands (removed after 24 months/releases) or the --destination flag for
which there is no final removal date yet.
Contributing large patches
We welcome contributions from anyone.
If you wish to contribute a new large feature, you are encouraged to discuss it in Discord or a GitHub Discussion first before diving in. Before spending too much time on a particular design, you should see if the community and the maintainers have any feedback on your idea and general approach. It also is a better experience for you as an author if you contributed smaller patches first, so you understand how the project and the community around it works.
If you open a pull request without discussion first, you may find that the community already has discussed this and found a better approach, or that it already was deemed not to be a fit for the project.
Since many ideas have come up before, but they haven't been implemented because they might be deceptively nuanced, or there may be strong opinions around them, bringing it up to the community first helps discover past discussions, so your design can be informed by them.
Once you have vetted your idea with the community, please write a Design Doc which requires an architecture review from multiple stakeholders, see the process here.
Contributing to the documentation
We appreciate bug
reports
about any problems, however small, lurking in our documentation
website or in the jj help <command> docs. If a part of the bug report template does not apply, you can
just delete it.
Before reporting a problem with the documentation website, we'd appreciate it if
you could check that the problem still exists in the "prerelease" version of the
documentation (as opposed to the docs for one of the released versions of jj).
You can use the version switcher in the top-left of the website to do so.
If you are willing to make a PR fixing a documentation problem, even better!
The documentation website sources are Markdown files located in the docs/
directory. You do not need to
know Rust to work with them. See below for instructions on how to preview the
HTML docs as you edit the Markdown files.
Doing so is optional, but recommended.
The jj help docs are sourced from the "docstring" comments inside the Rust
sources, currently from the cli/src/commands
directory. Working
on them requires setting up a Rust development environment, as described
below, and may occasionally require adjusting a test.
Learning Rust
In addition to the Rust Book and the other excellent resources at https://www.rust-lang.org/learn, we recommend the "Comprehensive Rust" mini-course for an overview, especially if you are familiar with C++.
Style guide
See here.
Setting up a development environment
To develop jj, the mandatory steps are simply
to install Rust (the default
installer options are fine), clone the repository, and use cargo build
, cargo fmt,
cargo clippy --workspace --all-targets, and
cargo test --workspace. If you are preparing a PR, there are some additional
recommended steps.
Summary
One-time setup:
rustup toolchain add nightly # wanted for 'rustfmt'
rustup toolchain add 1.89 # also specified in Cargo.toml
cargo install --locked bacon
cargo install --locked cargo-insta
cargo install --locked cargo-nextest
During development (adapt according to your preference):
bacon clippy-all
cargo +nightly fmt # Occasionally
cargo nextest run --workspace # Occasionally
cargo insta test --workspace --test-runner nextest # Occasionally
!!! warning
Build artifacts from debug builds and especially from repeated
invocations of `cargo test` can quickly take up 10s of GB of disk space.
Cargo will happily use up your entire hard drive. If this happens, run
`cargo clean`.
Explanation
These are listed roughly in order of decreasing importance.
-
Nearly any change to
jj's CLI will require writing or updating snapshot tests that use theinstacrate. To make this convenient, install thecargo-instabinary. Usecargo insta test --workspaceto run tests, andcargo insta review --workspaceto update the snapshot tests. The--workspaceflag is needed to run the tests on all crates; by default, only the crate in the current directory is tested. -
GitHub CI checks require that the code is formatted with the nightly version of
rustfmt. To do this on your computer, install the nightly toolchain and usecargo +nightly fmt. -
Your code will be rejected if it cannot be compiled with the minimal supported version of Rust ("MSRV"). Currently,
jjfollows a rather casual MSRV policy: "The currentrustcstable version, minus one." As of this writing, that version is 1.89.0. -
Your code needs to pass
cargo clippy. You can also usecargo +nightly clippyif you wish to see more warnings. -
You may also want to install and use
bacon, to automatically build, check, and / or run tests. -
To run tests more quickly, use
cargo nextest run --workspace. To usenextestwithinsta, usecargo insta test --workspace --test-runner nextest.On Linux, you may be able to speed up
nextesteven further by using themoldlinker, as explained below.
Measuring code coverage
Install cargo-llvm-cov and
cargo-nextest (see above), then run:
cargo +nightly cov # add --html to get a browsable report
cov is an alias defined in .cargo/config.toml which enables a consistent
set of options for all contributors. The nightly Rust toolchain is required (the
compiler instrumentation feature itself is nightly only).
When you are writing new test modules, make sure to turn coverage off for
that module so it doesn't skew the resultant accounting; this can be done by
copy/pasting the following #[cfg_attr] after your #[cfg(test)] stanza:
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
mod tests {
// ...
}
Configuring jj fix to run rustfmt
Run this in the jj repo:
jj config set --repo fix.tools.rustfmt '{ command = ["rustfmt", "+nightly"], patterns = ["glob:**/*.rs"] }'
Note: users of Nix and
direnvshould drop the"+nightly"argument above since the devShell is already configured to pull in a nightly version of rustfmt:jj config set --repo fix.tools.rustfmt '{ command = ["rustfmt"], patterns = ["glob:**/*.rs"] }'
Using mold for faster tests on Linux
On a machine with a multi-core CPU, one way to speed up
cargo nextest on Linux is to use the multi-threaded mold
linker. This linker may help
if, currently, your CPU is underused while Rust is linking test
binaries. Before proceeding with mold, you can check whether this is
an issue worth solving using a system monitoring tool such as htop.
mold is packaged for many distributions. On Debian, for example,
sudo apt install mold should just work.
A simple way to use mold is via the -run option, e.g.:
mold -run cargo insta test --workspace --test-runner nextest
There will be no indication that a different linker is used, except for
higher CPU usage while linking and, hopefully, faster completion. You
can verify that mold was indeed used by running
readelf -p .comment target/debug/jj.
There are also ways of having Rust use mold by default, see the "How
to use" instructions.
On recent versions of MacOS, the default linker Rust uses is already multi-threaded. It should use all the CPU cores without any configuration.
Set up a RAM disk for faster tests on macOS
jj tests can be sped up significantly on macOS by using a RAM disk instead of
the usual /tmp directory (on one Mac, the tests sped up ~3 times from 180
seconds to 55 seconds). You can set this up as follows:
sudo mkdir -p /Volumes/RAMDisk
sudo chmod a+wx /Volumes/RAMDisk
sudo mount_tmpfs /Volumes/RAMDisk # Add `-e` to make it case-sensitive
# Add `-o nobrowse` to hide the tmpfs from Finder
You will need to re-run this after a reboot. Consider making it a script you can
run with sudo. (The first two commands don't need sudo if you change the dir
to somewhere in your HOME, the last one always does.)
Then, you can rust tests as, for example,
TMPDIR=/Volumes/RAMDisk cargo insta test --workspace --test-runner nextest
You can double-check whether or not the RAM disk is mounted with
mount | grep tmpfs
Some details and speculation
Hard drive speed is not the issue here. Experimentally, when /tmp
is physical, Ilya experienced the tests doing writes at 60MB/s (as reported by
the Activity Monitor) on an SSD that should be many times as fast.
Instead, it seems to have something to do with file locking and
fdatasync. A likely curlprit is the presence of
global kernel locks in APFS. There are some benchmarks in
this
PR.
It might be possible to add an entry to /etc/fstab to mount tmpfs
automatically. If you succeed with this, let us (and Ilya in particular) know!
Editor setup
Visual Studio Code
We recommend at least these settings:
{
"files.insertFinalNewline": true,
"files.trimTrailingWhitespace": true,
"[rust]": {
"files.trimTrailingWhitespace": false
}
}
Zed
// .zed/settings.json
{
"ensure_final_newline_on_save": true,
"remove_trailing_whitespace_on_save": true,
"languages": {
// We don't use a formatter for Markdown files, so format_on_save would just
// mess with others' docs
"Markdown": { "format_on_save": "off" }
"Rust": {
"format_on_save": "on",
// Avoid removing trailing spaces within multi-line string literals
"remove_trailing_whitespace_on_save": false
}
},
"lsp": {
"rust-analyzer": {
"initialization_options": {
// If you are working on docs and don't need `cargo check`, uncomment
// this option:
//
// "checkOnSave": false,
// Use nightly `rustfmt`, equivalent to `cargo +nightly fmt`
"rustfmt": { "extraArgs": ["+nightly"] }
}
}
}
}
Helix
# .helix/languages.toml
[language-server.rust-analyzer.config.rustfmt]
extraArgs = ["+nightly"]
Alternative development setup with Nix
If you have Nix installed, you can use the provided
flake.nix to get a development environment with all necessary tools
pre-configured:
nix develop
Once inside the shell, you can run cargo build, cargo test etc. as usual.
Other tools like uv, cargo-insta, cargo-nextest and more are installed,
and so you should be able to follow any other recommendations in this guide as
needed.
!!! tip "Editor integration"
Launch your editor from within the `nix develop` shell so that
rust-analyzer and other LSP tools can find the correct toolchain. For
example:
```shell
nix develop
code . # or your editor of choice
```
!!! note "direnv users"
If you use [direnv](https://direnv.net/) with
[nix-direnv](https://github.com/nix-community/nix-direnv), you can `echo
"source_env .envrc.recommended" >> .envrc` to automatically activate the
development environment when entering the directory.
Alternative development setup with mise
An experimental development setup is available using
mise. If you try it, file bugs,
PRs, or tell us on Discord/IRC/discussions if you experience problems
or if this config is too inflexible. If we can make it work for most
platforms and most people's needs, including people previously unfamiliar
with mise, we may make mise the recommended way to set up a development
environment.
This tool manages the necessary dependencies for you, eliminating the need for
a separate setup process. mise automatically installs the required tools when
they are needed.
Here are some of the commands you may find yourself using frequently during development:
mise test: Runs all tests.mise test <string>: Runs tests that contain a specific string. For example,mise test squashwould run tests with "squash" in their name.mise build: Compilesjj.mise build:release: Compilesjjin release mode.mise build:docs: Builds the documentation forjj.
For a complete list of all available tasks, you can run mise tasks or review
the configuration file at .config/mise.toml.
You can customize this configuration using
a mise.local.toml file.
Lines 1–500 of 781. Load more
# How to Contribute ## Policies We'd love to accept your patches and contributions to this project. There are just a few small guidelines you need to follow. ### Contributor License Agreement Contributions to this project must be accompanied by a Contributor License Agreement. You (or your employer) retain the copyright to your contribution; this simply gives us permission to use and redistribute your contributions as part of the project. Head over to <https://cla.developers.google.com/> to see whether you have already signed the CLA or to sign it. You generally only need to submit a CLA once, so if you've already submitted one (even if it was for a different project), you probably don't need to do it again. In other words, the Google CLA is not scoped to a specific project. If you sign the Google CLA, it applies to other Google open-source projects as well (including future projects). ### Commit guidelines Unlike many GitHub projects (but like many VCS projects), we care more about the contents of commits than about the contents of PRs. We review each commit separately, and we don't squash-merge the PR (so please manually squash any fixup commits before sending for review). Each commit should ideally do one thing. For example, if you need to refactor a function in order to add a new feature cleanly, put the refactoring in one commit and the new feature in a different commit. If the refactoring itself consists of many parts, try to separate out those into separate commits. You can use `jj split` to do it if you didn't realize ahead of time how it should be split up. Include tests and documentation in the same commit as the code they test and document. The commit message should describe the changes in the commit; the PR description can even be empty, but feel free to include a personal message. We don't use [Conventional Commits] and instead start the commit message with `<topic>: ` rather than like `chore: `, `feat: ` and `fix: `. This means if you modified a command in the CLI, use its name as the topic, e.g. `next/prev: <your-modification>` or `conflicts: <your-modification>`. We don't currently have a specific guidelines on what to write in the topic field, but the reviewers will help you provide a topic if you have difficulties choosing it. [How to Write a Git Commit Message] is a good guide if you're new to writing good commit messages. We are not particularly strict about the style, but please do explain the reason for the change unless it's obvious. If the PR closes an open issue or feature request for the project, include the `Closes #<issue-number>` or `Fixes #<issue-number>` in the commit description. If you have been invited to the `jj-vcs/` organization feel free to create branches directly in the repo, ideally prefixed by your name or username. This allows other people to directly check out your work and possibly integrate them in their custom builds of jj. [Conventional Commits]: https://www.conventionalcommits.org/en/v1.0.0/ [How to Write a Git Commit Message]: https://cbea.ms/git-commit/ ### Code reviews All submissions, including submissions by project members, require review. We use GitHub pull requests for this purpose. Consult [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more information on using pull requests. The project unfortunately has a shortage of reviewers (a common problem in open-source projects). To maximize the chances of getting a timely review, do what you can to provide reviewers (and other future readers) with the necessary context. For example, if you're adding a new feature, explain why that feature is useful, how it works from the user's point of view, how it's designed, and what the limitations of your design are. If you have considered other designs, it may be useful to mention them. Another way of speeding up reviews is to review others' PRs so the maintainers don't need to spend as much time on them. When you address comments on a PR, don't make the changes in a commit on top (as is typical on GitHub). Instead, please make the changes in the appropriate commit. You can do that by creating a new commit on top of the initial commit (`jj new <commit>`) and then squash in the changes when you're done (`jj squash`). `jj git push` will automatically force-push the bookmark. Mark conversation threads as resolved when you have addressed them. If you realize that a comment requires non-trivial changes, write a reply instead and ask your reviewer to take another look after updating the code. When your first PR has been approved, we typically invite you to the `jj-vcs/contributors` team to give you contributor access, so you can address any remaining minor comments and then merge the PR yourself when you're ready. If your employer pays anyone (not necessarily you) to contribute to Jujutsu, please make sure your GitHub username is [recorded](paid_contributors.md). To avoid conflicts of interest, please don't merge a PR that has only been approved by someone from the same organization. Similarly, as a reviewer, there is no need to approve your coworkers' PRs, since the author should await an approval from someone else anyway. It is of course still appreciated if you review and comment on their PRs. Also, if the PR seems completely unrelated to your company's interests, do feel free to approve it. ### Community Guidelines This project follows [Google's Open Source Community Guidelines](https://opensource.google/conduct/). ### Deprecations and Removals If your PR removes or renames an option, a command, or config option don't remove it immediately. Instead implement a warning that the command, command option, or config option is deprecated and will be removed in jj `v<current> + 6`. Also add a `// TODO: remove in jj<version+6>+` comment so other contributors can remove it later. As we currently release monthly this translates to a six month deprecation period. This is something the project does to not break workflows and gives users the the option to provide feedback on features we plan to remove or supersede with other approaches. Changes to the repo format (everything which is in `.jj/`) are more disruptive. We aim to be backwards-compatible for at least a year (12 releases). Also consider if it's worth being forwards-compatible (i.e making sure that the last N versions of `jj` can read the new format). Examples of such changes are moving repo-level configuration out of the repository or deriving the evolog from the op-log. Some things are required to be supported for even longer but that is in the end a maintainer decision. Some examples of this were the `jj checkout/merge` commands (removed after 24 months/releases) or the `--destination` flag for which there is no final removal date yet. ## Contributing large patches We welcome contributions from anyone. If you wish to contribute a new large feature, you are encouraged to discuss it in Discord or a GitHub Discussion first before diving in. Before spending too much time on a particular design, you should see if the community and the maintainers have any feedback on your idea and general approach. It also is a better experience for you as an author if you contributed smaller patches first, so you understand how the project and the community around it works. If you open a pull request without discussion first, you may find that the community already has discussed this and found a better approach, or that it already was deemed not to be a fit for the project. Since many ideas have come up before, but they haven't been implemented because they might be deceptively nuanced, or there may be strong opinions around them, bringing it up to the community first helps discover past discussions, so your design can be informed by them. Once you have vetted your idea with the community, please write a [Design Doc](design_docs.md) which requires an architecture review from multiple stakeholders, see the [process here](design_docs.md#process). ## Contributing to the documentation We appreciate [bug reports](https://github.com/jj-vcs/jj/issues/new?template=bug_report.md) about any problems, however small, lurking in [our documentation website](https://docs.jj-vcs.dev/prerelease) or in the `jj help <command>` docs. If a part of the bug report template does not apply, you can just delete it. Before reporting a problem with the documentation website, we'd appreciate it if you could check that the problem still exists in the "prerelease" version of the documentation (as opposed to the docs for one of the released versions of `jj`). You can use the version switcher in the top-left of the website to do so. If you are willing to make a PR fixing a documentation problem, even better! The documentation website sources are Markdown files located in the [`docs/` directory](https://github.com/jj-vcs/jj/tree/main/docs). You do not need to know Rust to work with them. See below for [instructions on how to preview the HTML docs](#previewing-the-html-documentation) as you edit the Markdown files. Doing so is optional, but recommended. The `jj help` docs are sourced from the "docstring" comments inside the Rust sources, currently from the [`cli/src/commands` directory](https://github.com/jj-vcs/jj/tree/main/cli/src/commands). Working on them requires setting up a Rust development environment, as described below, and may occasionally require adjusting a test. ## Learning Rust In addition to the [Rust Book](https://doc.rust-lang.org/book/) and the other excellent resources at <https://www.rust-lang.org/learn>, we recommend the ["Comprehensive Rust" mini-course](https://google.github.io/comprehensive-rust/) for an overview, especially if you are familiar with C++. ## Style guide See [here](style_guide.md). ## Setting up a development environment To develop `jj`, the mandatory steps are simply to [install Rust](https://www.rust-lang.org/tools/install) (the default installer options are fine), clone the repository, and use `cargo build` , `cargo fmt`, `cargo clippy --workspace --all-targets`, and `cargo test --workspace`. If you are preparing a PR, there are some additional recommended steps. ### Summary One-time setup: rustup toolchain add nightly # wanted for 'rustfmt' rustup toolchain add 1.89 # also specified in Cargo.toml cargo install --locked bacon cargo install --locked cargo-insta cargo install --locked cargo-nextest During development (adapt according to your preference): bacon clippy-all cargo +nightly fmt # Occasionally cargo nextest run --workspace # Occasionally cargo insta test --workspace --test-runner nextest # Occasionally !!! warning Build artifacts from debug builds and especially from repeated invocations of `cargo test` can quickly take up 10s of GB of disk space. Cargo will happily use up your entire hard drive. If this happens, run `cargo clean`. ### Explanation These are listed roughly in order of decreasing importance. 1. Nearly any change to `jj`'s CLI will require writing or updating snapshot tests that use the [`insta`](https://insta.rs/) crate. To make this convenient, install the `cargo-insta` binary. Use `cargo insta test --workspace` to run tests, and `cargo insta review --workspace` to update the snapshot tests. The `--workspace` flag is needed to run the tests on all crates; by default, only the crate in the current directory is tested. 2. GitHub CI checks require that the code is formatted with the *nightly* version of `rustfmt`. To do this on your computer, install the nightly toolchain and use `cargo +nightly fmt`. 3. Your code will be rejected if it cannot be compiled with the minimal supported version of Rust ("MSRV"). Currently, `jj` follows a rather casual MSRV policy: "The current `rustc` stable version, minus one." As of this writing, that version is **1.89.0**. 4. Your code needs to pass `cargo clippy`. You can also use `cargo +nightly clippy` if you wish to see more warnings. 5. You may also want to install and use [`bacon`](https://dystroy.org/bacon/), to automatically build, check, and / or run tests. 6. To run tests more quickly, use `cargo nextest run --workspace`. To use `nextest` with `insta`, use `cargo insta test --workspace --test-runner nextest`. On Linux, you may be able to speed up `nextest` even further by using the `mold` linker, as explained below. ### Measuring code coverage Install [`cargo-llvm-cov`](https://github.com/taiki-e/cargo-llvm-cov) and `cargo-nextest` (see above), then run: ```shell cargo +nightly cov # add --html to get a browsable report ``` `cov` is an alias defined in `.cargo/config.toml` which enables a consistent set of options for all contributors. The nightly Rust toolchain is required (the compiler instrumentation feature itself is nightly only). When you are writing new test modules, make sure to turn coverage off for that module so it doesn't skew the resultant accounting; this can be done by copy/pasting the following `#[cfg_attr]` after your `#[cfg(test)]` stanza: ```rust #[cfg(test)] #[cfg_attr(coverage_nightly, coverage(off))] mod tests { // ... } ``` ### Configuring `jj fix` to run `rustfmt` Run this in the jj repo: ```shell jj config set --repo fix.tools.rustfmt '{ command = ["rustfmt", "+nightly"], patterns = ["glob:**/*.rs"] }' ``` > Note: users of Nix and `direnv` should drop the `"+nightly"` argument above > since the devShell is already configured to pull in a nightly version of > rustfmt: > > ```shell > jj config set --repo fix.tools.rustfmt '{ command = ["rustfmt"], patterns = ["glob:**/*.rs"] }' > ``` ### Using `mold` for faster tests on Linux On a machine with a multi-core CPU, one way to speed up `cargo nextest` on Linux is to use the multi-threaded [`mold` linker](https://github.com/rui314/mold). This linker may help if, currently, your CPU is underused while Rust is linking test binaries. Before proceeding with `mold`, you can check whether this is an issue worth solving using a system monitoring tool such as `htop`. `mold` is packaged for many distributions. On Debian, for example, `sudo apt install mold` should just work. A simple way to use `mold` is via the `-run` option, e.g.: ```shell mold -run cargo insta test --workspace --test-runner nextest ``` There will be no indication that a different linker is used, except for higher CPU usage while linking and, hopefully, faster completion. You can verify that `mold` was indeed used by running `readelf -p .comment target/debug/jj`. There are also ways of having Rust use `mold` by default, see the ["How to use" instructions](https://github.com/rui314/mold#how-to-use). On recent versions of MacOS, the default linker Rust uses is already multi-threaded. It should use all the CPU cores without any configuration. ### Set up a RAM disk for faster tests on macOS `jj` tests can be sped up significantly on macOS by using a RAM disk instead of the usual `/tmp` directory (on one Mac, the tests sped up ~3 times from 180 seconds to 55 seconds). You can set this up as follows: ```sh sudo mkdir -p /Volumes/RAMDisk sudo chmod a+wx /Volumes/RAMDisk sudo mount_tmpfs /Volumes/RAMDisk # Add `-e` to make it case-sensitive # Add `-o nobrowse` to hide the tmpfs from Finder ``` You will need to re-run this after a reboot. Consider making it a script you can run with `sudo`. (The first two commands don't need sudo if you change the dir to somewhere in your HOME, the last one always does.) Then, you can rust tests as, for example, ```sh TMPDIR=/Volumes/RAMDisk cargo insta test --workspace --test-runner nextest ``` You can double-check whether or not the RAM disk is mounted with ```sh mount | grep tmpfs ``` <details> <summary> Some details and speculation </summary> <!-- MkDocs doesn't support Markdown markup inside `details` :( --> Hard drive speed is not the issue here. Experimentally, when <code>/tmp</code> is physical, Ilya experienced the tests doing writes at 60MB/s (as reported by the Activity Monitor) on an SSD that should be many times as fast. Instead, it seems to have something to do with file locking and <code>fdatasync</code>. A likely curlprit is the presence of <a href="https://gregoryszorc.com/blog/2018/10/29/global-kernel-locks-in-apfs/"> global kernel locks in APFS</a>. There are some benchmarks in <a href="https://github.com/jj-vcs/jj/pull/7493#issuecomment-3289020874">this PR</a>. It might be possible to add an entry to `/etc/fstab` to mount tmpfs automatically. If you succeed with this, let us (and Ilya in particular) know! </details> ### Editor setup #### Visual Studio Code We recommend at least these settings: ```js { "files.insertFinalNewline": true, "files.trimTrailingWhitespace": true, "[rust]": { "files.trimTrailingWhitespace": false } } ``` #### Zed ```js // .zed/settings.json { "ensure_final_newline_on_save": true, "remove_trailing_whitespace_on_save": true, "languages": { // We don't use a formatter for Markdown files, so format_on_save would just // mess with others' docs "Markdown": { "format_on_save": "off" } "Rust": { "format_on_save": "on", // Avoid removing trailing spaces within multi-line string literals "remove_trailing_whitespace_on_save": false } }, "lsp": { "rust-analyzer": { "initialization_options": { // If you are working on docs and don't need `cargo check`, uncomment // this option: // // "checkOnSave": false, // Use nightly `rustfmt`, equivalent to `cargo +nightly fmt` "rustfmt": { "extraArgs": ["+nightly"] } } } } } ``` #### Helix ```toml # .helix/languages.toml [language-server.rust-analyzer.config.rustfmt] extraArgs = ["+nightly"] ``` ### Alternative development setup with Nix If you have [Nix](https://nixos.org/) installed, you can use the provided `flake.nix` to get a development environment with all necessary tools pre-configured: ```shell nix develop ``` Once inside the shell, you can run `cargo build`, `cargo test` etc. as usual. Other tools like `uv`, `cargo-insta`, `cargo-nextest` and more are installed, and so you should be able to follow any other recommendations in this guide as needed. !!! tip "Editor integration" Launch your editor from within the `nix develop` shell so that rust-analyzer and other LSP tools can find the correct toolchain. For example: ```shell nix develop code . # or your editor of choice ``` !!! note "direnv users" If you use [direnv](https://direnv.net/) with [nix-direnv](https://github.com/nix-community/nix-direnv), you can `echo "source_env .envrc.recommended" >> .envrc` to automatically activate the development environment when entering the directory. ### Alternative development setup with `mise` An experimental development setup is available using [`mise`](https://mise.jdx.dev/). If you try it, file bugs, PRs, or tell us on Discord/IRC/discussions if you experience problems or if this config is too inflexible. If we can make it work for most platforms and most people's needs, including people previously unfamiliar with `mise`, we may make `mise` the recommended way to set up a development environment. This tool manages the necessary dependencies for you, eliminating the need for a separate setup process. `mise` automatically installs the required tools when they are needed. Here are some of the commands you may find yourself using frequently during development: * `mise test`: Runs all tests. * `mise test <string>`: Runs tests that contain a specific string. For example, `mise test squash` would run tests with "squash" in their name. * `mise build`: Compiles `jj`. * `mise build:release`: Compiles `jj` in release mode. * `mise build:docs`: Builds the documentation for `jj`. For a complete list of all available tasks, you can run `mise tasks` or review the configuration file at `.config/mise.toml`. You can customize this configuration using [a `mise.local.toml` file](https://mise.jdx.dev/configuration.html#mise-toml).