monotone-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Monotone-devel] Updated Issue 209 - support drop/modified conflict


From: Markus Wanner
Subject: Re: [Monotone-devel] Updated Issue 209 - support drop/modified conflict
Date: Fri, 08 Jun 2012 14:24:48 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:10.0.4) Gecko/20120510 Icedove/10.0.4

Hi,

On 06/08/2012 12:04 AM, Stephen Leake wrote:
> I don't see this as a valid use case; can you elaborate?
> 
> Hmm. I can imaging having win32 and unix support in the parent, and
> dropping win32 in the child.

Yeah, sounds like an example. Did you really never see the warning and
just ignore it, because you know you want the file deleted?

> My prefered solution for that case would be to split the project into
> five (or more) projects; win32 support, unix support, common
> project; release project 1 contains common, unix, and win32; release
> project two contains common and unix.

Now assume the parent project is not under your control. Your preferred
solution is to split the project into different branches and you want to
do that in your fork. In the win32 branch, you certainly don't ever want
the unix files. And vice versa. You delete them. And you are cento
percento sicuro you don't ever want to see them again.

The parent project continues as it did before. You want to propagate
their changes to your fork. Every modification from the parent project
will currently invoke the warning about the modification not being
visible in your sub-project, because of the files you deleted.

> But it's easier to use directories and build directives to achieve that
> result, so I'm back to thinking this is not a valid use case.

Here, you need to elaborate. How can directories and build directives be
a replacement for a thing as simple as a file deletion.

Also keep in mind that - as currently often adviced - you could move
your files to an attic directory instead of deleting. The move doesn't
emit the same warning a delete does. And it remains persistent, in the
sense that the file won't ever move back. However, that's clearly a hack
around die-die-die already. I think it's properly reasonable for the
user to wish these files to vanish from their checkouts.

> Assuming for the moment it is a valid use case, one way to handle it is
> to put an attribute on the file (in the parent branch) that indicates it
> is permanently deleted in the child branch, and have the conflict
> detection code honor that attribute.
> 
> That is a mechanism that allows the user to inform mtn about their
> considered resolution to the on-going conflict.

Well, it's a bit hard to put an attribute on a deleted file...  And no,
requiring to put it on the parent branch is not a option (because you
might not be in control of it, see above example).

> Another way would be to put some option (like --no-dropped-modified, or
> perhaps "--resolve-dropped-modified <file> drop") in the workspace
> options file for the child branch. Not as good as an attribute, because
> it's not in the database.

Full ACK. I'd like to add: it should not only be something in the
database, but something that can be synchronized between databases. So
multiple users don't have to repeat that decision.

> Note that file suture is no help in this case.

Agreed.

Proper file resurrection could be, though. At least when thinking of
deleted files as "moved to some unreachable place, contents intact".
There once was such a proposal for tracking (and properly merging) a
files liveliness.

>> Ultimately, it turns out that there are two distinct ways to think of a
>> delete. My way of looking at it is that a delete - just like a rename -
>> is just a change to how the file's content can be reached. It doesn't
>> change it nor does it conflict with modifications thereof. An un-delete
>> will simply make that file visible, again - possibly including merged
>> stuff. Let's call that variant A).
> 
> I've never thought of it that way.

You better start thinking of it that way. Note for example, that the
path of a file is just one of the properties of a "file" (node) in
monotone, which gets mark-merged separately from its contents, AFAIUI.
(Please, anybody, correct me if I'm wrong here).

(I read through your suture documentation and noticed you trapped into
the same fallacy of trying to identify files by their file names. IMO
sutures must not depend on file names. Instead, it should well be
possible to suture two files with different paths).

> Delete changes the file from "can be reached" to "can't be reached".
> Rename changes the file from "can be reached via path A" to "can be
> reached via path B".
> 
> If the file contains C code, and other C code depends on it, the
> delete will be noticed at build time.
> 
> Rename would also be noticed at build time, but it is easy to make
> additional changes to restore consistency: fix the 'include' statements,
> or the makefile list of object file names.
> 
> Restoring consistency in the delete case would mean bigger changes.
> 
> If nothing else in the project depends on the deleted file, so neither
> delete nor rename (nor modify, for that matter) would be noticed,
> perhaps it should be in a different project (as with win32 above).

Monotone doesn't care about "project consistency". It manages trees of
files over their livetime. And files happen to come and go in the
lifetime of a project.

Think of the example above of splitting an existing project into unix,
win32 and common sub-branches, again. You'd pretty certainly have to
make changes to your Makefile as well to do that split, yes. OTOH maybe
you could simply require them to be checked out as:

  ./         checkout of branch for "current"
  ./win32/   checkout of branch for "win32"
  ./unix/    checkout of branch for "unix"

If that matches the layout of the parent project, nothing else would
have to be changed. And "consistency" (as seen from the compiler) is
maintained, even though there are tons of deletes for monotone.

>> The other way of thinking of a delete is that it also truncates the
>> file's contents, which is a modification of the file's contents and
>> certainly conflicts with other modifications. The user might then expect
>> an un-delete to restore the exact contents of the file as it was just
>> before the delete. Let's call that variant B).
> 
> That's been my model.

Yeah, I understand that now. I'm glad we reached the point of seeing and
hopefully understanding each others model.

>> We could allow a single revision to "patch" a file to zero length before
>> deleting it. Therefore store the users wish for that delete to conflict
>> with modifications of the file. In such a case, monotone should clearly
>> raise a merge conflict against modifications of that file.
> 
> I don't understand this.

Well, at the moment, monotone doesn't care if you modify the file's
contents to zero length before the delete. It simply drops that
modification and records a file deletion in the revision.

Instead of adding an attribute, we could allow monotone to store a patch
(trucation) prior to deletion (in the same revision). However, that
requires the user to decide on a delete type (conflict resolution) at
the time of the commit, which I dislike.

In principle, I like the attribute approach better. However, there's the
technical difficulty of being unable to store attributes on deleted files.

(Also note that during the liveliness tracking and merging discussion,
Nathaniel brought up the example of OpenEmbedded, who happens to create
and delete lots of files in their process. So that if monotone never
really deletes a file, but keeps it in its manifest with an "invisible"
attribute or some such, the overhead from deleted files would soon
surpass the amount of data for live files).

>> However, I'm concerned about how to expose these two kinds of deletes to
>> the user. I don't expect the average user to be able to understand the
>> difference. Certainly not at the point in time of the delete. Maybe at
>> the point in time of a merge (which currently emits the warning).
> 
> Perhaps my attribute proposal above would work?
> 
>> Maybe, the user even wants different revisions to merge differently for
>> the same deleted file. So it's not a property of the delete, but... of
>> what else?
> 
> I don't know :).

I think we agree that it's a decision the user shouldn't have to make at
commit (of the delete) time. But monotone should rather ask the user
what to do the first time there's a choice (i.e. a conflict).

It just occurs to me that this resembles the case of copying files. For
a user, it's just copying a file. However, afterward, there are two
options on how to merge modifications to "copied" files, which I've seen
referred to as "symmetrical" and "asymmetrical" copy: either the merge
only adjusts the original file (asym), leaving the copy as is. Or it
could duplicate that modification as well and apply the modification to
both files as part of the merge. There exist valid use cases for both
variants. My point for this discussion is: I think that's another case
where the user has a better chance of understanding the effects of his
decision when asked at the time of the merge (instead of at commit time).

Complicating things, I don't think it's a file specific decision. Maybe
there exist use cases where you want to ignore modifications from the
parent project, but at least want to see a warning, or even better a
real conflict, if somebody else from your project tried to modify the
file "before" seeing your deletion.

My gut feeling is that such decisions should be stored per branch. I.e.
assuming branches "parent" and "child", a file "foo" existing in
"parent" and propagated to "child", but then deleted there. Once a
conflict with a modification of "foo" in "parent" arises, the user can
choose to:

 - keep ignoring modifications from branch "parent" to file "foo"
 - continue to get conflicts for mods from branch "parent" to file "foo"

and once we have proper resurrection:
 - resurrect file "foo", including the modification(s)


Given that such a preference only needs to be stored in case of a real
conflict, I think storing an attribute might not hurt too much. After
all, it would even be possible to remove such "merge preference
attributes" once you no longer need them.

I'd simply store these as attributes of the root node and let them
reference a file name. (Which would get more complicated to track in the
face of renames on the parent branch, but well...)

Thank you for reading this far, you've now made it. ;-)

Comments?

Regards

Markus Wanner



reply via email to

[Prev in Thread] Current Thread [Next in Thread]