Commit graph

312 commits

Author SHA1 Message Date
Yuya Nishihara
c93682f218 revset: parameterize default string pattern kind, add config knob
Some checks are pending
binaries / Build binary artifacts (push) Waiting to run
website / prerelease-docs-build-deploy (ubuntu-24.04) (push) Waiting to run
Scorecards supply-chain security / Scorecards analysis (push) Waiting to run
Glob patterns will be enabled by default globally. Since this will be a big
breaking change in revsets, this patch adds a config knob to turn the new
default on/off.
2025-11-24 01:39:32 +00:00
Yuya Nishihara
3b37ed102e tests: specify string pattern prefix, use subject(glob:_) accordingly
Deprecation warnings will be emitted for default "substring:" patterns. This
change will suppress them. Since "glob:" will be the new default, I made these
tests use "glob:" when both "exact:" and "glob:" work.

Tests for the revset filter functions aren't updated.
2025-11-24 01:39:32 +00:00
Scott Taylor
5aa71d59a9 lib: replace MergedTreeId with MergedTree and Merge<TreeId>
After the previous commit, `MergedTree` and `MergedTreeId` are almost
identical, with the only difference being that `MergedTree` is attached
to a `Store` instance. `MergedTreeId` is also equivalent to
`Merge<TreeId>`, since it is just a wrapper around it.

In the future, `MergedTree` might contain additional metadata like
conflict labels. Therefore, I replaced `MergedTreeId` with `MergedTree`
wherever I think it would be required to pass this additional metadata,
or where the additional methods provided by `MergedTree` would be
useful. In any remaining places, I replaced it with `Merge<TreeId>`.

I also renamed some of the `tree_id()` methods to `tree_ids()` for
consistency, since now they return a merge of individual tree IDs
instead of a single "merged tree ID". Similarly, `MergedTree` no longer
has an `id()` method, since tree IDs won't fully identify a `MergedTree`
once it contains additional metadata.
2025-11-08 14:06:58 +00:00
Yuya Nishihara
d6b5530513 revset: do not ignore "git" remote if user pattern is specified
Since we can now express the default pattern as `remote=~exact:"git"`, we can
unblock queries matching the "git" remote.
2025-10-31 00:37:50 +00:00
Yuya Nishihara
626e5b29a6 revset: parameterize special "git" remote that is ignored by default
The default remote parameter of remote_bookmarks() will be derived from this
parameter. It doesn't make sense to exclude @git bookmarks if the backend isn't
Git. It's also nice that parsing tests don't depend on the feature flag.
2025-10-31 00:37:50 +00:00
Yuya Nishihara
f7256f611c revset: parse string patterns into StringExpression
Some checks are pending
binaries / Build binary artifacts (push) Waiting to run
website / prerelease-docs-build-deploy (ubuntu-24.04) (push) Waiting to run
Scorecards supply-chain security / Scorecards analysis (push) Waiting to run
A typical use case is to query bookmarked revisions ignoring auto-generated
bookmarks. `bookmarks() ~ bookmarks(x)` doesn't work because a revision may have
multiple bookmarks. It's also nice that we can document the default of
`remote_bookmarks()` as `remote_bookmarks(remote=~exact:"git")`.

Closes #7665
2025-10-29 23:59:58 +00:00
Yuya Nishihara
c7ffb5d42a view: rename remaining local "tag" functions 2025-09-30 13:51:40 +00:00
Yuya Nishihara
46d5555be4 cleanup: leverage trait upcasting, delete as_any*()
This patch also adds .downcast*() wrappers to prevent misuse of as &Any casting.
The compiler wouldn't help detect &Arc<T> as &Any, for example.

https://blog.rust-lang.org/2025/04/03/Rust-1.86.0/#trait-upcasting
2025-09-20 01:22:47 +00:00
Austin Seipp
7ec5980f26 revset: add new exactly(x, n) expression
Some checks are pending
binaries / Build binary artifacts (push) Waiting to run
website / prerelease-docs-build-deploy (ubuntu-24.04) (push) Waiting to run
Scorecards supply-chain security / Scorecards analysis (push) Waiting to run
With `all:` having gone away, some users (including me) had been using it
to enforce an invariant: by omitting it, an expression was guaranteed to
yield exactly one result. For example, this is important when using tools
like `jj rebase -B/-A`

Instead, let's fix that case by building that functionality into the
revset language itself. The previous behavior can now be enforced via
the term `exactly(x, 1)`

In the future, `n` could also be a range.

Signed-off-by: Austin Seipp <aseipp@pobox.com>
2025-09-18 18:48:12 +00:00
Martin von Zweigbergk
ba60fe1c61 revset: require SymbolResolverExtension to be Send and Sync
Some checks are pending
binaries / Build binary artifacts (push) Waiting to run
website / prerelease-docs-build-deploy (ubuntu-24.04) (push) Waiting to run
Scorecards supply-chain security / Scorecards analysis (push) Waiting to run
This will make `RevsetExtensions` also `Send` and `Sync`, which the
CLI crate already kind of assumes since it stores `RevsetExtensions`
in an `Arc`.
2025-09-05 11:25:22 +00:00
Yuya Nishihara
2391764ab7 revset: integrate change-path index
The current implementation does linear search, which I think is good assuming
the size of the changed paths set is usually small. The next costly part of "jj
log PATH" is commit.empty() template on merge commits (#5411). We'll need a
public API to query changed-path index to optimize it.
2025-08-15 11:46:49 +00:00
Scott Taylor
760ca1525b revset: add first_parent() function
Resolves #4579.
2025-07-31 22:17:05 +00:00
Martin von Zweigbergk
28562f1b10 tests: remove CommitGraphBuilder
The `CommitGraphBuilder` type doesn't seem to carry its weight
anymore.
2025-07-31 04:56:34 +00:00
Martin von Zweigbergk
ca6edfaab0 tests: add a helper for writing random commit with given parents 2025-07-31 04:56:34 +00:00
Scott Taylor
f65e42c60d revset: optimize heads(first_ancestors(x) & ...)
This optimization is already done for `heads(ancestors(x) & ...)`, so I
think it makes sense to extend it to `first_ancestors()` as well. This
is especially important if the expression involves a filter that
requires reading commits. For instance, in the nixpkgs repo, evaluating
`heads(first_ancestors(@) & description(jujutsu))` takes 2.6 seconds on
my machine before this optimization, and only 0.2 seconds after.
2025-07-30 11:57:33 +00:00
Scott Taylor
1f8aede388 revset: add first_ancestors() function 2025-07-28 22:16:04 +00:00
Austin Seipp
ba24140f1d cli, lib: move to Rust 2024 language edition
This applies a `cargo fmt` and fixes clippy lints to keep the build
properly working.

Signed-off-by: Austin Seipp <aseipp@pobox.com>
2025-07-28 17:05:41 +00:00
Martin von Zweigbergk
94b99b2460 revset: add naive version of bisect() function
This adds a version of the `bisect()` revset that simply takes the
midpoint of the input set when iterated over. That's correct in linear
history and probably usually good enough in non-linear history too. We
can improve it later. I think it's valuable to have this building
block even in an imperfect state.
2025-07-27 13:31:26 +00:00
Scott Taylor
63d8372a2b revset_engine: evaluate X as predicate in reachable(X, Y)
Benchmark results on Git repo:

```
reachable(@, all())                 no significant change
reachable(@, v2.49.0..)             no significant change
reachable(author(peff), all())      2.0% faster
reachable(author(peff), v2.49.0..)  94.3% faster
```
2025-07-26 13:50:05 +00:00
Martin von Zweigbergk
8022a49d9b merged_tree: make resolve() and merge() async 2025-07-25 17:58:18 +00:00
Yuya Nishihara
3269c63bdf str_util: add is_match_bytes(), use it in diff_contains() revset
We don't have an intuitive way to search for non-UTF-8 strings with
diff_contains(), but this allows the user to search for UTF-8 patterns inside
files of arbitrary encoding (such as text logs.)

We could instead make .is_match() accept AsRef<[u8]>, but I think an explicit
bytes method is better. haystack is usually a string.
2025-07-25 10:44:34 +00:00
Martin von Zweigbergk
191369f06f merged_tree: make merge() take all args by value
This avoids unnecessary cloning. Most of the callers don't need copies
of the trees anyway.
2025-07-24 21:28:40 +00:00
Yuya Nishihara
be094ef76e revset: don't resolve symbol expression to multiple revisions
It's surprising that a symbol expression may be resolved to multiple revisions,
and that's one of the reason we require all: modifier in some places. Let's make
a symbol resolution fail in that case so we can deprecate the all: syntax.

The new error hints are a bit less informative, but I don't want to implement
ad-hoc formatting for resolve_some_revsets_default_single(). The user will have
to review the graph anyway in order to resolve divergence/conflicts.

Closes #5632
2025-07-07 14:11:29 +00:00
Yuya Nishihara
8db40c7fa2 revset: add change_id/commit_id(prefix) predicates
Basically, these functions work in the same way as bookmarks()/tags(). They
restrict the namespace to search the specified symbol, and unmatched symbol
isn't an error. One major difference is that ambiguous prefix triggers an error.
That's because ambiguous prefix should logically select all matching entries,
whereas the underlying functions don't provide this behavior. It's also unclear
whether we would want to get all matching commits by commit_id(prefix:'').

#5632
2025-06-30 14:38:50 +00:00
Scott Taylor
bcde9ca728 revset: add parents(x, depth) and children(x, depth)
Resolves #3337.
2025-06-29 03:51:19 +00:00
Yuya Nishihara
68c23c3ccc revset: remove SymbolResolver abstraction, rename DefaultSymbolResolver
Since the extension point is now provided by SymbolResolverExtension, this
abstraction isn't useful anymore. This change will probably help implement
commit/change_id(pattern) functions. If the resolver were abstract type, we
would have to add resolve_commit/change_id() methods separately.
2025-06-22 00:48:10 +00:00
Yuya Nishihara
3451f468bb revset: remove FailingSymbolResolver, use DefaultSymbolResolver in tests
Since UserRevsetExpression is now a different type than the resolved one, we no
longer have to resolve internal revset by using the failing resolver.
2025-06-22 00:48:10 +00:00
Yuya Nishihara
360023bcff tests: extract helper to create DefaultSymbolResolver without extensions
I also removed resolve_symbol_with_extensions() as there are no callers who pass
in non-empty extensions.
2025-06-22 00:48:10 +00:00
Yuya Nishihara
123088b8e4 revset: expand all() set to include all referenced commits
The semantics is similar to experimental.directaccess=true in Mercurial. Hidden
revisions and their ancestors become temporarily available. This means all() is
not exactly the same as ::visible_heads(). The latter never includes hidden
revisions.

We could instead transform all() to (all() | referenced_commits). However, this
wouldn't work if expressions like ::hidden are intersected/united with filters,
all(), etc.

Fixes #5871
2025-06-19 11:21:49 +00:00
Yuya Nishihara
43668934df revset: add intersection node to backend filter predicates
This was originally suggested by Scott Taylor in #6679. I thought filter
intersections would have been externalized to the set intersections, but that
was wrong. Since union of filter intersections (e.g. `(f1 | f2 & f3) & s4`) is
evaluated as `filter_within(s4, f1 | f2 & f3)`, it doesn't make sense to convert
`f2 & f3` back to set intersection `filter_within(all(), f2) & f3`.
2025-06-15 14:45:21 +00:00
Scott Taylor
58adbc0f60 revset: optimize heads of a range with filter
Resolves #6656.

Currently, evaluating an expression like `heads(::@ ~ empty())` requires
iterating over all commits in `::@` and checking the predicate against
each commit, which can be very slow. This PR implements an optimization
to convert expressions to the form `heads(x..y & filter)` when it is
possible to do so efficiently. Expressions of this form can be evaluated
using a specialized algorithm which terminates iteration early without
checking all commits.

Benchmark results on Git repo:

```
revsets/heads(author(peff))     97.248% improvement
revsets/heads(::v2.40.0)        98.467% improvement
```
2025-06-14 15:55:23 +00:00
Yuya Nishihara
523b9132c8 revset: remove redundant intersection/union with none()
Since we now have separate stage to resolve user symbols, we can simply rewrite
expressions like `x & none()` to `none()`.
2025-06-10 22:47:07 +00:00
Yuya Nishihara
6c0cd68cf1 str_util: parse regex-i:pattern as case-insensitive regex
Just for completeness. Case-insensitive search can be achieved by (?i), but doc
and hint suggest that the -i suffix works for all pattern types.

Closes #6653
2025-06-01 00:25:56 +00:00
Martin von Zweigbergk
acd824269f git: write change-id header by default
We haven't had any reports of problems from people who opted in. Since
it's early in the release cycle now, let's now test it on everyone who
builds from head, so we get almost a month of testing from those
people before it's enabled by default in a released version.

This impacts lots of test cases because the change-id header is added
to the Git commit. Most are uninteresting. `test_git_fetch` now sees
some divergent changes where it used to see only divergent bookmarks,
which makes sense.
2025-05-08 23:05:38 +00:00
Martin von Zweigbergk
ed8dcc82b3 revset: make test a little easier to update if commit id changes
This should make it easier to find the right magic numbers to produce
commit ids with the same prefix.
2025-05-08 23:05:38 +00:00
Martin von Zweigbergk
2c39ba316b revset: use simpler constants for arbitrary numbers
AFAICT, it only matters that one of the numbers results in a commit ID
that starts with "040".
2025-05-08 23:05:38 +00:00
Martin von Zweigbergk
f0545ee25c test: introduce test helpers for creating repo path types
I'm about to make the constructors return a `Result`. The helpers will
hide the unwrapping.
2025-04-15 14:42:23 +00:00
Yuya Nishihara
a1d88980a9 revset: compare conflict file contents without materializing as conflicts
The logic is similar to the color-words diff's. We first resolve trivial
conflicts, then compare each hunk of Merge<&BStr> type. We also apply the same
optimization as the resolved case to minimize lines to be merged and diffed.
2025-04-14 01:07:24 +00:00
Nils Koch
fbaa51b4ce revset: add signed function 2025-04-12 14:14:26 +00:00
Yuya Nishihara
3f5f872204 view: rename workspace "id" to "name"
This matches the current implementation.
2025-03-31 03:39:29 +00:00
Yuya Nishihara
e66c545438 view: replace WorkspaceId by string-like newtypes
I think this makes more sense because WorkspaceId is currently a human-readable
name. In error/status messages, workspace names are now printed in revset
syntax.

New WorkspaceId types do not implement Default. It would be weird if string-like
type had non-empty Default::default(). The DEFAULT constant is provided instead.
2025-03-31 03:39:29 +00:00
Yuya Nishihara
f87db58617 view: rename RemoteRefState::Tracking to Tracked
In jj's model, a local bookmark "tracks" remote bookmarks. It's wrong to call
a remote bookmark state as "tracking".
2025-03-31 01:41:31 +00:00
Yuya Nishihara
fb8e45d6f9 view: introduce GitRefName newtypes
We don't reuse the RefName type here because fully-qualified Git ref name
shouldn't be considered a local ref name in jj.
2025-03-28 01:29:30 +00:00
Yuya Nishihara
bcf3d5869b revset: add optional local variables to RevsetParseContext 2025-03-27 13:23:58 +00:00
Yuya Nishihara
ffad6fe96f revset: extract internal context struct from RevsetParseContext
This allows callers to mutate RevsetParseContext if needed.

RevsetParseContext was changed to an opaque struct at 4e0abf0631 "revset: make
RevsetParseContext opaque." I think the intent there was to hide implementation
details from revset extension functions. This is now achieved by opaque
LoweringContext.

Another reason of this change is that aliases_map is no longer needed when
transforming AST to UserRevsetExpression.
2025-03-26 13:03:41 +00:00
Yuya Nishihara
02722eae54 view: port bookmark/tag name types to RefName/RemoteName
I tried to minimize this patch, but it seemed rather complicated than porting
most callers all at once. Remote management functions in git.rs are unchanged.
They'll be ported separately.

With this change, many non-template bookmark/remote name outputs should be
rendered in revset syntax.
2025-03-26 11:07:06 +00:00
Yuya Nishihara
cc8a80c548 ref_name: move RemoteRefSymbol types from refs module 2025-03-26 11:07:06 +00:00
Ilya Grigoriev
acaedc3382 cleanup: enable unused_trait_names clippy lint and run clippy --fix 2025-03-16 00:35:56 +00:00
Ilya Grigoriev
5eae2d92a0 tests: run insta --force-update-snapshots
This is a replacement for #5558.

Thanks to @yuja 's https://github.com/mitsuhiko/insta/pull/722, this is
now easy to generate.
2025-03-06 21:35:08 +00:00
Ilya Grigoriev
1ede79c483 MSRV: Update to 1.84 and run clippy --fix, cargo fmt
The CI seems to correctly use rustc 1.84.1 (and not 1.84.0) with this.

For reference, we last updated the MSRV to 1.76 in 5b517b5. According to
https://releases.rs/docs/1.76.0/, this was when it barely became stable.

`flake.nix` seems to be using a nightly toolchain now, so it seems there
is no need to update the version there.

The more precise clippy command used was:

cargo clippy --workspace --all-targets --fix
2025-03-06 07:24:28 +00:00