Suppose we use these options with an expression that matches more than
one patch. For instance:
> darcs initialize
> touch a1 a2
> darcs record -la a1 -m 'a1'
> darcs record -la a2 -m 'a2'
Then do
> darcs log --from-patch a
This lists only 'a2'.
> darcs log --to-patch a
This lists both 'a1' and 'a2'.
I expected --from-patch and --to-patch to work symmetrically: either
darcs log --from-patch a -> a2
darcs log --to-patch a -> a1
or
darcs log --from-patch a -> a1,a2
darcs log --to-patch a -> a1,a2
These expectations are certainly biased by my math-oriented brain. What
actually happens is that --from-match and --to-match select patches no
earlier than and no later than the *last* patch (in repo order) that is
matched by the given expression.
What about other commands? Here is what happens with diff:
darcs diff --to-patch a -> nothing
darcs diff --from-patch a -> a2
darcs diff --from-patch a --to-patch a -> a2
I think the idea here is that the reference point is the working state,
unless both --from-xxx and --to-xxx are given. So that --to-xxx alone
always gives the empty selection. The other two cases are similar to the
ones for log.
One more example:
darcs rebase unsuspend --to-patch 'a' -> a1
Here it seems we select patches up to the /first/ matching patch.
If one applies the right mental model, these behaviors aren't too
surprising. One merely needs to think of how matching is implemented: we
start at the recorded state, searching for the first match. For log and
diff this means we go backward, for rebase unsuspend it means we go forward.
Is there a way to define the semantics of these options declaratively
i.e. without recourse to operational details? Preferably such that the
same rules apply for all commands?
Alternatively: should we /change/ the rules so that they do have a
simple declarative specification that is valid for all commands?
Possibly at the cost of efficiency?
Here is one possible spec:
"--from-match e" selects the sequence of patches that start with the
earliest one that matches "e".
"--to-match e" selects the sequence of patches that end with the latest
one that matches "e".
In both cases, this implies that nothing is selected if there is no
patch that matches "e". It also implies that any patches selected by
--match "e" are included in both --from-match "e" and --to-match "e".
What about usability? The current behavior is geared towards operations
near the recorded state. That makes sense, in a way. I may not care that
there are patches in ancient history that also match what I give to
--from-match. However, the initial example shows that this can lead to
(at least to me) surprising results.
The more I think about this, the more I come to the conclusion that a
consistent, simple, declarative spec is the best way to get predictable
results, which (IMO) is a preerequisite for using these options with
confidence. If the user wants to exclude ancient history, she can use
--last=50 or --from-tag "." as additional constraints. This requires
that we fix matching so that arbitrary combinations are allowed and
treated as if they were combined with "and", which has been on my list
anyway.
BTW, unrecord and obliterate already have an implicit --from-tag "."
(roughly speaking; in fact they stop searching when they hit the latest
/clean/ tag).
|