[darcs-users] Data loss bug when renaming and replacing a non standard token?

Dan Pascu dan at ag-projects.com
Sun Mar 22 20:55:37 UTC 2009


On Sunday 22 March 2009, Ashley Moran wrote:
> Hi
>
> One of my clients stumbled across a very specific set of operations
> that cause data loss.  Fortunately it was really minor (a few lines),
> but very suprising behaviour.  It happens when pulling a patch that
> renames a file AND replaces a token with the token chars '[%r/]'.
> Darcs says there is a conflict, but does not create a backup file with
> the existing data.
>
> Is this is a bug, or are we abusing `darcs replace`?  (Or both?)

It seems that this happens if you do not have an external-merge option 
defined in ~/.darcs/defaults or you do not specify one on the command 
line, but use --mark-conflicts (or don't use any ---xxx-conflicts).
I tried your example with the following entry in ~/.darcs/defaults and 
this time it opened kdiff3 and merged the local change and allowed me to 
also adjust it before saving it:

ALL external-merge kdiff3 --output %o %a %1 %2

For who is interested in more detail in debugging this, I made a short 
analysis of what happens in various cases. Both darcs 1.0.9 and 2.2.0 
exhibit the same behavior, so the problem is not new to darcs2. The tests 
use a darcs v1 repository when testing darcs-1.0.9 and a darcs v2 
repository when testing darcs-2.2.0. Here are the results:

1. No --external-merge is used or defined in defaults

1.1 --allow-conflicts will have the following result:

$ cat testdata 
Given %r/I have a file%r/ do
end
$ darcs whatsnew
replace ./testdata [%r/] / %r/
$

1.2 --mark-conflicts will have the following result:

$ cat testdata 
Given /I have a file/ do
end
$ darcs whatsnew
No changes!
$

1.3 --dont-allow-conflicts will refuse the apply the patch

2. With external-merge defined in ~/.darcs/defaults as:

   ALL external-merge kdiff3 --output %o %a %1 %2

2.1 If I do not save the merge result from kdiff3, then the output is like 
in case 1.1 (with --allow-conflicts):

$ cat testdata 
Given %r/I have a file%r/ do
end
$ darcs whatsnew
replace ./testdata [%r/] / %r/
$

2.2 If I save the merged result from kdiff3, then I get the following 
result:

2.2.1 Using darcs-2.2.0

$ ls
_darcs  testdata  testdata.orig
$ cat testdata
Given /I have a file/ do
end
Given %r/something else/ do
end
$ cat testdata.orig 
Given %r/I have a file%r/ do
end
$ darcs whatsnew
replace ./testdata [%r/] / %r/
hunk ./testdata 1
-Given %r/I have a file%r/ do
+Given /I have a file/ do
+end
+Given %r/something else/ do
addfile ./testdata.orig
hunk ./testdata.orig 1
+Given %r/I have a file%r/ do
+end
$

2.2.2 With darcs-1.0.9

$ ls
_darcs  testdata
$ cat testdata
Given /I have a file/ do
end
Given %r/something else/ do
end
$ darcs whatsnew
{
replace ./testdata [%r/] / %r/
hunk ./testdata 1
-Given %r/I have a file%r/ do
+Given /I have a file/ do
+end
+Given %r/something else/ do
}
$ 

Now, when using --xxx-conflicts it seems pretty clear what is happening, 
but there are 2 questions:

1. Why --allow-conflicts has a reversed replaced applied to working copy?
2. Why both --allow-conflicts and --mark-conflicts have removed the 
unrecorded lines.

With --external-merge defined there are more questions though:

1. If external-merge is defined in defaults, --xxx-conflicts are 
completely ignored. I believe the external merger should not be used if I 
explicitly indicate on the command line --dont-allow-conflicts. I'm not 
sure what should happen with --allow-conflicts.

2. Even though there was a replace patch that changed '%r/' to '/', in the 
merged result, the lines that were added but not yet recorded in repo2, 
still contain %r/. I was under the impression that a replace patch is 
useful exactly for these situations as it will combine with the changes 
that may have still added the old token on the receiving side and change 
those entries to the new token as well. But here we see that the newly 
added lines kept the original token and were not affected by the replace 
patch. Is this expected behavior, and if so what is the usefulness of a 
replace patch if it doesn't do more than a find/replace in the editor 
does? At least the documentation explained this expected behavior for the 
replace patch and use it a a reason why the replace patch is better than 
a find/replace in the editor.

3. With darcs-2.2.0, it seems that an .orig file was left in the working 
directory and also automatically added to the repository.

In these tests I used the commands bellow, the only difference is that I 
tried them with 2 versions of darcs, and used the --xxx-conflicts 
and --external-merge options explicitly to see what happens in each case.

Hope this helps to debug the problems.

>
> Replication steps below.
>
> Thanks
> Ashley
>
>
> % mkdir repo1
> % cd repo1
> % darcs init
>
> % cat >testfile <<END
> Given %r/I have a file/ do
> end
> END
> % darcs record -alm "Add testfile"
>
> % cd ..
> % darcs get repo1 repo2
>
> % cat >>testfile <<END
> Given %r/something else/ do
> end
> END
>
> % cd ../repo1
> % darcs mv testfile testdata
> % darcs replace --force --token-chars '[%r/]' '%r/' '/' testdata
> % darcs record -am "Rename testfile and replace a symbol"
>
> % cd ../repo2
>
> % cat testfile
> Given %r/I have a file/ do
> end
> Given %r/something else/ do
> end
>
> % darcs pull -a
> Pulling from "/Users/ashleymoran/Documents/Development/work/darcs/
> repo1"...
> We have conflicts in the following files:
> ./testdata
> Finished pulling and applying.
>
> % cat testdata
> Given /I have a file/ do
> end
>
> % ls
> _darcs		testdata



-- 
Dan


More information about the darcs-users mailing list