View Ticket
Ticket Hash: 74413366fe5067b3de2ee80567f15d432c7ea58d
Title: Bad behaviour merging with renames
Status: Open Type: Code_Defect
Severity: Critical Priority:
Subsystem: Resolution: Fixed
Last Modified: 2011-10-12 16:23:50
Version Found In: [79b7902cdd]
We hit a case when a rename DELETED some files that where in P, V and M!

After an investigation, we tracked the problem:

  • Merge calls "find_filename_changes(between p and m)"
  • find_filename_changes calls bisect_shortest_path( directOnly )

We think that if we change the find_filename_changes() so bisect_shortest_path gets called with "directOnly=false", it solves all our problems.

But we don't know further consequences from this. We need this problem fixed. drh, as you implemented all this, could you tell us if this is the change to do?

I will attach the patch that removes the directOnly on find_filename_changes.

anonymous claiming to be viric added on 2011-01-04 09:21:03 UTC:
The first line of the report should read: "We hit a case when a *merge* DELETED some files that where in P, V and M".

anonymous claiming to be viric added on 2011-01-04 09:53:45 UTC:
A diagram to understand the situation:

     ^  \____
     |   ____[M]   (the merge from P added B)
     | _/     |
    [P]       |
     |        |
[rn A to B ]  |
     |        |
[create A  ]  |
     |        |
     |    __[ . ]
     |   /
[   root   ]

So, looking at renames between P and M (with merges) does not have any rename in the way. But if we get the shortest path without merges (direct only), through root, there appears a rename "from B to A" (the reverse of the checkin).

This rename makes the merge fail.

anonymous claiming to be viric added on 2011-01-04 11:04:35 UTC:
Here is the script that helps reproducing the problem. Notice that it needs fossil fixed by the patch I proposed in [c9d454153e], otherwise it fails to reproduce the problem (not that it works; simply it misses commits when merging):

fossil new a.fossil
mkdir a 
cd a
fossil open ../a.fossil
touch b
fossil add b
sleep 1
fossil commit -b b -m xxxb
fossil update trunk
touch a
fossil add a
sleep 1
fossil commit -m xxxa
fossil mv a c
mv a c
sleep 1
fossil commit -m xxxac
fossil update b
fossil merge trunk
sleep 1
fossil commit -m merge
fossil update trunk

After this:

$ fossil merge b
"fossil undo" is available to undo changes to the working checkout.

It should *not* delete C.

Notice that without the patch in [c9d454153e], fossil merge fails to see the rename at all, and will do the merge ignoring the checkin with the rename in trunk.

anonymous claiming to be viric added on 2011-01-04 14:40:04 UTC:
After seeing the change in [ff2a87103b], we see a situation where the onlyDirect affects. I don't know if it is a big trouble or if the situation can be improved.

Consider this graph:

 |  \
 |  _[M]
 | /  |
[P]   |
 |  _[rename]
 | /   
[ ]

With the long trip (directOnly), the merge from M to V looks like a RENAME. With the short trip, it looks like ADDED/DELETE.

What do you think?

anonymous claiming to be viric added on 2011-01-05 11:36:12 UTC:
I reopen, to grab attention on the previous comment.

viriketo added on 2011-10-12 16:23:50 UTC:
It may be fixed by [0b93b0f958].