#pragma section-numbers 2 <> = Revset null/wdir Plan = How to handle `null` and `wdir()` in revset? <> == 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 * {X} wrong === 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(...)` || {X} `first(null:) -> ()` || || || (./) `null: & first(null:) -> -1` || ||`hidden()` || (./) null won't be hidden || ||`last(set, [n])` || {X} `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` || === Ancestor / Descendant === * operation that interacts with DAG or `revlog` * `wdir()` can't live in it * `null` sometimes goes wrong because `p2() = null` * Issue:4905 ||'''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) -> ()` || || || {X} `ancestor(null) -> ()` || || || (./) `null: & ancestor(*roots) -> -1` || ||`ancestors(set)` || (./) `ancestors(null:0) -> -1, 0` || ||`branchpoint()` || {X} `null & branchpoint() -> -1` || ||`children(set)` || (./) `children(null) -> roots` || ||`descendants(set)` || {X} `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` || === 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)` || {X} `max(null) -> ()` || || || (./) `null: & max(null) -> -1` || ||`min(set)` || {X} `min(null) -> ()` || || || (./) `null: & min(null) -> -1` || ||`sort(set[, [-]key...])` key=rev || (./) `sort(0:null) -> -1, 0` || === 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` || === 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])` || (./) || === 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 || === Trivial identifier / wrapper === ||'''Predicate''' ||'''null''' || ||`id(string)` || (./) `id(000000000000) -> -1` || ||`present(set)` || (./) `present(null) -> -1` || ||`rev(number)` || (./) `rev(-1) -> -1` || == Status of commands == * (./) finished * /!\ partially implemented * {X} not yet finished (TODO: commands that should reject `wdir()`, subrepo, largefiles?) ||'''Command''' ||'''Default''' ||'''wdir''' || ||`annotate` ||`p1` || (./) || ||`archive` ||`p1` || (./) Cset:3ec8351fa6ed || ||`cat` ||`p1` || /!\ || ||`diff` ||`p1:wdir` || /!\ || ||`export` ||`p1` || /!\ Issue:5438 || ||`files` ||`wdir` || (./) || ||`grep` ||`tip:0` || {X} || ||`identify` ||`wdir` || (./) || ||`locate` ||`wdir` || (./) || ||`log` ||`tip:0` || (./) || ||`parents` ||`wdir` || (./) || ||`status` ||`wdir` || (./) || See also Cset:0e41f110e69e == Expected behavior == General guidelines (from Issue: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,) }}} == 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)"` == Possible implementation == how `null` and `wdir()` appear in set: * `fullreposet` allows us to populate a set containing `null` and `wdir()` only if specified (Cset:d2de20e1451f, backed out by Cset:e16456831516) * this magic should be disabled once `fullreposet` is evaluated * `.filter() -> spanset().filter()` `None` is itchy: * map `None` to `len(repo)` or `INT_MAX` a. always integer in set: `repo[len(repo)] -> wctx`, but `wctx.rev() -> None` a. 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 * {o} but it is likely to hide bugs * `INT_MAX` * {*} is constant, which will cause less bugs * {o} 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`. == See also == * http://www.selenic.com/pipermail/mercurial-devel/2015-May/069744.html * https://selenic.com/pipermail/mercurial-devel/2015-June/071263.html ---- CategoryDeveloper CategoryNewFeatures