mirror of
https://github.com/martinvonz/jj.git
synced 2024-12-24 12:48:55 +00:00
revset: split out no-args head()
to visible_heads()
The `heads()` revset function with one argument is the counterpart to `roots()`. Without arguments, it returns the visible heads in the repo, i.e. `heads(all())`. The two use cases are quite different, and I think it would be good to clarify that the no-arg form returns the visible heads, so let's split that out to a new `visible_heads()` function.
This commit is contained in:
parent
982062bd75
commit
e1c57338a1
6 changed files with 23 additions and 20 deletions
|
@ -23,6 +23,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
* The minimum supported Rust version (MSRV) is now 1.64.0.
|
* The minimum supported Rust version (MSRV) is now 1.64.0.
|
||||||
|
|
||||||
|
* The `heads()` revset function was split up into two functions. `heads()`
|
||||||
|
without arguments is now called `visible_heads()`. `heads()` with one argument
|
||||||
|
is unchanged.
|
||||||
|
|
||||||
### New features
|
### New features
|
||||||
|
|
||||||
* `jj git push --deleted` will remove all locally deleted branches from the remote.
|
* `jj git push --deleted` will remove all locally deleted branches from the remote.
|
||||||
|
|
|
@ -104,9 +104,8 @@ revsets (expressions) as arguments.
|
||||||
* `git_refs()`: All Git ref targets as of the last import. If a Git ref
|
* `git_refs()`: All Git ref targets as of the last import. If a Git ref
|
||||||
is in a conflicted state, all its possible targets are included.
|
is in a conflicted state, all its possible targets are included.
|
||||||
* `git_head()`: The Git `HEAD` target as of the last import.
|
* `git_head()`: The Git `HEAD` target as of the last import.
|
||||||
* `heads([x])`: Commits in `x` that are not ancestors of other commits in `x`.
|
* `visible_heads()`: All visible heads (same as `heads(all())`).
|
||||||
If `x` was not specified, it selects all visible heads (as if you had said
|
* `heads(x)`: Commits in `x` that are not ancestors of other commits in `x`.
|
||||||
`heads(all())`).
|
|
||||||
* `roots(x)`: Commits in `x` that are not descendants of other commits in `x`.
|
* `roots(x)`: Commits in `x` that are not descendants of other commits in `x`.
|
||||||
* `latest(x[, count])`: Latest `count` commits in `x`, based on committer
|
* `latest(x[, count])`: Latest `count` commits in `x`, based on committer
|
||||||
timestamp. The default `count` is 1.
|
timestamp. The default `count` is 1.
|
||||||
|
|
|
@ -627,7 +627,7 @@ impl<'index, 'heads> EvaluationContext<'index, 'heads> {
|
||||||
// but if it does, the heads set could be extended to include the commits
|
// but if it does, the heads set could be extended to include the commits
|
||||||
// (and `remote_branches()`) specified in the revset expression. Alternatively,
|
// (and `remote_branches()`) specified in the revset expression. Alternatively,
|
||||||
// some optimization rules could be removed, but that means `author(_) & x`
|
// some optimization rules could be removed, but that means `author(_) & x`
|
||||||
// would have to test `:heads() & x`.
|
// would have to test `:visble_heads() & x`.
|
||||||
let walk = self.composite_index.walk_revs(self.visible_heads, &[]);
|
let walk = self.composite_index.walk_revs(self.visible_heads, &[]);
|
||||||
Ok(Box::new(RevWalkRevset { walk }))
|
Ok(Box::new(RevWalkRevset { walk }))
|
||||||
}
|
}
|
||||||
|
|
|
@ -798,19 +798,19 @@ static BUILTIN_FUNCTION_MAP: Lazy<HashMap<&'static str, RevsetFunction>> = Lazy:
|
||||||
Ok(RevsetExpression::all())
|
Ok(RevsetExpression::all())
|
||||||
});
|
});
|
||||||
map.insert("heads", |name, arguments_pair, state| {
|
map.insert("heads", |name, arguments_pair, state| {
|
||||||
let ([], [opt_arg]) = expect_arguments(name, arguments_pair)?;
|
let arg = expect_one_argument(name, arguments_pair)?;
|
||||||
if let Some(arg) = opt_arg {
|
let candidates = parse_expression_rule(arg.into_inner(), state)?;
|
||||||
let candidates = parse_expression_rule(arg.into_inner(), state)?;
|
Ok(candidates.heads())
|
||||||
Ok(candidates.heads())
|
|
||||||
} else {
|
|
||||||
Ok(RevsetExpression::visible_heads())
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
map.insert("roots", |name, arguments_pair, state| {
|
map.insert("roots", |name, arguments_pair, state| {
|
||||||
let arg = expect_one_argument(name, arguments_pair)?;
|
let arg = expect_one_argument(name, arguments_pair)?;
|
||||||
let candidates = parse_expression_rule(arg.into_inner(), state)?;
|
let candidates = parse_expression_rule(arg.into_inner(), state)?;
|
||||||
Ok(candidates.roots())
|
Ok(candidates.roots())
|
||||||
});
|
});
|
||||||
|
map.insert("visible_heads", |name, arguments_pair, _state| {
|
||||||
|
expect_no_arguments(name, arguments_pair)?;
|
||||||
|
Ok(RevsetExpression::visible_heads())
|
||||||
|
});
|
||||||
map.insert("branches", |name, arguments_pair, state| {
|
map.insert("branches", |name, arguments_pair, state| {
|
||||||
let ([], [opt_arg]) = expect_arguments(name, arguments_pair)?;
|
let ([], [opt_arg]) = expect_arguments(name, arguments_pair)?;
|
||||||
let needle = if let Some(arg) = opt_arg {
|
let needle = if let Some(arg) = opt_arg {
|
||||||
|
@ -2046,7 +2046,7 @@ mod tests {
|
||||||
assert_eq!(parse("foo | -"), Err(RevsetParseErrorKind::SyntaxError));
|
assert_eq!(parse("foo | -"), Err(RevsetParseErrorKind::SyntaxError));
|
||||||
// Space is allowed around infix operators and function arguments
|
// Space is allowed around infix operators and function arguments
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(" description( arg1 ) ~ file( arg1 , arg2 ) ~ heads( ) "),
|
parse(" description( arg1 ) ~ file( arg1 , arg2 ) ~ visible_heads( ) "),
|
||||||
Ok(
|
Ok(
|
||||||
RevsetExpression::filter(RevsetFilterPredicate::Description("arg1".to_string()))
|
RevsetExpression::filter(RevsetFilterPredicate::Description("arg1".to_string()))
|
||||||
.minus(&RevsetExpression::filter(RevsetFilterPredicate::File(
|
.minus(&RevsetExpression::filter(RevsetFilterPredicate::File(
|
||||||
|
@ -2205,7 +2205,7 @@ mod tests {
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse("description(heads())"),
|
parse("description(visible_heads())"),
|
||||||
Err(RevsetParseErrorKind::InvalidFunctionArguments {
|
Err(RevsetParseErrorKind::InvalidFunctionArguments {
|
||||||
name: "description".to_string(),
|
name: "description".to_string(),
|
||||||
message: "Expected function argument of type string".to_string()
|
message: "Expected function argument of type string".to_string()
|
||||||
|
|
|
@ -600,10 +600,10 @@ fn test_evaluate_expression_heads(use_git: bool) {
|
||||||
vec![commit3.id().clone()]
|
vec![commit3.id().clone()]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Heads of all commits is the set of heads in the repo
|
// Heads of all commits is the set of visible heads in the repo
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
resolve_commit_ids(mut_repo, "heads(all())"),
|
resolve_commit_ids(mut_repo, "heads(all())"),
|
||||||
resolve_commit_ids(mut_repo, "heads()")
|
resolve_commit_ids(mut_repo, "visible_heads()")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1187,7 +1187,7 @@ fn test_evaluate_expression_visible_heads(use_git: bool) {
|
||||||
let commit3 = graph_builder.commit_with_parents(&[&commit1]);
|
let commit3 = graph_builder.commit_with_parents(&[&commit1]);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
resolve_commit_ids(mut_repo, "heads()"),
|
resolve_commit_ids(mut_repo, "visible_heads()"),
|
||||||
vec![commit3.id().clone(), commit2.id().clone()]
|
vec![commit3.id().clone(), commit2.id().clone()]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1626,7 +1626,7 @@ fn test_evaluate_expression_description(use_git: bool) {
|
||||||
);
|
);
|
||||||
// Searches only among candidates if specified
|
// Searches only among candidates if specified
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
resolve_commit_ids(mut_repo, "heads() & description(\"commit 2\")"),
|
resolve_commit_ids(mut_repo, "visible_heads() & description(\"commit 2\")"),
|
||||||
vec![]
|
vec![]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1692,7 +1692,7 @@ fn test_evaluate_expression_author(use_git: bool) {
|
||||||
);
|
);
|
||||||
// Searches only among candidates if specified
|
// Searches only among candidates if specified
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
resolve_commit_ids(mut_repo, "heads() & author(\"name2\")"),
|
resolve_commit_ids(mut_repo, "visible_heads() & author(\"name2\")"),
|
||||||
vec![]
|
vec![]
|
||||||
);
|
);
|
||||||
// Filter by union of pure predicate and set
|
// Filter by union of pure predicate and set
|
||||||
|
@ -1766,7 +1766,7 @@ fn test_evaluate_expression_committer(use_git: bool) {
|
||||||
);
|
);
|
||||||
// Searches only among candidates if specified
|
// Searches only among candidates if specified
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
resolve_commit_ids(mut_repo, "heads() & committer(\"name2\")"),
|
resolve_commit_ids(mut_repo, "visible_heads() & committer(\"name2\")"),
|
||||||
vec![]
|
vec![]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,7 +98,7 @@ fn test_bad_function_call() {
|
||||||
1 | heads(foo, bar)
|
1 | heads(foo, bar)
|
||||||
| ^------^
|
| ^------^
|
||||||
|
|
|
|
||||||
= Invalid arguments to revset function "heads": Expected 0 to 1 arguments
|
= Invalid arguments to revset function "heads": Expected 1 arguments
|
||||||
"###);
|
"###);
|
||||||
|
|
||||||
let stderr = test_env.jj_cmd_failure(&repo_path, &["log", "-r", "latest(a, not_an_integer)"]);
|
let stderr = test_env.jj_cmd_failure(&repo_path, &["log", "-r", "latest(a, not_an_integer)"]);
|
||||||
|
|
Loading…
Reference in a new issue