2012-01-01

Mercurial の Case Folding Collision を修復する

調子にのって Makefile を書いていたら、平行しているブランチで makefile と Makefile を作るという失態です。ほんとうに、あけましておめでとうございます。

結論から言うと、How to fix Mercurial Case Folding Collisionで解決しました。以下、個人的なメモです。

問題の再現方法

ベースになるリポジトリを作る。

$ hg init foo
$ cd foo
$ touch foo.c
$ hg add
adding foo.c
$ hg commit -m "foo.c"

小文字の「makefile」を持つブランチを作る。

$ hg branch low
marked working directory as branch low
$ touch makefile
$ hg add
adding makefile
$ hg commit -m "added makefile"

default ブランチで「Makefile」を作る。

$ hg up default
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ touch Makefile
$ hg add
adding Makefile
$ hg commit -m "added Makefile"

ブランチをマージする。

$ hg up default
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg merge low
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg st
M makefile
$ hg commit -m "merged"
$ hg up low
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ hg up default
abort: case-folding collision between makefile and Makefile

修正する

ブランチを眺めましょう。

$ hg glog
o    changeset:   3:94ffa654c8c1
|\   tag:         tip
| |  parent:      2:65bd31a51e91
| |  parent:      1:67211aceefe3
| |  user:        furukawa
| |  date:        Sun Jan 01 16:39:17 2012 +0900
| |  summary:     merged
| |
| o  changeset:   2:65bd31a51e91
| |  parent:      0:21c6ffb22524
| |  user:        furukawa
| |  date:        Sun Jan 01 16:39:16 2012 +0900
| |  summary:     added Makefile
| |
@ |  changeset:   1:67211aceefe3
|/   branch:      low
|    user:        furukawa
|    date:        Sun Jan 01 16:39:15 2012 +0900
|    summary:     added makefile
|
o  changeset:   0:21c6ffb22524
   user:        furukawa
   date:        Sun Jan 01 16:39:14 2012 +0900
   summary:     foo.c

そんなわけで、具体的な作業にはいります。changeset 1 で、makefile を追加したのがそもそもの元凶である、と仮定します。このリビジョンを修正します。

$ hg debugsetparents 1
$ hg debugrebuildstate

上の操作で changeset 1 を親とするリビジョンにしています(たぶん)。で、makefile をなかった事にします。

$ hg rm -A -f makefile
$ hg forget makefile
$ hg commit -m "fixed case problem"
$ hg up -C tip
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg glog
@  changeset:   4:b636a1636454
|  branch:      low
|  tag:         tip
|  parent:      1:e8c081d89471
|  user:        furukawa
|  date:        Sun Jan 01 16:47:06 2012 +0900
|  summary:     fixed case problem
|
| o  changeset:   3:20205d0bcf9d
|/|  parent:      2:d1de5468f0be
| |  parent:      1:e8c081d89471
| |  user:        furukawa
| |  date:        Sun Jan 01 16:41:58 2012 +0900
| |  summary:     merged
| |
| o  changeset:   2:d1de5468f0be
| |  parent:      0:43bc62047652
| |  user:        furukawa
| |  date:        Sun Jan 01 16:41:56 2012 +0900
| |  summary:     added Makefile
| |
o |  changeset:   1:e8c081d89471
|/   branch:      low
|    user:        furukawa
|    date:        Sun Jan 01 16:41:56 2012 +0900
|    summary:     added makefile
|
o  changeset:   0:43bc62047652
   user:        furukawa
   date:        Sun Jan 01 16:41:55 2012 +0900
   summary:     foo

default ブランチに、これを取り込んで終了

$ hg up 2
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg merge low
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg commit
created new head

まとめ

こういう操作で修復できました。が、実はよくわかっていません。とくに、debugsetparents と debugrebuildstate が危ういです。