just playing with tangled
1# How to Contribute
2
3
4## Policies
5
6We'd love to accept your patches and contributions to this project. There are
7just a few small guidelines you need to follow.
8
9### Contributor License Agreement
10
11Contributions to this project must be accompanied by a Contributor License
12Agreement. You (or your employer) retain the copyright to your contribution;
13this simply gives us permission to use and redistribute your contributions as
14part of the project. Head over to <https://cla.developers.google.com/> to see
15your current agreements on file or to sign a new one.
16
17You generally only need to submit a CLA once, so if you've already submitted one
18(even if it was for a different project), you probably don't need to do it
19again.
20
21### Commit guidelines
22
23Unlike many GitHub projects (but like many VCS projects), we care more about the
24contents of commits than about the contents of PRs. We review each commit
25separately, and we don't squash-merge the PR (so please manually squash any
26fixup commits before sending for review).
27
28Each commit should ideally do one thing. For example, if you need to refactor a
29function in order to add a new feature cleanly, put the refactoring in one
30commit and the new feature in a different commit. If the refactoring itself
31consists of many parts, try to separate out those into separate commits. You can
32use `jj split` to do it if you didn't realize ahead of time how it should be
33split up. Include tests and documentation in the same commit as the code they
34test and document.
35
36The commit message should describe the changes in the commit;
37the PR description can even be empty, but feel free to include a personal
38message. We start the commit message with `<topic>: ` and don't use
39[conventional commits](https://www.conventionalcommits.org/en/v1.0.0/). This means if
40you modified a command in the CLI, use its name as the topic, e.g.
41`next/prev: <your-modification>` or `conflicts: <your-modification>`. We don't
42currently have a specific guidelines on what to write in the topic field, but
43the reviewers will help you provide a topic if you have difficulties choosing
44it. [How to Write a Git Commit Message](https://cbea.ms/git-commit/) is a good
45guide if you're new to writing good commit messages. We are not particularly
46strict about the style, but please do explain the reason for the change unless
47it's obvious.
48
49### Code reviews
50
51All submissions, including submissions by project members, require review. We
52use GitHub pull requests for this purpose. Consult
53[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
54information on using pull requests.
55
56When you address comments on a PR, don't make the changes in a commit on top (as
57is typical on GitHub). Instead, please make the changes in the appropriate
58commit. You can do that by creating a new commit on top of the initial commit
59 (`jj new <commit>`) and then squash in the changes when you're done (`jj squash`).
60`jj git push`
61will automatically force-push the bookmark.
62
63When your first PR has been approved, we typically invite you to the
64`jj-vcs/contributors` team to give you contributor access,
65so you can address any remaining minor comments and then merge the PR yourself
66when you're ready. If you realize that some comments require non-trivial
67changes, please ask your reviewer to take another look.
68
69If your employer pays anyone (not necessarily you) to contribute to Jujutsu,
70please make sure your GitHub username is [recorded](paid_contributors.md).
71To avoid conflicts of interest, please don't merge a PR that has only been
72approved by someone from the same organization. Similarly, as a reviewer, there
73is no need to approve your coworkers' PRs, since the author should await an
74approval from someone else anyway. It is of course still appreciated if you
75review and comment on their PRs. Also, if the PR seems completely unrelated to
76your company's interests, do feel free to approve it.
77
78### Community Guidelines
79
80This project follows [Google's Open Source Community
81Guidelines](https://opensource.google/conduct/).
82
83## Contributing large patches
84
85Before sending a PR for a large change which designs/redesigns or reworks an
86existing component, we require an architecture review from multiple
87stakeholders, which we do with [Design Docs](design_docs.md), see the
88[process here](design_docs.md#process).
89
90## Contributing to the documentation
91
92We appreciate [bug
93reports](https://github.com/jj-vcs/jj/issues/new?template=bug_report.md)
94about any problems, however small, lurking in [our documentation
95website](https://jj-vcs.github.io/jj/prerelease) or in the `jj help
96<command>` docs. If a part of the bug report template does not apply, you can
97just delete it.
98
99Before reporting a problem with the documentation website, we'd appreciate it if
100you could check that the problem still exists in the "prerelease" version of the
101documentation (as opposed to the docs for one of the released versions of `jj`).
102You can use the version switcher in the top-left of the website to do so.
103
104If you are willing to make a PR fixing a documentation problem, even better!
105
106The documentation website sources are Markdown files located in the [`docs/`
107directory](https://github.com/jj-vcs/jj/tree/main/docs). You do not need to
108know Rust to work with them. See below for [instructions on how to preview the
109HTML docs](#previewing-the-html-documentation) as you edit the Markdown files.
110Doing so is optional, but recommended.
111
112The `jj help` docs are sourced from the "docstring" comments inside the Rust
113sources, currently from the [`cli/src/commands`
114directory](https://github.com/jj-vcs/jj/tree/main/cli/src/commands). Working
115on them requires setting up a Rust development environment, as described
116below, and may occasionally require adjusting a test.
117
118
119## Learning Rust
120
121In addition to the [Rust Book](https://doc.rust-lang.org/book/) and the other
122excellent resources at <https://www.rust-lang.org/learn>, we recommend the
123["Comprehensive Rust" mini-course](https://google.github.io/comprehensive-rust/)
124for an overview, especially if you are familiar with C++.
125
126## Setting up a development environment
127
128To develop `jj`, the mandatory steps are simply
129to [install Rust](https://www.rust-lang.org/tools/install) (the default
130installer options are fine), clone the repository, and use `cargo build`
131, `cargo fmt`,
132`cargo clippy --workspace --all-targets`, and
133`cargo test --workspace`. If you are preparing a PR, there are some additional
134recommended steps.
135
136### Summary
137
138One-time setup:
139
140 rustup toolchain add nightly # wanted for 'rustfmt'
141 rustup toolchain add 1.84 # also specified in Cargo.toml
142 cargo install --locked bacon
143 cargo install --locked cargo-insta
144 cargo install --locked cargo-nextest
145
146During development (adapt according to your preference):
147
148 bacon clippy-all
149 cargo +nightly fmt # Occasionally
150 cargo nextest run --workspace # Occasionally
151 cargo insta test --workspace --test-runner nextest # Occasionally
152
153!!! warning
154
155 Build artifacts from debug builds and especially from repeated
156 invocations of `cargo test` can quickly take up 10s of GB of disk space.
157 Cargo will happily use up your entire hard drive. If this happens, run
158 `cargo clean`.
159
160### Explanation
161
162These are listed roughly in order of decreasing importance.
163
1641. Nearly any change to `jj`'s CLI will require writing or updating snapshot
165 tests that use the [`insta`](https://insta.rs/) crate. To make this
166 convenient, install the `cargo-insta` binary.
167 Use `cargo insta test --workspace` to run tests,
168 and `cargo insta review --workspace` to update the snapshot tests.
169 The `--workspace` flag is needed to run the tests on all crates; by default,
170 only the crate in the current directory is tested.
171
1722. GitHub CI checks require that the code is formatted with the *nightly*
173 version of `rustfmt`. To do this on your computer, install the nightly
174 toolchain and use `cargo +nightly fmt`.
175
1763. Your code will be rejected if it cannot be compiled with the minimal
177 supported version of Rust ("MSRV"). Currently, `jj` follows a rather
178 casual MSRV policy: "The current `rustc` stable version, minus one."
179 As of this writing, that version is **1.84.0**.
180
1814. Your code needs to pass `cargo clippy`. You can also
182 use `cargo +nightly clippy` if you wish to see more warnings.
183
1845. You may also want to install and use [`bacon`](https://dystroy.org/bacon/),
185 to automatically build, check, and / or run tests.
186
1876. To run tests more quickly, use `cargo nextest run --workspace`. To
188 use `nextest` with `insta`, use `cargo insta test --workspace
189 --test-runner nextest`.
190
191 On Linux, you may be able to speed up `nextest` even further by using
192 the `mold` linker, as explained below.
193
194
195### Configuring `jj fix` to run `rustfmt`
196
197Run this in the jj repo:
198
199```shell
200jj config set --repo fix.tools.rustfmt '{ command = ["rustfmt", "+nightly"], patterns = ["glob:**/*.rs"] }'
201```
202
203### Using `mold` for faster tests on Linux
204
205On a machine with a multi-core CPU, one way to speed up
206`cargo nextest` on Linux is to use the multi-threaded [`mold`
207linker](https://github.com/rui314/mold). This linker may help
208if, currently, your CPU is underused while Rust is linking test
209binaries. Before proceeding with `mold`, you can check whether this is
210an issue worth solving using a system monitoring tool such as `htop`.
211
212`mold` is packaged for many distributions. On Debian, for example,
213`sudo apt install mold` should just work.
214
215A simple way to use `mold` is via the `-run` option, e.g.:
216
217```shell
218mold -run cargo insta test --workspace --test-runner nextest
219```
220
221There will be no indication that a different linker is used, except for
222higher CPU usage while linking and, hopefully, faster completion. You
223can verify that `mold` was indeed used by running
224`readelf -p .comment target/debug/jj`.
225
226There are also ways of having Rust use `mold` by default, see the ["How
227to use" instructions](https://github.com/rui314/mold#how-to-use).
228
229On recent versions of MacOS, the default linker Rust uses is already
230multi-threaded. It should use all the CPU cores without any configuration.
231
232### Editor setup
233
234#### Visual Studio Code
235
236We recommend at least these settings:
237
238```js
239{
240 "files.insertFinalNewline": true,
241 "files.trimTrailingWhitespace": true,
242 "[rust]": {
243 "files.trimTrailingWhitespace": false
244 }
245}
246```
247
248#### Zed
249
250```js
251// .zed/settings.json
252{
253 "ensure_final_newline_on_save": true,
254 "remove_trailing_whitespace_on_save": true,
255
256 "languages": {
257 // We don't use a formatter for Markdown files, so format_on_save would just
258 // mess with others' docs
259 "Markdown": { "format_on_save": "off" }
260 "Rust": {
261 "format_on_save": "on",
262 // Avoid removing trailing spaces within multi-line string literals
263 "remove_trailing_whitespace_on_save": false
264 }
265 },
266
267 "lsp": {
268 "rust-analyzer": {
269 "initialization_options": {
270 // If you are working on docs and don't need `cargo check`, uncomment
271 // this option:
272 //
273 // "checkOnSave": false,
274
275 // Use nightly `rustfmt`, equivalent to `cargo +nightly fmt`
276 "rustfmt": { "extraArgs": ["+nightly"] }
277 }
278 }
279 }
280}
281```
282
283## Previewing the HTML documentation
284
285The documentation for `jj` is automatically published online at
286<https://jj-vcs.github.io/jj/>.
287
288When editing documentation, you should check your changes locally — especially
289if you are adding a new page, or doing a major rewrite.
290
291### Install `uv`
292
293The only thing you need is [`uv`][uv] (version 0.5.1 or newer).
294
295`uv` is a Python project manager written in Rust. It will fetch the right Python
296version and the dependencies needed to build the docs. Install it like so:
297
298[uv]: https://docs.astral.sh/uv/
299
300=== "macOS/Linux"
301
302 ``` { .shell .copy }
303 curl -LsSf https://astral.sh/uv/install.sh | sh
304 ```
305
306 !!! note
307 If you don't have `~/.local/bin` in your `PATH`, the installer will
308 modify your shell profile. To avoid it:
309
310 ``` { .shell .copy }
311 curl -LsSf https://astral.sh/uv/install.sh | env INSTALLER_NO_MODIFY_PATH=1 sh
312 ```
313
314=== "Windows"
315
316 ``` { .shell .copy }
317 powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
318 ```
319
320=== "Homebrew"
321
322 ``` { .shell .copy }
323 brew install uv
324 ```
325
326=== "Cargo"
327
328 ``` { .shell .copy }
329 # This might take a while
330 cargo install --git https://github.com/astral-sh/uv uv
331 ```
332
333=== "Other options"
334
335 * Directly download the binaries from GitHub: [uv releases](https://github.com/astral-sh/uv/releases).
336 * Even more options: [Installing uv](https://docs.astral.sh/uv/getting-started/installation/).
337
338### Build the docs
339
340To build the docs, run from the root of the `jj` repository:
341
342``` { .shell .copy }
343uv run mkdocs serve
344```
345
346Open <http://127.0.0.1:8000> in your browser to see the docs.
347
348As you edit the `.md` files in `docs/`, the website should be rebuilt and
349reloaded in your browser automatically.
350
351!!! note "If the docs are not updating"
352 Check the terminal from which you ran `uv run mkdocs serve` for any build
353 errors or warnings. Warnings about `"GET /versions.json HTTP/1.1" code 404`
354 are expected and harmless.
355
356## Building the entire website
357
358!!! tip
359 Building the entire website is not usually necessary. If you are editing
360 documentation, the previous section is enough.
361
362 These instructions are relevant if you are working on the versioning of the
363 documentation that we currently do with `mike`.
364
365The full `jj` website includes the documentation for several `jj` versions
366(`prerelease`, latest release, and the older releases). The top-level
367URL <https://jj-vcs.github.io/jj> redirects to
368<https://jj-vcs.github.io/jj/latest>, which in turn redirects to
369the docs for the last stable version.
370
371The different versions of documentation are managed and deployed with
372[`mike`](https://github.com/jimporter/mike), which can be run with
373`uv run mike`.
374
375On a POSIX system or WSL, one way to build the entire website is as follows (on
376Windows, you'll need to understand and adapt the shell script):
377
3781. Check out `jj` as a co-located `jj + git` repository (`jj clone --colocate`),
379cloned from your fork of `jj` (e.g. `github.com/jjfan/jj`). You can also use a
380pure Git repo if you prefer.
381
3822. Make sure `github.com/jjfan/jj` includes the `gh-pages` bookmark of the jj repo
383and run `git fetch origin gh-pages`.
384
3853. Go to the GitHub repository settings, enable GitHub Pages, and configure them
386to use the `gh-pages` bookmark (this is usually the default).
387
3884. Install `uv` as explained in [Previewing the HTML
389documentation](#previewing-the-html-documentation), and run the same `sh` script
390that is used in GitHub CI (details below):
391
392 ```shell
393 .github/scripts/docs-build-deploy prerelease main --push
394 ```
395
396 This should build the version of the docs from the current commit,
397 deploy it as a new commit to the `gh-pages` bookmark,
398 and push the `gh-pages` bookmark to the origin.
399
4005. Now, you should be able to see the full website, including your latest changes
401to the `prerelease` version, at `https://jjfan.github.io/jj/prerelease/`.
402
4036. (Optional) The previous steps actually only rebuild
404`https://jjfan.github.io/jj/prerelease/` and its alias
405`https://jjfan.github.io/jj/main/`. If you'd like to test out version switching
406back and forth, you can also rebuild the docs for the latest release as follows.
407
408 ```shell
409 jj new v1.33.1 # Let's say `jj 1.33.1` is the currently the latest release
410 .github/scripts/docs-build-deploy v1.33.1 latest --push
411 ```
412
4137. (Optional) When you are done, you may want to reset the `gh-pages` bookmark to the
414same spot as it is upstream. If you configured the "upstream" remote,
415this can be done with:
416
417 ```shell
418 # This will LOSE any changes you made to `gh-pages`
419 jj git fetch --remote upstream
420 jj bookmark set gh-pages -r gh-pages@upstream
421 jj git push --remote origin --bookmark gh-pages
422 ```
423
424 If you want to preserve some of the changes you made, you can do `jj bookmark
425 set my-changes -r gh-pages` BEFORE running the above commands.
426
427### Explanation of the `docs-build-deploy` script
428
429The script sets up a few environment variables and invokes `uv run mike deploy`
430with some default arguments and whatever arguments were passed to
431`docs-build-deploy`. Run `uv run mike help deploy` to find out what the
432arguments do.
433
434If you need to do something more complicated, you can use `uv run mike
435...` commands. You can also edit the `gh-pages` bookmark directly, but take care
436to avoid files that will be overwritten by future invocations of `mike`. Then,
437you can submit a PR based on the `gh-pages` bookmark of
438<https://jj-vcs.github.com/jj> (instead of the usual `main` bookmark).
439
440Previously, the version switcher would not work unless the value of the
441`site_url` config in `mkdocs.yml` matched the actual URL the site is being
442served from. This bug should now be fixed, but if you are not serving the site
443from https://jj-vcs.github.com/jj and something does not work weirdly, you might
444want to adjust the `site_url` to something like `https://jjfan.github.io/jj`.
445
446
447## Modifying protobuffers (this is not common)
448
449 Occasionally, you may need to change the `.proto` files that define jj's data
450 storage format. In this case, you will need to add a few steps to the above
451 workflow.
452
453 - Install the `protoc` compiler. This usually means either `apt-get install
454 protobuf-compiler` or downloading [an official release]. The
455 `prost` [library docs] have additional advice.
456 - Run `cargo run -p gen-protos` regularly (or after every edit to a `.proto`
457 file). This is the same as running `cargo run` from `lib/gen-protos`. The
458 `gen-protos` binary will use the `prost-build` library to compile the
459 `.proto` files into `.rs` files.
460 - If you are adding a new `.proto` file, you will need to edit the list of
461 these files in `lib/gen-protos/src/main.rs`.
462
463[an official release]: https://github.com/protocolbuffers/protobuf/releases
464[library docs]: https://docs.rs/prost-build/latest/prost_build/#sourcing-protoc
465
466 The `.rs` files generated from `.proto` files are included in the repository,
467 and there is a GitHub CI check that will complain if they do not match.
468
469## Logging
470
471You can print internal jj logs using `JJ_LOG`. It acts like the `RUST_LOG`
472environment variable, frequent in Rust codebases, and accepts one or more
473[directives]. You can also run `JJ_LOG=debug jj` to get `debug` level logs
474enabled for all targets. You can also use the `--debug` global option, which
475turns on `debug` log level for `jj-lib` and `jj-cli` only.
476
477[directives]: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives
478
479## Profiling
480
481One easy-to-use sampling profiler
482is [samply](https://github.com/mstange/samply). For example:
483```shell
484cargo install samply
485samply record jj diff
486```
487Then just open the link it prints.
488
489Another option is to use the instrumentation we've added manually (using
490`tracing::instrument`) in various places. For example:
491```shell
492JJ_TRACE=/tmp/trace.json jj diff
493```
494Then go to `https://ui.perfetto.dev/` in Chrome and load `/tmp/trace.json` from
495there.