Bug 3648 - case folding collision with a changeset removing a directory and adding it back with a name with a different case
Summary: case folding collision with a changeset removing a directory and adding it ba...
Status: RESOLVED FIXED
Alias: None
Product: Mercurial
Classification: Unclassified
Component: Mercurial (show other bugs)
Version: earlier
Hardware: PC Mac OS
: urgent bug
Assignee: Bugzilla
URL:
Keywords: regression
Depends on:
Blocks:
 
Reported: 2012-10-04 19:43 UTC by Ehsan Akhgari
Modified: 2017-11-01 18:05 UTC (History)
8 users (show)

See Also:
Python Version: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Ehsan Akhgari 2012-10-04 19:43 UTC
Steps to reproduce (on Mac or Windows):

1. Clone https://bitbucket.org/ehsan/broken-inbound
2. Pull http://hg.mozilla.org/mozilla-central/
3. hg merge

You'll see an error message like this:

case-folding collision between media/webrtc/trunk/src/modules/audio_coding/codecs/iSAC/fix/source/filterbank_tables.c and media/webrtc/trunk/src/modules/audio_coding/codecs/isac/fix/source/filterbank_tables.c

We had to strip the offending changeset (d81b605dc8d8) from our repository today to work around this.

Please refer to my blog post <http://ehsanakhgari.org/blog/2012-10-04/renaming-directories-in-mercurial-by-just-changing-the-case> for more details, and let me know if you have questions.  Thanks!
Comment 1 Bryan O'Sullivan 2012-10-05 13:00 UTC
Couple of things here.

1. Giving a reproduction recipe that takes hours to clone huge repos is not as helpful as you might think.

2. In your blog post, your characterization of the reason for the bug is wrong. It has nothing to do with the repo storage mechanism, and is in fact a filesystem problem.

3. If you're going to be whiny and rude in a blog post, that's fine. But if you link to that blog post from your bug report, do you actually expect someone who could fix the bug to be motivated to help you?
Comment 2 Ehsan Akhgari 2012-10-05 13:29 UTC
(In reply to comment #1)
1. I understand that bug reports with small test cases are much more easier to act on, and I did in fact try to reproduce this in a small test example repo.  The guilty changeset is <https://bitbucket.org/ehsan/broken-inbound/changeset/d81b605dc8d8da6d9b7ed3ca3b5d03038c630c30>, which removes the iSAC directory and adds an isac directory, and I tried doing that using a number of ways that I could think of (hg mv, hg rm and hg add again, etc.) but I could not reproduce this problem.  I was also not the person who created that changeset, so I don't have an exact idea on what happened there.  Which is why I filed this bug in its current form.  But I would love to make this easier to act on if I can provide any additional information.

2. My understanding of hg internals is limited, so I may in fact be misunderstanding what causes this bug.  I would happily update the post if you would let me know what the exact underlying cause of the bug is.

3. I'm sorry if I upset you, I did not mean to do that by linking to my post, and I'm here in good spirit.  The reason I did that was to provide the background on how we saw the bug happen.  As I said before I would be happy to provide more information here if someone lets me know what they need to know in order to debug this.
Comment 3 Matt Mackall 2012-10-05 15:25 UTC
[adding foozy]

Here's a possible repro:

 hg init a
 cd a

 mkdir a
 echo a > a/a   # dir/file that will cause problems
 hg ci -Am0
 cp -a a b      # note the convolutions here to bypass Mercurial's case-folding
 hg rm a        # detection
 hg add b       # 
 hg mv b A      # replacing this block with 'hg mv a b; hg mv b A' gives a working merge
 hg st -C
 hg ci -Am1
 hg up 0
 echo b > a/a   # modify a file in a
 hg ci -Am2
 hg merge
 hg st

In the above case, it's NOT a bug. Mercurial can't know that a/a and A/a are "the same file" because they have different names and no renames between the two were recorded (and they're definitionally not the same file on some systems Mercurial supports). Since they can't both exist in a checkout on a case-insensitive filesystem simultaneously, we have a problem that can't nicely be solved at merge time.

On the other hand, if we don't touch a/a on the local side, the collision still triggers. Recent Mercurial is overzealous here: it reports collisions, even if one of the colliding files would otherwise be deleted in the merge.

Now let's check your repo:

 $ hg log --follow media/webrtc/trunk/src/modules/audio_coding/codecs/iSAC/isac_test.gypi
 changeset:   97249:305edcfd6460
 user:        Randell Jesup <rjesup@jesup.org>
 date:        Thu Jun 21 07:34:58 2012 -0400
 summary:     Bug 749889: Webrtc import of rev 2047, with most of third_party and test/data removed rs=ted

Just as I suspected: the colliding file is newly-introduced and the old file was simply deleted without renaming.

Two obvious work-arounds:

- do the problematic merge on a case-sensitive filesystem
- rename the local or remote directory to not case-collide first, then merge
Comment 4 Ehsan Akhgari 2012-10-05 16:18 UTC
We did try doing the merge on Linux on a case sensitive file system, and then we tried doing another merge from mozilla-central on Mac with a case insensitive file system, and the problem happened again.  So perhaps the first work-around does not work?

(We did not try the second work-around mostly because I didn't think of it.)
Comment 5 Matt Mackall 2012-10-05 16:57 UTC
I tested the first workaround with 2.3, but wouldn't be surprised if it didn't work with stale versions.
Comment 6 Ehsan Akhgari 2012-10-05 17:15 UTC
Hmm, I'm using 2.3.1... but maybe I'm missing something.
Comment 7 Hal 2012-10-05 18:37 UTC
fwiw, this may be version sensitive - I could not reproduce using hg version 2.0
Comment 8 Matt Mackall 2012-10-05 18:39 UTC
Yes, it's introduced with 2.1, with various nearby changes after that.
Comment 9 Hal 2012-10-08 12:26 UTC
(In reply to comment #8)
Matt - thanks for the versions impacted information. So far we've been talking about a problem in the client side code. Is there any component of this issue in the server side?

We're evaluating an update from hg 2.0.2 to 2.3.x on the server side. Would you expect that to affect this client side issue one way or the other?
Comment 10 Matt Mackall 2012-10-08 12:48 UTC
No, it's entirely dependent on the filesystem capabilities detected in the working directory. The backend storage is completely portable and can store (for instance) case-colliding, invalid-on-Windows, UTF-8 filenames on VFAT.

(raising to urgent, as this bug is a regression.)
Comment 11 FUJIWARA Katsunori 2012-10-25 03:43 UTC
(In reply to comment #3)

Please let me confirm my understanding about this issue.

Collision detection causes unexpected merge fail in the case
below:

 mkdir a
 echo a > a/a
 hg ci -Am0
 cp -a a b
 hg rm a
 hg add b
 hg mv b A
 hg st -C
 hg ci -Am1
 hg up 0
 # echo b > a/a   # modify a file in a
 echo b > x   # modify another file, 
              # so "a/a" must not collide against "A/a" on other head
              # because "a/a" was already removed on other
 hg ci -Am2
 hg merge
 hg st

So, we should fix "overzealous"-ness of recent Mercurial,
shouldn't we ?
Comment 12 Matt Mackall 2012-10-25 12:53 UTC
Yes.

Files that are going to be deleted by the merge anyway shouldn't cause case collisions.
Comment 13 HG Bot 2012-10-31 17:59 UTC
Fixed by http://selenic.com/repo/hg/rev/ce7bc04d863b
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
icasefs: make case-folding collision detection as deletion aware (issue3648)

Before this patch, case-folding collision is checked simply between
manifests of each merged revisions.

So, files may be considered as colliding each other, even though one
of them is already deleted on one of merged branches: in such case,
merge causes deleting it, so case-folding collision doesn't occur.

This patch checks whether both of files colliding each other still
remain after merge or not, and ignores collision if at least one of
them is deleted by merge.

In the case that one of colliding files is deleted on one of merged
branches and changed on another, file is considered to still remain
after merge, even though it may be deleted by merge, if "deleting" of
it is chosen in "manifestmerge()".

This avoids fail to merge by case-folding collisions after choices
from "changing" and "deleting" of files.

This patch adds only tests for "removed remotely" code paths in
"_remains()", because other ones are tested by existing tests in
"test-casecollision-merge.t".

(please test the fix)