I just hate that Windows doesn’t care about case in file/folder names. Today I hate it very very much. I’ve spent hours and hours trying to get working Mercurial repository converted from Subversion repository.
It should be trivial thing to do. I’ve converted many other repositories without problems. And indeed I’ve been happily using the import I did couple of months ago. Then at Monday when I was traveling without network access I decided to do something I hadn’t do before with this repository: I wanted to do a new clone and develop with it. I expected it just works as Mercurial usually does. BUT cloning aborted with error message “abort: case-folding collision between FRHED/frhed.dsp and FRHED/FRHED.dsp“. WHAT??
Digging into history I noticed there is commit by Jochen (SVN rev 46) which renames FRHED/FRHED.dsp to FRHED/frhed.dsp. That looks so innocent change and indeed should not cause problems. But for some reason I haven’t yet figured out the FRHED.dsp is not really removed from the converted Mercurial repository. So now when I try to update the working copy (clone, update etc) there are two similar filenames (as Windows sees them).
I expect this is two-fold problem. First the Subversion doesn’t do real renames for the files, but it does copy + delete for the file. And then (I suspect) hgsvn doesn’t detect the rename correctly as the filename doesn’t change (from Windows point of view).
There is a page in Mercurial wiki about fixing case collisions. I’ve tried many variations of that. It basically works as it creates repository I can clone. But as the “fixing” commit is naturally the last commit in the repository it doesn’t help with the problem unable to update working copy to earlier revision. I’m afraid I have to live with this restriction.
Out of interest I’m also trying Mercurial Queues to edit the history and remove the FRHED.dsp file after the rename. In hope I can get a fully working repository.
Yes, I know. Editing the version control history is bad idea. You simply should not do it. Especially with distributed version control system like Mercurial. Mercurial wiki has a good page about this.
But I want to experiment this (I’m sure I learn a lot about Mercurial in the course). So far it seems it can be done, but it requires hand-editing many revisions. And indeed I just realized I tried to do it wrong way around.. Whoops.
The principle here is MQ exports the history as set of patches. Then the patches can be edited, reordered, removed etc. And applied back to the repository after the changes. My idea is to remove the commit that renamed the file (so the original FRHED.dsp filename remains untouched). And then edit further patches so that they edit FRHED.dsp file instead of frhed.dsp.
As I said above I already started doing this wrong way – I removed the rename commit and started editing patches so that they edit the frhed.dsp file instead of FRHED.dsp. But the problem is of course that if I remove the commit, there never will be frhed.dsp file… Doh.
After some more experiments I’m stuck with new problem. Edited patches don’t apply cleanly and at the moment I’m still wondering why. I mean, the patches don’t apply for files whose diffs I don’t edit in patch files. If I just remove hunks for editing FRHED.dsp why hunks for heksedit.dsp fail… This is a bit weird. But I’m new with this MQ stuff so perhaps I just did something wrong. I need to learn more about MQ.
But I’ll leave that for tomorrow. I’m still positive I can get working repository out of this.
Update: After several attempts I finally managed to fix the Mercurial repository.
Things got wrong in SVN rev 46 (as mentioned above). The hgsvn conversion script records rename of FRHED/FRHED.dsp to FRHED/frhed.dsp as copying of FRHED/FRHED.dsp to FRHED/frhed.dsp. So it won’t remove original file, just creates a new copy with new name. Which only differs by case and causes Windows to not see it as two different files.
And then things go totally wrong in conversion. The script generated diffs that made same changes to both FRHED/FRHED.dsp and FRHED/frhed.dsp files. Which in addition to all other problems also caused the patches to fail to apply by hand (as the first change already applied the change and second was then invalid).
Anyway, the working solution I found was to convert the faulty revision to real rename. I did this with MQ (see above). I reverted the revision 46 (SVN) and replaced it with real (Mercurial) rename of FRHED/FRHED.dsp to FRHED/frhed.dsp. Next problem was there were set of patches referring to now inexisting file. Simple solution was to do a search in files for FRHED.dsp for the patch files and remove all changes to that file. Once I had fixed the patch set I simply re-applied it to repository.
And the end result is the FRHED.dsp file disappeared. And I have exactly the repository I wanted.
I’m not sure how to avoid this kind of problem in the future. Best would be to avoid this kind of renames. But if somebody does the rename then there is no way to really backout it from Subversion repository. So sometimes manual fixing is needed. Luckily I now know how to do it in few minutes.
The exact procedure is:
- convert the SVN repository to Mercurial using hgsvn
- CD to Mercurial repository
- initialize MQ: hg qinit
- export history to patches, including the faulty revision: hg qimport -r FAULTY:tip
- apply the faulty patch: hg qpop - copies FRHED/FRHED.dsp as FRHED/frhed.dsp, but nothing happens in the filesystem
- fix the result: hg mv FRHED/FRHED.dsp FRHED/temp.dsp; hg mv FRHED/temp.dsp FRHED/frhed.dsp – this results in Mercurial seeing real rename. We must use temp as filename as intermediate step.
- tell MQ that the patch was modified: hg qrefresh
- edit patch set in .hg/patches folder and remove references from all patches to FRHED/FRHED.dsp file
- apply the fixed patch set: hg qpush -a
- delete the patch queue: hg qdelete -r qbase:qtip
- Now we have fixed Mercurial repository