Note:
This page is primarily intended for developers of Mercurial.
Revset null/wdir Plan
How to handle null and wdir() in revset?
Contents
1. Status of revset functions
A list of revset functions and operators sorted by category.
(TODO: add current/expected behavior of wdir())
works as expected
not determined, but seems correct
not determined, but seems wrong or unsure
wrong
1.1. Set
- common set operation or intersection with computed set
should have no problem with null and wdir()
but several functions use None (= wdir()) for different meanings
Predicate |
null |
not x |
null: & !0:tip -> -1 |
|
null:0 & !null -> 0 |
x and y |
null:tip & null -> -1 |
x or y |
0 + null -> -1 |
x - y |
null:tip - 0: -> -1 |
all() |
null & all() -> () |
bundle() |
bundle won't have null |
first(set, [n]), limit(...) |
first(null:) -> () |
|
null: & first(null:) -> -1 |
hidden() |
null won't be hidden |
last(set, [n]) |
last(tip:null) -> () |
|
null: & last(tip:null) -> -1 |
outgoing([path]) |
null won't appear |
remote([id [,path]]) |
null won't appear |
reverse(set) |
reverse(null:0) -> 0, -1 |
1.2. Ancestor / Descendant
operation that interacts with DAG or revlog
wdir() can't live in it
null sometimes goes wrong because p2() = null
Predicate |
null |
x::y |
null::0 -> -1, 0 |
x^n, x^ |
0^1 -> -1 |
x^ |
0^ -> () |
x~n |
0~1 -> -1 |
ancestor(*changeset) |
ancestor(*roots) -> () |
|
ancestor(null) -> () |
|
null: & ancestor(*roots) -> -1 |
ancestors(set) |
ancestors(null:0) -> -1, 0 |
branchpoint() |
null & branchpoint() -> -1 |
children(set) |
children(null) -> roots |
descendants(set) |
descendants(null) -> * |
follow() |
null & follow() -> () |
follow(file) |
null should have no file |
heads(set) |
heads(null) -> -1 |
|
null: & heads(0) -> 0 |
merge() |
null & merge() -> () |
only(set, [set]) |
null won't appear |
p1([set]) |
p1(0) -> () |
|
null & p1(0) -> () |
p2([set]) |
p2(0) -> () |
parents([set]) |
parents(0) -> () |
|
null & parents(0) -> () |
roots(set) |
roots(null:0) -> -1, 0 |
1.3. Arithmetic
- integer comparison, increment or decrement
null should work, but wdir() can't because of None
Predicate |
null |
x:y |
null:0 -> -1, 0 |
max(set) |
max(null) -> () |
|
null: & max(null) -> -1 |
min(set) |
min(null) -> () |
|
null: & min(null) -> -1 |
sort(set[, [-]key...]) key=rev |
sort(0:null) -> -1, 0 |
1.4. Changectx attribute
filter by ctx attributes
should have no problem with null and wdir()
Predicate |
null |
author(string), user(string) |
null & author("") -> -1 |
closed() |
null won't be closed |
converted([id]) |
null won't be converted |
date(interval) |
null & date(-99999) -> -1 |
desc(string) |
null & desc("") -> -1 |
destination([set]) |
null won't be rebased |
extra(label, [value]) |
null & extra(branch, default) -> -1 |
grep(regex) |
null & grep("") -> -1 |
keyword(string) |
null & keyword("") -> -1 |
matching(revision [, field]) |
null & matching(null) -> -1 |
origin([set]) |
null won't be rebased |
sort(set[, [-]key...]) key!=rev |
sort(0:null, date) -> -1, 0 |
1.5. File status / manifest
filter by match, etc.
should have no problem with null and wdir()
Predicate |
null |
adds(pattern) |
null should have no file |
contains(pattern) |
|
file(pattern) |
|
modifies(pattern) |
|
removes(pattern) |
|
subrepo([pattern]) |
|
1.6. Misc revision data
- filter by miscellaneous data that requires a real revision
tend to crash by wdir()
Predicate |
null |
bisect(string) |
null won't appear |
bookmark([name]) |
null won't be bookmarked |
branch(string) |
null & branch(default) |
branch(set) |
branch(null) -> 0, ... |
bumped() |
null won't appear |
divergent() |
null won't appear |
draft() |
null should be public |
extinct() |
null won't appear |
filelog(pattern) |
null should have no file |
head() |
null & head() -> () in empty repo |
named(namespace) |
null won't be named |
obsolete() |
null won't be obsoleted |
public() |
null & public() -> -1 |
secret() |
null should be public |
tag([name]) |
null won't be tagged |
unstable() |
null won't appear |
1.7. Trivial identifier / wrapper
Predicate |
null |
id(string) |
id(000000000000) -> -1 |
present(set) |
present(null) -> -1 |
rev(number) |
rev(-1) -> -1 |
2. Status of commands
finished
partially implemented
not yet finished
(TODO: commands that should reject wdir(), subrepo, largefiles?)
Command |
Default |
wdir |
annotate |
p1 |
|
archive |
p1 |
|
cat |
p1 |
|
diff |
p1:wdir |
|
export |
p1 |
|
files |
wdir |
|
grep |
tip:0 |
|
identify |
wdir |
|
locate |
wdir |
|
log |
tip:0 |
|
parents |
wdir |
|
status |
wdir |
|
See also 0e41f110e69e
3. Expected behavior
General guidelines (from 4691)
null should not appear in the general case
- We need a simple and consitent rules for it to appear
- It must not be an implementation hell revset side
- It should be simple enough to support it when writing revset in extension
We want similar rules for wdir()
marmoute:
null should not survive combination (and) with anything.
1) The following include null in the result - "null" - "null + 2" - "null::" (probably) - "::null" (probably) 2) the following does not includes it - "null and (::2)" - "null and date(-9001)" - "null and all()" (replaces null by any of the variant in (1)) "all()" could maybe take and argument to accept null.
yuja:
null should work just like other revisions once appeared
- "null and (:2)" -> () # because :2 = 0:2 - "null and (::2)" -> (null,) - "null and date(-100000)" -> (null,) - "null and all()" -> () # if all() = 0:tip or (null) # if all() = everything in sets (like "and true") - "wdir() and draft()" -> (wdir,)
4. Possible use cases
(TODO: I don't have good example in mind)
hg log -Gr ":wdir() and branch(name)" to show DAG of the specified branch including working directory
hg log -r "wdir():0 and modifies(pattern)"
5. Possible implementation
how null and wdir() appear in set:
fullreposet allows us to populate a set containing null and wdir() only if specified (d2de20e1451f, backed out by e16456831516)
this magic should be disabled once fullreposet is evaluated
.filter() -> spanset().filter()
None is itchy:
map None to len(repo) or INT_MAX
always integer in set: repo[len(repo)] -> wctx, but wctx.rev() -> None
- use integer representation only in revset: wrap result by a proxy set
that converts between None and len(repo)
len(repo)
will allow us to handle wdir as contiguous revision
but it is likely to hide bugs
INT_MAX
is constant, which will cause less bugs
but it can't appear in spanset, will require more special cases
- changelog, rbc, etc.
null should be handled in the same way as regular revisions because changelog knows it.
but wdir() isn't. what should we do?
https://selenic.com/pipermail/mercurial-devel/2015-July/071768.html
ff... hash:
have to exist in base-16 trie (nodetree) so that short ff... hash can be resolved correctly.
but nodetree uses INT_MAX for nullrev.
6. See also
http://www.selenic.com/pipermail/mercurial-devel/2015-May/069744.html
https://selenic.com/pipermail/mercurial-devel/2015-June/071263.html