[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