v0.30.0

jj-vcs/jjv0.30.0Jun 4, 2025by yuja

AI Summary

Experimental support for transferring change IDs to Git remotes has been enabled by default, the old `libgit2` code path has been removed, and `jj split` has gained new options for placement and messaging.

Key Highlights

  • Experimental support for transferring change IDs to Git remotes is now enabled by default
  • The old `libgit2` code path for fetches and pushes has been removed
  • `jj split` has gained `--message`, `--insert-before`, `--insert-after`, and `--destination` options

Breaking Changes

  • The old `libgit2` code path for fetches and pushes has been removed
  • In templates, bookmark/tag/remote names are now formatted in revset symbol notation
  • `jj rebase` now automatically abandons divergent commits if another commit with the same change ID is already present
  • The deprecated `--skip-empty` flag for `jj rebase` has been removed
  • External diff tools are now run in the temporary directory containing the before and after directories

New Features

  • `jj split` has gained a `--message` option to set the description
  • Added `git.track-default-bookmark-on-clone` setting
  • Templates can now do arithmetic on integers with `+`, `-`, `*`, `/`, and `%` infix operators
  • Evolution history is now stored in the operation log

Full Release Notes

### About

jj is a Git-compatible version control system that is both simple and powerful. See the [installation instructions](https://jj-vcs.github.io/jj/v0.30.0/install-and-setup/) to get started.

### Release highlights

* The experimental support from release 0.29.0 for transferring the change ID
  to/from Git remotes has been enabled by default. The change ID is stored in
  the Git commit itself (in a commit header called `change-id`), which means
  it will be transferred by regular `git push` etc. Please let us know if you
  run into any problems with it. You can disable it setting
  `git.write-change-id-header`. Note that some Git remotes (e.g GitLab) and
  some Git commands (e.g. `git rebase`) do not preserve the change ids when
  they rewrite commits.

* `jj rebase` now automatically abandons divergent commits if another commit
  with the same change ID is already present in the destination with identical
  changes.

* `jj split` has gained `--message`, `--insert-before`, `--insert-after`, and
  `--destination` options.

* `jj evolog` can show associated operations for commits created by new jj
  versions.

### Breaking changes

* The old `libgit2` code path for fetches and pushes has been removed,
  and the `git.subprocess` setting along with it.

* In templates, bookmark/tag/remote names are now formatted in revset symbol
  notation. The type of `bookmark.remote()` is changed to `Option<_>`.
  `bookmark.remote() == "foo"` still works, but `bookmark.remote().<method>()`
  might need `if(bookmark.remote(), ..)` to suppress error.

* `jj rebase` now automatically abandons divergent commits if another commit
  with the same change ID is already present in the destination with identical
  changes. To keep these divergent commits, use the `--keep-divergent` flag.

* The deprecated `--skip-empty` flag for `jj rebase` has been removed. Use the
  `--skip-emptied` flag instead.

* The deprecated `jj branch` subcommands have been removed. Use the `jj
  bookmark` subcommands instead.

* `jj util completion` now requires the name of the shell as a positional
  argument and no longer produces Bash completions by default. The deprecated
  optional arguments for different shells have been removed.

* (**Update:** this entry was mistakenly omitted in the release notes previously)
  External diff tools are now run in the temporary directory containing
  the before (`left`) and after (`right`) directories, making diffs appear
  more pleasing for tools that display file paths prominently. Users can
  opt out of this by setting `merge-tools.<tool>.diff-do-chdir = false`,
  but this will likely be removed in a future release. Please report any
  issues you run into.

### Deprecations

* The `ui.diff.format` and `ui.diff.tool` config options have been merged as
  `ui.diff-formatter`. The builtin format can be specified as `:<format>`
  (e.g. `ui.diff-formatter=":git"` for Git diffs.)

* The `.normal_hex()` method will be removed from the `CommitId` template type.
  It's useful only for the `ChangeId` type.

### New features

* `jj split` has gained a `--message` option to set the description of the
  commit with the selected changes.

* `jj split` has gained the ability to place the revision with the selected
  changes anywhere in the revision tree with the `--insert-before`,
  `--insert-after` and `--destination` command line flags.

* Added `git.track-default-bookmark-on-clone` setting to control whether to
  track the default remote bookmark on `jj git clone`.

* Templates can now do arithmetic on integers with the `+`, `-`, `*`, `/`, and
  `%` infix operators.

* Evolution history is now stored in the operation log. `jj evolog` can show
  associated operations for commits created by new jj versions.

### Fixed bugs

* Work around a git issue that could cause subprocess operations to hang if the
  `core.fsmonitor` gitconfig is set in the global or system gitconfigs.
  [#6440](https://github.com/jj-vcs/jj/issues/6440)

* `jj parallelize` can now parallelize groups of changes that _start_ with an
  immutable change, but do not contain any other immutable changes.

* `jj` will no longer warn about deprecated paths on macOS if the configured
  XDG directory is the deprecated one (~/Library/Application Support).

* The builtin diff editor now correctly handles splitting changes where a file
  is replaced by a directory of the same name.
  [#5189](https://github.com/jj-vcs/jj/issues/5189)

### Packaging changes

* Due to the removal of the `libgit2` code path, packagers should remove any
  dependencies on `libgit2`, `libssh2`, Zlib, OpenSSL, and `pkg-config`, and
  ensure they are not setting the Cargo `git2` or `vendored-openssl` features.

### Contributors

Thanks to the people who made this release happen!

* Alper Cugun (@alper)
* Austin Seipp (@thoughtpolice)
* Benjamin Brittain (@benbrittain)
* Benjamin Tan (@bnjmnt4n)
* Bryce Berger (@bryceberger)
* Colin Nelson (@orthros)
* Doug Stephen (@dljsjr)
* Emily (@emilazy)
* Eyvind Bernhardsen (@eyvind)
* Felix Geisendörfer (@felixge)
* Gaëtan Lehmann (@glehmann)
* Ilya Grigoriev (@ilyagr)
* Isaac Corbrey (@icorbrey)
* Jonas Greitemann (@jgreitemann)
* Josep Mengual (@truita)
* kkoang (@kkoang)
* Manuel Mendez (@mmlb)
* Marshall Bowers (@maxdeviant)
* Martin von Zweigbergk (@martinvonz)
* Mateus Auler (@mateusauler)
* Michael Pratt (@prattmic)
* Nicole Patricia Mazzuca (@strega-nil)
* Philip Metzger (@PhilipMetzger)
* Scott Taylor (@scott2000)
* T6 (@tjjfvi)
* Vincent Ging Ho Yim (@cenviity)
* Winter (@winterqt)
* Yuya Nishihara (@yuja)