On Thu, Sep 03, 2009 at 12:01:02PM +0100, Bolstridge, Andrew wrote:
> I have a situation where I think there's a bug in the tree conflict
> detection code. I've tested this (using Tortoise) and have the steps to
> reproduce it.
> The bug appears to be around deleted files within a directory, if I have
> 2 directories and delete the same file in each, then try to merge, I get
> a tree conflict error reported on the un-deleted file.
> Create 2 directories projA and projB, each contain test1.txt and
> test2.txt. Commit both projects.
> Delete test2.txt from both directories. Commit.
> Edit test1.txt in projA only. Commit.
I don't think the edit is necessary to trigger this.
> Merge (all) changes from projA to projB - you'd expect the changes in
> test1.txt to be copied to projB without problem, however, I get a tree
> conflict error instead. There is no mention in the dialog about the 2
> deleted files.
> Now this is a simple test case to reproduce the problem as best as I
> can. I know I am merging all revisions, as there is no mergeinfo in the
> projects yet, but I've seen this error in more complex situations where
> the same deletion has occurred in 2 projects at different times, but
> still need to be merged together. I usually get round that by picking
> revisions to merge, but that's time consuming and it's something I'd
> want the system to handle better.
> I assume here that when merging the revision where test2.txt was
> deleted, it fails to delete that file in the target directory as its
> already been deleted. I would expect that this should be a silent
> 'failure' (and the same applies when merging in a new file that's
> already present) as the merge operation is correct - after all's done,
> the directory needs to be the same as the merge source, which it is even
> if the merging didn't do the deletion itself.
> Incidentally, I think this is the single most common cause of tree
> conflicts in our org, if this didn't throw up a tree conflict, I doubt
> we'd ever see one again. Does anyone have an comment on this, is it a
> bug or a limitation in the merge/conflict routines?
It is a limitation in the way Subversion implements moves.
*Any* delete vs. delete tree conflict is a false positive.
Now, why do we have false positives? Who would inflict something
this stupid upon their users? The problem is really rooted in a design
decision made way back when Subversion was in its infancy.
Subversion implements a move as copy+delete. So when you run
"svn move a b" (or do the equivalent in Tortoise), the client
internally does the equivalent of:
svn copy a b
svn remove a
Also note that a "copy" really is an "addition with history" which
means it is an "addition with copyfrom information".
So when the move gets committed, the client tells the server two things:
1) Please add 'b', and its copyfrom info is 'from a_at_rev'.
2) Please delete 'a'.
That's all the server ever gets to know. Basically, the information that
there was a move is thrown out the window by the client before it even
talks to the server.
Now, the server could probably still guess that there was a rename if
you comitted 1) and 2) within the same revision. Usually people do this,
but svn does not enforce it. But even then it does not always work out,
e.g. what if you did this:
svn copy a b
svn copy a c
svn remove a
Which of the copies was a rename now? We can't tell this apart from:
svn copy a b
svn move a c
svn copy a c
svn move a b
which are clearly different situations when checking for tree conflicts.
Another problem is that, when you merge the move into another branch,
the server tells the client two things:
1) Please delete 'a'.
2) Please add 'b', and its copyfrom info is 'from a_at_rev'.
1) happens before 2), so during 1) the client has no way of telling whether
the delete is related to the add, because the add is still about to happen.
Now, you might think that it should be possible to work around this
limitation somehow. I thought long about working around this, before
1.6.0 was released. There's a problem with keeping state reliably in case
users abort the merge half-way through. For more detail about this see the
section called "TREE CONFLICT DETECTION WITH TRUE RENAMES" in this file:
So, in your case, the two deletions of the same file in ProjA and ProjB
cause a tree conflict because one or both of them could have been a move.
I know this is fairly stupid, and probably the biggest limitation in
the way tree conflicts are handled in 1.6.x. However, it *was* a
concious design decision, because there is currently no other way to
reliably flag move vs. move and move vs. delete tree conflicts.
Tree conflicts are just warnings. They are a way of Subversion to ask
for human assistance. If you see a delete vs. delete conflict, check
the history and make sure both sides wanted the file deleted.
Provided that both sides really ran "svn remove" on the file,
just mark the tree conflict as resolved and you are done.
> Certainly, the error that is reported to the user at the end of the
> merge operation needs some work, I do not have a tree conflict on
> test1.txt, the parent directory maybe, and I should be told what the
> tree conflict is - in this case, that test2.txt was deleted.
I don't know about the Tortoise UI, but the svn command line
client can tell you this. It does not tell you at the end of the
merge operation as you expected. You need to run 'svn status' to
find out more. It should show something like:
! C test2.txt
> local delete, incoming delete upon merge
'svn info' also provides additional information if run on a
tree-conflicted item. Try it out.
But yes, it needs much more work. If you can provide developer resources,
please point them our way.
Improvements to the user interface are welcome. There's an item
for this on our task list, for interested contributers to pick up:
As part of the working copy library rewrite which is happening on trunk
right now (and which is taking up most of our developer resources),
we hope to start fixing the problems with the current move implementation,
at least partly. The new working copy meta data will properly represent moves.
So we can, at least in the working copy, tell whether a file was deleted
or whether it was moved.
But that solves only part of the problem. It helps in the case where a
merge sends a textual edit for a file which was moved locally, but not
in the case where the merge sends a delete. Until the server can tell
the client that something was moved rather then deleted, there is no way
to merge renames from one branch to another without causing a tree conflict.
There is a lot of work left to do before this problem can really be fixed,
and our team is fairly small so progress is not as quick as we would like.
Let's say we'll have this feature maybe in 1.8, or 1.9, or 1.10...
Sorry for the inconvenience. I hope you still value the fact that we're
at least trying to flag potential problems during a merge, so that if
people *really* make conflicting changes and try to merge them, we do
catch that. With 1.5.x, you could end up losing changes in certain
situations, so from a reliability point of view, the 1.6.x behaviour
is, while much more annoying, more correct and safe.
In general, while Subversion has a lot of positive aspects, some weak spots
due to the initial design goal of Subversion, replacing CVS with something
better than CVS, still shine through in cases like these.
It's certainly better than CVS because CVS could not move things at all.
But it's far from perfect. And today's requirements certainly go way beyond
a "better CVS". But getting from a "better CVS" to something marginally good
is a lot of work, and it takes time.
To unsubscribe from this discussion, e-mail: [users-unsubscribe_at_subversion.tigris.org].
Received on 2009-09-03 14:54:35 CEST