v0.44.0

jj-vcs/jjv0.44.0Aug 6, 2026by martinvonz

AI Summary

Stabilizes tag fetching and pushing, introduces the merge_point() revset, and enhances jj run with parallel processing and error handling flags.

Key Highlights

  • Stabilized fetching and pushing of tags (tracked vs untracked)
  • New merge_point() revset function to find branch merge points
  • Enhanced jj run command with parallel processing and passthrough flags
  • jj file search now supports line numbers (-n)

Breaking Changes

  • jj git fetch now fetches tags automatically (previously respected Git's tagOpt)
  • jj git clone --fetch-tags=all|none|included removed in favor of --tag=PATTERN
  • jj git push --all now pushes all tags in addition to bookmarks
  • WorkspaceRef.root() and RepoPath.absolute() return types changed to Option<FsPath>
  • jj file search output format changed to show full paths
  • Arguments passed multiple times now allow last occurrence to win

New Features

  • New merge_point() revset function
  • New try(expr, fallback...) template function
  • jj run flags: --passthrough, --ignore-changes, --ignore-errors
  • jj tag track/untrack commands
  • builtin_log() revset alias
  • diff.stat.max-bar-width config option
  • jj absorb --interactive/--tool support

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.44.0/install-and-setup/) to get started.

### Release highlights

* Support for fetching and pushing tags has now been stabilized. Tags can be
  tracked or untracked just like bookmarks. Tracked tags are pushed by default.

### Breaking changes

* `jj git fetch` now fetches tags the same way it fetches bookmarks. Tags are
  fetched as `<name>@<remote>`, and these remote tags are automatically tracked
  by local tags of the same name. Running `jj git fetch` in an existing
  repository will re-fetch all tags to initialize the tracking state.

  Git's `tagOpt` is no longer respected. To disable tag fetching, set
  `remotes.<name>.fetch-tags = '~*'` in the jj configuration.

* `jj git clone --fetch-tags=all|none|included` is removed in favor of
  `--tag=PATTERN`.

* `jj git push --all` now pushes all tags in addition to bookmarks.

* The `WorkspaceRef.root()` and `RepoPath.absolute()` template functions now
  return `Option<FsPath>` and `FsPath` respectively, instead of `String`. The
  `path` keyword in `jj config list` templates now returns `Option<FsPath>`.

* `jj file search` now prints every matched line prefixed by the file path,
  instead of only the file paths of files containing a match. Use
  `--name-only` for the previous behavior.
  [#9399](https://github.com/jj-vcs/jj/issues/9399)

* Passing an argument more than once is no longer an error. The last occurrence
  wins, so `jj --no-pager --no-pager version` and `jj log -n 5 -n 10` now work,
  and an argument baked into an alias or a wrapper can be given explicitly as
  well. Arguments that can be specified multiple times, such as `--config` and
  `jj log -r`, are unaffected and still collect all of their values.
  [#8101](https://github.com/jj-vcs/jj/issues/8101)
  [#9859](https://github.com/jj-vcs/jj/issues/9859)

### Deprecations

None

### New features

* New `merge_point()` revset function which (similar to `fork_point`) finds the
  point where multiple branches merge.

* `jj workspace list` now shows workspace roots by default. The output can be
  customized with `templates.workspace_list` or `-T`, and `WorkspaceRef.root()`
  returns an optional `FsPath` value.
  [#9713](https://github.com/jj-vcs/jj/pull/9713),
  [#9826](https://github.com/jj-vcs/jj/pull/9826)

* New `try(expr, fallback...)` template function to suppress runtime errors.

* `jj run` now processes revisions from oldest to newest by default. The start
  order is guaranteed: each revision begins execution only after the previous
  one has started, even with `--jobs` higher than 1.

* `jj run` gained a `--passthrough` flag that connects the subprocess's
  stdout/stderr directly to the terminal instead of capturing output.

* `jj run` gained a `--ignore-changes` flag to avoid editing any revisions even
  if the command modifies the working copy.

* `jj run` gained a `--ignore-errors` flag to continue running against the
  remaining revisions even if the command exits with a nonzero exit code.

* `jj file search` now supports `-n`/`--line-number` to prefix each match with
  its 1-based line number within the file.

* `jj git push` gained a `--allow-conflicts` flag to allow pushing commits
  containing conflicts.

* New `jj tag track`/`untrack` commands to associate local tags with remotes.
  Note that fetched tags are tracked by default.

* Added `builtin_log()` revset alias for the built-in default `jj log` revset.
  `revsets.log` now defaults to `builtin_log()`, so custom log revsets can
  reuse the built-in default instead of copying its full expression.

* Added config option `diff.stat.max-bar-width` for use with `--stat` to limit
  the `++--` bar width. In the templating language, `diff.stat()` can optionally
  take a second (positional or named) argument `max_bar_width` for an equivalent
  effect.

* `jj absorb` now supports `--interactive`/`-i`/`--tool` to let you
  interactively choose which hunks from the source to consider for absorption.
  This is useful when you only want to absorb *part* of a commit without first
  splitting it. Any hunks that are not selected or cannot be absorbed remain in
  the source commit.

### Fixed bugs

* Recursive alias definitions are detected more precisely. jj can now expand
  aliases that are simply repeated. For example, with the alias `jj = []`, the
  command `jj jj jj` will resolve to `jj`. Aliases can also fall back to the
  default command. For example, with the alias `i = ["--ignore-working-copy"]`,
  `jj i` will resolve to `jj --ignore-working-copy`.

* Git temporary files are now cleaned up more reliably in the presence of
  signals (e.g. `Ctrl-C`). This should reduce the rate of "Could not acquire
  lock for index file" errors.
  ([#7530](https://github.com/jj-vcs/jj/issues/7530))

* Fixed Git HEAD mismatch after the working copy became immutable.
  [#9827](https://github.com/jj-vcs/jj/issues/9827)

* `jj` now creates a new working-copy revision as soon as the one of the current
  workspace becomes immutable, as well as during snapshotting. This brings the
  behavior closer to `jj` 0.42 and earlier.

* Snapshotting no longer fails if the working copy contains a path whose name
  isn't valid UTF-8. Such paths can't be tracked, so they are now skipped and
  reported as a warning instead.
  [#9774](https://github.com/jj-vcs/jj/issues/9774)

* Fixed failure when reading configuration in copied repo with an empty
  repo-level configuration directory.

* `jj diff` and `jj status` no longer omit a rename or copy in a merge commit
  when the renamed source is present in more than one parent. The identical copy
  record reported for each parent was mistaken for a conflict and discarded.
  [#9752](https://github.com/jj-vcs/jj/issues/9752)

* `jj run` no longer panics when its revset includes a conflicted commit. The
  conflict is now preserved in the rewritten commit.
  [#9747](https://github.com/jj-vcs/jj/issues/9747)

* Fixed a panic when passing overly-large length parameters to ID templater
  functions (`commit_id.short()`, `commit_id.shortest()`, etc.).
  [#9833](https://github.com/jj-vcs/jj/issues/9833)

* `jj git import` and `export` in colocated workspaces are now disabled by
  default. These commands usually do nothing, but they had a race condition.

### Contributors

Thanks to the people who made this release happen!

* Aaron Bies (@slerpyyy)
* Ada Alakbarova (@ada4a)
* Alexandre Hallaine (@alexandre-hallaine)
* Amaan Qureshi (@amaanq)
* Austin Seipp (@thoughtpolice)
* Caleb White (@calebdw)
* Chawye Hsu (@chawyehsu)
* David Rieber (@drieber)
* Gaëtan Lehmann (@glehmann)
* hexbinoct (@hexbinoct)
* ivelieu (@ivelieu)
* Joseph Lou (@josephlou5)
* Josh McKinney (@joshka)
* Josh Steadmon (@steadmon)
* Kevin Liao (@kevincliao)
* Luna Schwalbe (@lunagl)
* Martin von Zweigbergk (@martinvonz)
* Matt Van Horn (@mvanhorn)
* Nika Layzell (@mystor)
* Niko Savola (@nikosavola)
* Nitzan Raz (@BackSlasher)
* Noah Lev (@camelid)
* OlshaMB (@OlshaMB)
* Philip Metzger (@PhilipMetzger)
* Remo Senekowitsch (@senekor)
* Rob Pilling (@bobrippling)
* Stephen Jennings (@jennings)
* Techcable (@Techcable)
* TogarashiPepper (@TogarashiPepper)
* Vladimir Petrzhikovskii (@0xdeafbeef)
* Waleed Khan (@arxanas)
* Wang Yuantao (@0WD0)
* xtqqczze (@xtqqczze)
* Yash Bavadiya (@xevrion)
* Yuya Nishihara (@yuja)