[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: [RFC] v2 Tree conflict resolver spec.

From: Neels J Hofmeyr <neels_at_elego.de>
Date: Fri, 19 Feb 2010 00:15:33 +0100

Daniel Näslund wrote:
> Hi Neels!
> Thanks for all your feedback! The use of the libsvn_wc terms BASE,
> WORKING and ACTUAL will be replaced by your suggested (or was it
> Julians?) checked-in state and checked-out state in the next version of
> the RFC.

Hey father man :)

I'd like to make sure that these terms are clear. The way you wrote
"checked-in" sounds to me like something quite different than intended
(should be "going to check in" or "going to be checked in").

The "going to check in" or short check-in state as Julian and I started
calling it is a local edit or schedule that is going to be checked into the
repos with the next commit.

"Check*ed*-in" sounds like it is already committed ("already checked in")...

The checked-out state (note that this one has the 'ed') is all the
unmodified data we have in the WC, that could be gotten from a clean
checkout. "...it is checked out".

Hmm, I wish we had more clarity around terms. Having written this, I don't
think check-in is such a good choice anymore -- with the English language's
subtleties of future/past tense involved.

"BASE" has also been overloaded with -- in some situations -- starkly
different meanings.

What was that naming we suggested for the WC-NG storage trees once?

Quoting from
[Greg replying to Julian replying to Neels]

On Fri, Jan 29, 2010 at 06:59, Julian Foad <julianfoad_at_btopenworld.com> wrote:
> Neels J Hofmeyr wrote:
>> I'd call them the Unchanged tree, the Schedule tree, and the Actual tree.
>> And just to be wild, I'd not make them all-caps ;)
> For the first, "Unchanged" could be OK, although since we talk about
> changes so often it might be ambiguous in more contexts than some other
> words would be. ("If the Actual version is unchanged ...", "If the
> Unchanged version has changed ...") "Original" or "Repository" or
> "Checked out" might be better. "Base" might be OK if we decide that's
> what the meaning of the user-level "Base" concept should be.

I have no particular interest in ensuring the names line up, but I
definitely don't want to use the same name when it means something
else to our users.

"Repository" is troublesome because you might be talking about the
server-side trees. "Original", "Checked out", or "Pristine" seem okay.

> For the second, "Schedule" is a bad idea because it has strong and
> specific meanings in WC-1. Greg suggested "Restructured" which sounds
> perfect.
> For the third, "Actual" is fine.

Too busy to respond in depth here, but just had a thought: how about
"Edits" to replace the "Actual" name?

(Let me just say that the current BASE-tree will not be called "Pristine".
We should absolutely *not* call it that. We already have the PRISTINE table,
and a pristine is *linked to* from a BASE, not *is* a BASE.)

> Find further comments inline.
> On Tue, Feb 09, 2010 at 03:20:57PM +0100, Neels J Hofmeyr wrote:
>> Daniel Näslund wrote:
>>> Design spec for tree conflict resolution in the commandline client
>>> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> The hard part is figuring out what state the wc is in during the
>>> different user cases.
>> Actually, wc-ng should make that part easy. The hard part is making the
>> conflict resolution conform with adjacent WC states. (attention, high degree
>> of meta language. No need to understand me :P )
> After a read through of last weeks discussions on pristine and base, the
> hard part is probably to understand what the terminology actually means! :)

I shouldn't have started philosophizing about hard parts, heh. No hard
feelings ;)

> [...]
>>> Contents
>>> =========
>>> Problem definition
>>> Requirements
>>> Terminology
>>> Use cases update/switch
>>> Use cases merge
>>> API changes
>>> User interface
>>> Problem definition
>>> =========================
>>> Users are having problems understanding how to resolve tree conflicts.
>>> For some operations they may not know how to get back to a previous
>>> state. They don't always know how to view the changes causing a
>>> conflict.
>> Agreed!! :)
> The spec has really been about resolving conflicts and defining the
> states of the wc. We haven't touched on methods for viewing the changes.
> A diff is good for a text conflict but of limited value for displaying a
> tree conflict. More on that later.


>>> Requirements
>>> =====================
>>> It should be easy for the user to understand why the conflict has
>>> happened and how to resolv it.
>> +1!!
>>> Update, switch and merge should be reversible. That is; going back to
>>> the former revision in the wc should restore the contents to the
>>> original.
>> Need some finer grain here: "going back"?
>> 'svn revert' should be able to undo all local changes, be they from merge or
>> manually inflicted. After 'revert', any tree-conflict should be gone, and
>> the node should reflect a state achievable with 'svn checkout'.
>> We could have a desire to revert only the last steps of current
>> modifications (i.e. only revert the last three merges that I did on top of a
>> locally modified file, the last of which caused a tree-conflict) -- but this
>> enters a scope far beyond tree conflict resolution. It would surely be nice
>> nevertheless, and it might be implemented by layers of THEIRS information...
>> in a different RFC.
>>> The resolver should not handle moves since we have no way to track
>>> those. When I say handle moves I mean "do something about the other end
>>> not affected by this conflict". We will apply give the option to apply
>>> changes elswehere and do renames but we will leave some files behind for
>>> the user to clean up.
>> (on the long run, with editor v2, we may be able to track moves
>> satisfactorily. We might want to design this future behavior now so we can
>> prepare for it and don't get ourselves in a big mess later.)
> Noted. My idea so far has been to substitute detection functionality by
> editor-v2 with input from the user, e.g. the user has the responsibility
> to detect moves and copies. When we have editor-v2, those parts should
> be easily replaced.

Yes, seen that. Now I'm thinking it is better to work on editor-v2 instead
of introducing user interaction that asks the user to supply other paths
(public API work, soon obsolete, but needs to be maintained).

>>> ### There should be a good way to view what has caused a conflict.
>>> ### Perhaps some info from 'svn info'.
>> Currently, 'svn info' on a tree-conflicted node says something like
>> [[[
>> Tree conflict: local edit, incoming delete upon merge.
>> Source left: (kind) URL_at_rev
>> Source right: (kind) URL_at_rev
>> ]]]
>> Are you saying that there should be more info? Which in particular?
> I'm talking about the options given when running the interactive tree
> conflict resolver (In case you thought I meant adding more info to svn
> info). If I got a tree conflict running without the resolver I would
> want to know :
> * What is the content of theirs? A dir listing or file content.
> * what is the content of mine? A dir listing or file content.

A diff/delta info should be enough? Like, not full listings, but only which
paths vanished and appeared, type of thing (same with file content, which is
already like that for the current interactive text resolution).

> * Was the target copied [#]?
> * Was the target moved? [#]
> * If the target was copied or moved in theirs, where did it get
> copied/moved from? We can't tell this automatically (until you know
> what...) but we can help the user make a pretty good guess.

I believe the copy_from info in the repos (aka svn_fs_history_prev()) is
able to convey where the file came from. No idea why we aren't using that
yet... Oh right, because the code that reports what happened in the repos
needs editor-v2 to be able to communicate this info to the code that takes
the actions and flags the conflicts. :)

> * For merges, we probably would want to check the svn:mergeinfo in some
> cases.
> [#] I have a weak understanding of the copy-from and moved_here
> concepts. As I understand it, we can detect locally moved or copied
> targets. We can't tell what has happened on the server side but we know
> what has happened locally.
> To exemplify: For a locally copied, incoming move of the file alpha2 I would do
> something like this:

you mean copied-here vs. moved-here (add vs. add)?

> [[[
> svn st -> shows me a local add, incoming add upon update TC on alpha2
> svn info alpha2 -> shows that alpha2 was locally copied from alpha
> svn info ^/trunk/alpha2 -> shows me
> svn log -v ^/trunk/alpha2 -> shows that alpha2 was moved from alpha in r2
> ]]]
> If I was dealing with a TC on a dir I could get some additional
> information with svn ls -R ^/trunk/dir.
> In the end it boils down to: 1) We need a way to show the structural
> changes to the user in a better way than a diff. 2) We need a way to
> help the user decide on what has happened during a copy or move. The
> problem lies in the nature of commandline program. It doesn't cope that
> well with interactively. Are we expecting the user to have another
> terminal open and run those commands there?
> If I was doing a resolver for Subclipse I would present a graph
> illustrating the changes in two file trees. It would look so _good_. I
> could start writing something to graphically represent the changes in
> two trees for the commandline client but text mode is text mode.
> (Although git log --graph is a useful thing and the standalone tree
> command is useful too). Just thinking out loud here.

Hm, yes. We are wading deep into huge complexity with tree-conflict
resolution. What use is a circular-move-resolver design when the user has no
good way of recognizing a circular move?

I think you're right that the best way to help the user understand would be
to go graphical. But that in itself is complex enough. Can you figure it out?

I'm not sure if we should actually have a user interaction that will open an
image viewer on a jpeg produced by the svn client binary -- but maybe when
*thinking* about graphical representation we can find an easier way... What
kinds of figures would exist? Can they be broken down into simple highly
repetitive shapes? Also just thinking aloud :)

>>> The tree conflict resolver interface should be consistent with the
>>> existing resolver. It should provide
>>> {postpone,theirs,mine,diff}-options.
>> :s/\(theirs\|mine\)/&-tree,&-tree/g ?
>> Whatever, there's much more detail further below.
>>> ### The user should be able to run the conflict resolver at any time.
>>> ### We have to fix libsvn_wc/conflicts.c first. Not really
>>> ### specific to this feature.
>> As far as I've understood, we should teach 'svn resolve --accept=*' to do
>> interactive tree-conflict resolution. Is there anything blocking that?
> Bert told me on IRC (slightly rewritten):
> <@Bert> dannas: Currently we don't store all the information available
> in the interactive conflict resolver for future use E.g. In the
> interactive conflict resolver for properties you have the older, left
> and right values (actual value).. but once postponed you just have a
> textfile containing a list of information that might have been modified
> or which might be in- or overcomplete My idea is to commit the conflict
> to the working copy before running the interactive resolver (including
> all the data now not stored yet).. and then run the resolver on the WC.
> And then continue. A 'svn resolve' invocation can then just re-use that
> code path. Currently we sometimes run the interactive resolver on a
> half modified working copy. And then use the result of the resolver to
> complete it in one way or antoher

I wasn't aware of this problem (until recently), and with tree-conflicts, we
are already heading in the desirable direction: Store all necessary info on
the conflict in the WC and don't lose that on 'postpone'.

>>> Terminology
>>> ============
>>> In this document, WORKING means the user's version, which possibly has
>>> text, property and/or tree modifications relative to the BASE; it does
>>> not mean the WC-NG database concept that is known as WORKING.
>> argh, well, ok...
>> IMHO it would be better not to overload the word "WORKING" in this RFC...
>> Below, when I say 'BASE tree' or 'WORKING tree', I mean the wc-ng metadata
>> store. When I say 'actual WC file system' I mean those files editable by the
>> user in her working copy, not the metadata.
>> (Hm, I don't say that much about props though, expect some remarks about
>> props to be missing below.)
> Too bad, I had hoped that BASE, WORKING and ACTUAL could be used at this
> abstraction level too. I saw you suggestions in the cheat sheet about
> using checked-in state and checked-out state. I'll think about it some
> more and probably come to the conclusion that those terms works. :)

Well, yes, but IMHO you were mixing them up. For example, you used BASE
referencing the source-right of a merge... currently, the "BASE tree" is
that SQLite table that remembers what the WC has checked out. The
commandline "@base" keyword reflects the pristine version of what is going
to be checked-in, which confusingly often means the same. But invariably,
'BASE' is always relative to the current WC. At least that is invariable :)

>>> Use cases update/switch
>>> ========================
> [...]
>>> Local add, incoming add
>>> -------------------------
>>> THEIRS: Put new BASE file/dir in WORKING.
>> What should happen here is that the incoming add is pulled into the BASE
>> tree node, while the wc-ng WORKING tree node still reflects the local add,
>> and the file in the actual WC file system stays unchanged. So, the local
>> status becomes 'replaced', and a 'revert' would remove the WORKING tree node
>> and change the actual WC file to the pristine contents of its BASE tree
>> node, so that the WC looks as if no local add had ever happened, and as if
>> the incoming add was completed successfully.
>>> MINE: Keep current WORKING file/dir.
>> Yes. Only remove the conflict marker, nothing else to be done.
>>> Move WORKING file/dir to <user-suggest>. Replace WORKING
>>> file/dir with the BASE-TARGET file/dir.
>> Oh you mean the user gives her added node a different name to avoid the
>> conflict ... makes sense
>> Schedule a local add at <user-suggest> with the current actual WC content of
>> 'this' path, then revert 'this' path, leaving behind the result of the
>> incoming add (in the BASE tree), and updating the actual WC filesystem to
>> the BASE tree node's pristine contents.
>>> MERGE Merge BASE file1 onto WORKING file2.
>> <groan> ;)
>> Hey, wait a minute, you said "Use cases update/switch" above. What *about*
>> merge with update/switch??
>> Oh you mean, this is what happens when the user says --accept=merge... ok
>>> If any copyfrom info is present (i.e. at least one of the files
>>> was copied), the user needs to select a copyfrom source:
>>> WORKING file | BASE file | Options
>>> --------------------------------------
>>> has copyfrom | has copyfrom |
>> ---------------------------------------
>>> Yes Yes Pick one copyfrom of 2, or none.
>>> Yes No Use WORKING copyfrom, or none.
>>> No Yes Use BASE copyfrom, or none.
>> So the user has to *always* choose which history/copyfrom she wants to keep
>> attached to the node. Good, haven't thought of that yet :)
> As I was saying earlier, I don't really understand copyfrom. Can we have
> copyfrom information on a BASE file (or checked-out file to use your
> suggested terminology) without editor-v2? The checked-out file has no
> local modifications so the copy could only have happened on an incoming
> revision and we can't track copies and moves on those, right?

The copy_from is a pointer of one node to the path_at_rev where it came from.
It's basically an arrow backwards, to be saved in the repos. For example,
when doing 'svn copy ^/trunk_at_REV ^/new_branch', the repos points
new_branch's prev_history to trunk_at_REV.
Now, doing that in the WC 'svn copy trunk new_branch', the WC WORKING-tree
node for new_branch notes a copy_from of ^/trunk_at_base. When next committing,
the copy_from becomes the history saved in the repos, making new_branch
point to ^/trunk_at_what-was-base. (That's e.g. for 'svn log', going backwards,
to be able to continue showing the modification history regardless of path
When having copy_from in the WC metadata, it is mostly to remember such a
backwards arrow to be committed to the repos.

We don't have copy_to information in the repos.

From looking at all the copy_from information in the repos, we can figure
out which operations the user actually carried out. But we can only go
backwards ... we can tell that an added node was copied from somewhere, then
we can tell that that other somewhere was removed in the same revision, and
derive a move. That's really horrible to have to do that everywhere, in
update, merge, diff etc..

Editor v2 acknowledges that we are actually interested in getting this info
easily. It provides an API that is able to communicate a move, replace, etc.
to the receiving end of the editor -- so this is much more "how our code
communicates" than "what the repos stores". For example, some places in the
code already know that something is a 'replace', but they are forced (by
editor-v1) to send a separate delete and then a separate add. The receiving
code then has to fumble them back together if it is interested in replaces
(cache all deletes, and then try to match adds with deletes). Editor-v2
acknowledges that replaces *are* interesting, over and above getting the
individual adds and deletes. "We" weren't anticipating that when writing

Back to the WC:
A BASE-tree node / checked-out state has no "copy_from", because it does not
need to commit anything to the repos. The checked-out stuff's history is in
the repos. "copy_from" is stored in the WORKING-tree node /
going-to-check-in state, only when you do an 'svn copy/move' to here (to the
node's path). Note that the WORKING node does not know where it was copied
or moved to, either. Some other tree node will commit that.

For example, if a 'move' is coming in, then the history of that incoming
move is already saved in the repos, no need to write that to the WORKING
node or something.

BASE, WORKING etc. are the states before and after an operation. Editor-v2
communicates that *operation* (more clearly than editor-v1). The end driving
editor-v2 will still need to do some figuring-out to send the proper ops.
But at least the receiving end of editor-v2 doesn't have to painfully match
things up anymore (with far less leverage on available information than the
driving end).

>>> Local del, incoming del
>>> -------------------------
>>> THEIRS: Nothing to do.
>>> MINE: Nothing to do.
>> Yes. When the user says --accept=theirs/mine, nothing needs to be done
>> except removing the conflict marker.
>>> RENAME: Merge BASE-TARGET <moved>
>>> onto WORKING <moved>.
>>> ### We need the user to tell us there was a rename until
>>> ### editor-v2 is here. Until then <moved> must be a user
>>> ### suggestion.
>> I think this needs another table that lists combos of 'locally moved' or not
>> vs. 'incoming move' or not.
> yeah.
>>> Local del, incoming edit
>>> -------------------------
>>> THEIRS: Replace the deleted WORKING file/dir with edited BASE file/dir.
>>> MINE: Keep current WORKING file/dir.
>> You mean locally schedule the node for deletion.
> Yes.
>> (comment from the future:)
>>> Merge BASE file/dir onto WORKING <user-suggest>.
>>> ### editor-v2 will automatically find a move. No need for this
>>> ### option then?
>> There will still be a tree-conflict reported, and the user should have the
>> option of applying the incoming edit to where she moved the local file. Need
>> this option. (but IMHO give it a better name)
>>> ### stsp: I hope to get the local move case working
>>> ### automatically before 1.7 release
>> Weey! :D How're ya gonna do that? Iterate all local adds and see if they
>> have copy_from info? Introduce copied_to info?

Actually, sure, we can get this info when crawling, and even from a nice db
query once the wc.db is one-per-WC (and not one-per-dir).

>>> Local edit, incoming del
>>> --------------------------
>>> THEIRS: Delete the file/dir from WORKING and ACTUAL.
>> Hey!! Now you're changing your terminology! That's not fair!
>> To clarify: remove all nodes from all trees including the actual working
>> copy file system. The file is now officially gone. (no status, no need to
>> commit for the delete to take effect)
> Perhaps this is wrong. We should just do scheduling. It's up to the user
> to do the final decision to remove the physical file.

When resolving to THEIRS, the user is *making* that decision. But, right, as
with 'svn delete --keep-local', we should probably have a way to leave the
locally edited version around... Yet another --accept option??

>>> MINE: Keep current WORKING file/dir.
>> The BASE tree node has been removed by the update that flagged the tree
>> conflict. Create a WORKING tree node, i.e. schedule the file as locally
>> added! The repos thinks this node is deleted, so we need to re-add it at the
>> next commit.
> Or keep the scheduled file as locally added. It's been re-added before
> we run the resolver.

Right, before starting to resolve, the node is already in locally-added
state and marked conflicted. The tree-conflict *flagging* code must arrange
the BASE/WORKING-tree nodes to reflect the proper schedule for MINE.

>>> Schedule BASE add-half for addition. Merge WORKING file/dir to
>>> add-half. (Must be suggested by user. We can't track add-halfs
>>> right now.
>> Maybe rather --accept=THEIR-RENAME?
> The names of the options is totally open for suggestions.

I don't feel too strongly about that either ... yet.

>> The add part of "their" rename has been recorded in the BASE tree (at the
>> move-target path) by the update that flagged the tree conflict -- it is now
>> known as officially existent. Simply modify the file in the actual WC file
>> system, i.e. schedule the file *modified*.
> Doh, my mistake.
> Update/switch was the easy part, now it's time for merge.

Merge is almost always a real shocker... oxygen masks ready.

>>> Use cases merge
>>> =======================
>>> ### julianf wrote: How can we most easily implement an extension of "svn
>>> ### merge" that achieves a copyfrom-history-sensitive diff (between WC
>>> ### items) rather than an unaware diff?
>> Like, before editor-v2? o_O
>> General note: the wc-ng BASE tree is never modified by merge, nor by tree
>> conflicts during merge. The conflict, as with uptch [1], exists entirely as
>> local mods/schedules, and a 'revert' should clear that completely.
>> Also, a tree-conflict during merge *should not* alter any other tree, be it
>> the WORKING tree or the actual WC file system; it should only flag a
>> conflict that notes which delta wanted to come in -- the pristine store will
>> be helpful to make resolving this to THEIRS a non-repository action.

Alarm bells ringing: I have figured out that we can forget fully storing
THEIRS in a merge-TC and thus we can forget resolving to THEIRS without
contacting the repos again. We could only remember what parameters the merge
operation had and re-trigger the same merge. The pristines would be able to
store the fulltexts of some revisions, but the merge operation still has to
do all its figuring out which nodes existed in which revisions as normal.

The simplest proof is to point out that the second, third, fifteenth merge
ranges may also cause tree-conflicts each. Can't store THEIRS for
completely-offline resolution! :(

> I'm watching the evolution of the pristine store spec with interest. :)

The pristine store is really sweet, I love it :)
It'll do a much better job than the explicit text-base files per node.

>> Resolving to MINE then is always achieved by just removing the conflict
>> marker and leaving the local state unchanged by the merge. (note, this so
>> far stands for tree-conflicts only)
>> [1] uptch = update/switch ;)
>> invented that last night... not one of the greatest genius inventions, I
>> know. More like a comic relief ;)
>>> Local add, incoming add
>>> -------------------------
>>> THEIRS: Replace WORKING with BASE. Merge START to END into WORKING.
>> What do you mean by 'BASE'? I presume the final content and props (within
>> the given merge range) of the incoming add.
> Yes, that was what I meant.

(This is where I meant the terms get mixed up)

>> Schedule as locally added (the previous local add is discarded, now we want
>> their local add).
> So we must revert the previous local add? I'm assuming we can find that
> target with our current API:s.

Not sure what you mean?

>>> MINE: Keep current WORKING file/dir.
>> see 'Resolving to MINE...' above.
>>> Move WORKING file/dir to <user-suggest>. Merge START to END into
>> Yes.
>> Using my words, I'd say "schedule the local add at path <user-suggested>,
>> remove local add schedule at this path and then carry out the merge's add
>> normally". Same thing.
>>> Local del, incoming del
>>> -------------------------
>>> THEIRS: Nothing to do.
>>> MINE: Nothing to do.
>>> MERGE START to END from THEIRS <user-suggest> into WORKING
>>> <user-suggest>.
>>> ### This will be handled automatically when we can handle moves.
>> Again, we can have "local del is/isn't part of move", "incoming del is/isn't
>> part of a move" plus the more special case "both are part of a move to the
>> same path" (which should not result in a tree conflict once detected).
>> ("both are not part of a move" should not result in a tree conflict once
>> detected, either.)
>>> Local del, incoming edit
>>> -------------------------
>> No add! Discard the local add, i.e. discard the WORKING tree node,
>> 'exposing' the current BASE tree node. Then carry out the merge's edit as usual.
>>> MINE: Nothing to do.
>> Yes.
>>> Merge WORKING add-half onto THEIRS file/dir. Copy THEIRS to
>>> WORKING delete-half.
>> Grief! THEIRS wants to edit 'this' path. Locally, 'this' path has gone
>> elsewhere. I'd call this case MERGE-HERE or something.
>> Keep local text and prop modifications, but bring these local mods back to
>> 'this' path. Then, merge THEIR edit onto the local mods, stepping into the
>> realm of text/prop conflicts.
>>> ### This is in case of a move with mods. The user would have to
>>> ### supply the path to the add-half. Editor-v2 will resolve this
>>> ### automatically.
>> ...will supply the path automatically, but the user still has to say how to
>> resolve it.
>>> Merge THEIRS file/dir onto WORKING add-half.
>>> ### The add-half would have to be supplied by the user.
>> 'This' node has been moved to a different path. Apply THEIR edit to the
>> other part, entering the realm of text/prop conflicts.
>> hmm, prext conflicts? lol
>>> Locale edit, incoming del
>>> --------------------------
>>> THEIRS: Remove WORKING file/dir.
>> Keep the BASE tree node, as always, and schedule as locally deleted.
>>> MINE: Nothing to do.
>> Yes.
>>> RENAME1: Merge START to END from THEIRS add-half onto WORKING.
>> THEIR delete is part of a move, possibly with prext mods. argh! prop and
>> text mods. Don't carry out THEIR move, but apply those prext mods to 'this'
>> path, entering realm of prext conflicts.
>>> RENAME2: Merge START to END from WORKING file/dir onto THEIRS add-half.
>> THEIR delete is part of a move, possibly with prext mods. Carry out THEIR
>> move, but apply local prext mods to the move-target path, entering realm of
>> prext conflicts.
>> Schedule 'this' path locally deleted, and schedule the move-target path
>> locally added, which contains THEIR edits merged onto the local edits.
>> Gee, what if THEIR move-target path is also locally added!?

And this remains open, see also the large <future> tag in the TC-cheatsheet
I posted, and the thread discussing that. Hey, reminds me of wanting to
commit that to notes/... (at least the top section)



Received on 2010-02-19 00:16:18 CET

This is an archived mail posted to the Subversion Dev mailing list.