The logic and reason behind error message TF14087
Today I want to talk about an error message that some of you might have encountered which generates a lot of confusion with our users (clearly this is our fault since error messages are supposed to help and not make you run and call product support). Even I must admit that when first seeing the message it was hard to put together not only what it meant but also what to do to resolve the issue.
The message in scrutiny is: TF14087: Cannot undelete “%0- insert your file name here” because not all of the deletion is being undeleted.
This message is obtained when you are performing a merge operation, but what really causes it? Well to answer that question let me frame you the scenario:
a. User creates a folder $/main -main also contains a lot of files underneath
b. User branches $/main to $/test and then branches $/test to $/production -typical promotion model
c. User performs merges between these branches and everything is working ok
d. For some reason and this is the important part the user deletes $/test; something had gone terribly wrong or they now decided they did not needed it.
e. After the deletion the user goes and branches again $/main again to $/test - now you have a $test active and a $/test deleted
f. User performs a merge between $/main and $/test and this works so they continue
g. During the development process someone renames a file in $/test - imagine foo.cs being renamed to bar.cs
h. User performs the merge and gets this error message and has no idea why.
Ok, I know those were a lot of steps and it can get confusing so let’s summarize pretty quickly how you would get this message.
a. A given source folder needs to have a merge relationship between a folder that is deleted and a folder that is not deleted with both of those folders having the same name. In our example the folder with the same name are $/test
b. A file in the active target folder is renamed
c. A merge from the source ($/main) to the target ($/test) is executed
With the scenario understood lets walk through some of the logic and explain what the message is telling the user (refer above for the message text).
When computing the merge we look at the paths being merged, we called these from and to and after getting these paths we then look at the debit and credit history in order to assemble the list of candidates changes to merge- this assumes a catch up merge for simplicity. In this example, when looking at the paths we match both the deleted and the active $/test folders so we think we are merging to both of these locations. This is not really the problem, since in our code we have logic that removes the deleted paths if an active one with the same name exists at that location. That code walks the contents of the folder and performs the filtering and this all works fine until a file in the target folder has been renamed. If a file has been renamed we now have $/test/foo in deleted space and $/test/bar in the non-deleted space and they do not match, hence $/test/bar does not get filtered out and it remains in the files to merge.
As merge continues another block of code looks at this and says: the user wants to merge into a deleted file so undelete the file in order to accomplish this. Well the deleted file was deleted when a folder was deleted so undelete the folder $/test as well. Now you can see what is going to happen next, we are trying to delete a folder but another folder with the same name already exists at that location. Bingo- namespace conflict!
The rest is then history, the error is caught and we display that very helpful message :) "cannot undelete filename because not all of the deletion is being undeleted" … where all of the deletion refers to the top level folder in this case $/test.
My own personal opinion is that this is a bug and we are going to revamp our logic to be able to account for this scenario and not get our users into this state. So hang in there while we solve it, and as far as a workaround, well just rename the $/test folder to another location and everything should be happy.