Hi Christopher,

Le 22 oct. 2011 à 14:31, Christopher Armstrong a écrit :

> On 20/10/2011, at 20:46 PM, Quentin Mathé wrote:
> 
>>> Sounds like we're on the same page – now I think I understand commit 
>>> tracks; so it is in fact a different idea than nested versioning.
>>> 
>>> If I understand commit tracks correctly, it has the effect of giving each 
>>> persistent root its own history graph, and for each persistent root, you 
>>> can easily move a "pointer" which marks the current state of that 
>>> persistent root. It sounds like a great idea to me (now I think the idea I 
>>> was experimenting with in COHistoryTrack, where normal undo/redo would be 
>>> implemented as selective undo, would end up being  a mess.)
>> 
>> That's how I understand commit tracks at least :-)
> 
> That sounds right. Additionally, the pointer has a history, which allows the 
> undo/redo bit. It is close but not the same as the concept of a branch when 
> you allow more than one commit track on the same persistent root, but I 
> haven't allowed that in the implementation yet. It is closest to the idea of 
> a "branch with history", where we know what the branch has looked like in the 
> past, but we still have a full history graph of the object under branching. 
> The history of each branch will look different, but the object history will 
> be the same for every branch.

ok. Sounds like another good way to explain it.

>>> I'll give some more details on nested versioning..
>>> 
>>>>> From what I have understood, the main interest is to support undoing 
>>>>> arbitrary branch operations such as deletion, switch or merge cleanly and 
>>>>> in a transparent way for the user.
>>> 
>>> That is one motivation; but my main motivation is to better handle 
>>> composite documents (at least, that's what I hope it does.)
>>> 
>>> My motivating example is a composite document called "outer" containing 
>>> another document, "inner". The pair could be a paper and a figure in the 
>>> paper, or a photo library and a photo, etc.
>>> 
>>> With the ObjectMerging model you have to make a choice between
>>> 
>>> a) make the inner document a normal object inside a persistent root.. this 
>>> means you forfeit native versioning support for the inner document. You 
>>> can't easily present the user with undo/redo controls for the inner 
>>> document, without resorting to using selective undo. You could still view a 
>>> history graph of the inner document by taking the persistent root's history 
>>> graph and filtering out nodes that don't affect the inner document, and 
>>> then selectively undo changes affecting the inner document. You can't 
>>> really maintain multiple branches of the inner document. On the positive 
>>> side, when you make a change like reverting, tagging, or branching the 
>>> outer document, the inner document is also affected.
>>> 
>>> or
>>> 
>>> b) make both the inner document and the outer document persistent roots. 
>>> This gives full versioning/branching/undo/redo support to both the outer 
>>> and inner document, but the problem is, the link to the inner document from 
>>> the outer document is now a weak reference by UUID, so the outer document 
>>> no longer owns the inner one, and tagging/branching/reverting the outer 
>>> document has no effect on the inner document. If the user wants to record 
>>> the state of the outer document including the inner one, he has to write 
>>> down the version number of both the outer and inner document. 
>>> 
>>> IMHO, neither of these options is very good, although a) is closer.
>>> 
>>> With nested versioning, the inner document can be a persistent root with 
>>> full, native versioning support (branch/tag/undo/redo), but it can be 
>>> nested inside the outer document, so branch/tag/undo/redo on the outer 
>>> document also affect the inner document.
>>> 
>>> As far as I'm aware, no one has done this in an organized way before, 
>>> although you could always do it ad-hoc, like using the versioning feature 
>>> in an OpenOffice.org Writer document and storing the file inside git or 
>>> another version control system.
>> 
>> b) seems good enough to begin with. I'm not entirely convinced that 
>> branching the outer document should branch the inner document automatically, 
>> although there are use cases where that's the best choice.
>> 
>> For example… For a page layout, I wouldn't want the inner documents to be 
>> branched, I just expect them to be in their more recent states. For a 
>> photomontage, getting the inner pictures/photos branched would be 
>> convenient, to ensure the overall composition look won't change in 
>> unexpected ways, no matter what I try on the inner elements (and I can 
>> manually bring them to their more recent states if I want to).
> 
> I think that branching in the second case is not always necessary, but it 
> should probably still be possible. As I outlined in my previous email, an 
> option was to hold an object at a revision, but still have it track the 
> branch and allow it to be updated manually. I think embedding it completely 
> (i.e. coping the whole object in as an embedded object), at least in the case 
> of a photo montage is not good, as it would consume alot more resources.

I agree about branching being not always necessary in the second case.

For embedding it completely, this only makes sense with Nested Versioning I 
suppose. From what I have understood, Nested Versioning would implement 
embedding as branching, the store would create cheap copies (or branches) when 
a root object is copied.

> Perhaps allowing the user to branch later from the current revision would be 
> better, when they know they want to branch?

Yes, I have doubts about any automatic branching scenario that doesn't involve 
an explicit user request to enable it.

> But this leads to the complexity that Eric identifies before, and I don't 
> think its easily solved.

Right.

> Maybe allow branches to be marked "private" to a document so that don't show 
> up in searches? I think the part about explicitly marking embedded root 
> objects is really important here.

Marking some branches as private sounds good to me.

> One of the things I want to avoid is "hierarchies" of root objects, which may 
> exist with nested versioning and make the whole thing really complicated. I 
> think trying to keep the object model as flat as possible is important to 
> keeping it usable.

I agree. Keeping the object model as flat as possible is important, since we 
have we'll also have COGroup to organize core objects but in a way that doesn't 
create hiearchies or nesting, although at the UI level it might appear to do 
so. I'm giving this example to outline the fact we should try to mimize the 
organization or nesting models we use to keep things obvious at the user level.

This puts aside, I think Nested Versioning doesn't necessarily imply the 
nesting of the root objects, I'd envision it more as a possible branching 
policy valid inside a compound document.

Another point worth to mention is the fact that almost no users will use 
branching I think. Let's suppose Étoilé ends up with the same audience than Mac 
OS X or Windows. I doubt that more than 5 or 10 % of the users will ever use 
the branching ability. For these users, it's going to be a very important 
feature though. 
My doubts about automatic branching are based on the troubles I get into when I 
try to explain branching to people with various computer experience levels. I 
get replies such as "why making copies is not good enough to work on document 
variations". If I explain you cannot merge the changes, the reply might be 
"merging changes would be nice but I'm not interested in this 'branch' concept. 
I just want to create copies and merge changes." 
I now think this informal approach to branching might be a better way to expose 
the users to it without too much mental burden. This makes me realize the 
important thing is the "merging" support rather than the "branching", and 
branches and copies should really be equivalent. 
For users who knows about branches and wants to organize things cleanly, we 
could provide some UI that exposes the branch concept and the possibility to 
turn copies into branches or vice-versa. This would act as a thin organization 
layer that remains optional.

>> For ObjectMerging, we could use a special ref marker rather than a plain 
>> UUID to represent references between root objects. 
>> 
>> A ref marker could include an optional branch UUID. Since a branch has a 
>> head, the ref marker would implicitly point to a specific root object 
>> version. If there is no optional branch UUID, the (inner document) current 
>> branch is picked. With this model, we could also automatically branch inner 
>> documents in a way similar to what you suggest above… 
>> For example, on branching the outer document, all the inner documents are 
>> branched. These "nested" branches would be private, in the sense they 
>> wouldn't be listed at the UI level among the branches of each root object 
>> (well, unless you request it). We could eventually use the outer document 
>> UUID as the inner document branch UUID, not sure it's a good idea though.
>> 
>> Rather than serializing a custom reference object, we could still use a 
>> plain UUID by generating a new UUID that represents a core object UUID + 
>> branch UUID pair, and a database table to store the mapping. I'm not sure 
>> it's a good idea either, because it would make the debugging less easy and 
>> much harder to interpret core objects exported as plists.
> 
> I don't think its a big conceptual burden for debugging, but yes, it does 
> make things more difficult.
> 
> The main problem I forsee is the need for COEditingContext to allow multiple 
> copies of the same object in the same context *at different revisions* at the 
> same time. It doesn't seem entirely unreasonable to want a copy of the same 
> object in the same document but at different revisions.

I gave some more thoughts about this problem. My current conclusion is we 
should merge notions such branches and root objects at the storage level (more 
or less your commit log idea I think). I mean that a branch creation would 
result in a new core object (that implies a new UUID). In this model, creating 
a new branch, copy or root object is the same.

We would have a main HistoryUnits (or HistorySequences or a better name) table 
that lists both branch and root object UUIDs, then a table HistoryRelations to 
memorize how public and private branches and copies are related to root 
objects. There might be some ways to improve this model, but at least this 
gives a basic idea and it seems very close to commit tracks to me.

For COEditingContext without making the current implementation more complex, we 
can then easily have the "same" root objects at various revisions at the same 
time, new entries in HistoryUnits and HistoryRelations table would make 
possible to support that.
A public branch would be a branch exposed to the user and a private branch 
would be an object accessed as a particular revision (but without a branch from 
the user viewpoint).
A branch public or private, a root object and root object copy would all 
correspond to the same 'history unit' construct at the store level.

What do you think?

Cheers,
Quentin.


_______________________________________________
Etoile-dev mailing list
[email protected]
https://mail.gna.org/listinfo/etoile-dev

Reply via email to