##// END OF EJS Templates
icasefs: rewrite case-folding collision detection (issue3452)...
FUJIWARA Katsunori -
r19105:c60a7f5a stable
parent child Browse files
Show More
@@ -110,54 +110,6 b' def _checkunknown(repo, wctx, mctx):'
110 raise util.Abort(_("untracked files in working directory differ "
110 raise util.Abort(_("untracked files in working directory differ "
111 "from files in requested revision"))
111 "from files in requested revision"))
112
112
113 def _remains(f, m, ma, workingctx=False):
114 """check whether specified file remains after merge.
115
116 It is assumed that specified file is not contained in the manifest
117 of the other context.
118 """
119 if f in ma:
120 n = m[f]
121 if n != ma[f]:
122 return True # because it is changed locally
123 # even though it doesn't remain, if "remote deleted" is
124 # chosen in manifestmerge()
125 elif workingctx and n[20:] == "a":
126 return True # because it is added locally (linear merge specific)
127 else:
128 return False # because it is removed remotely
129 else:
130 return True # because it is added locally
131
132 def _checkcollision(mctx, extractxs):
133 "check for case folding collisions in the destination context"
134 folded = {}
135 for fn in mctx:
136 fold = util.normcase(fn)
137 if fold in folded:
138 raise util.Abort(_("case-folding collision between %s and %s")
139 % (fn, folded[fold]))
140 folded[fold] = fn
141
142 if extractxs:
143 wctx, actx = extractxs
144 # class to delay looking up copy mapping
145 class pathcopies(object):
146 @util.propertycache
147 def map(self):
148 # {dst@mctx: src@wctx} copy mapping
149 return copies.pathcopies(wctx, mctx)
150 pc = pathcopies()
151
152 for fn in wctx:
153 fold = util.normcase(fn)
154 mfn = folded.get(fold, None)
155 if (mfn and mfn != fn and pc.map.get(mfn) != fn and
156 _remains(fn, wctx.manifest(), actx.manifest(), True) and
157 _remains(mfn, mctx.manifest(), actx.manifest())):
158 raise util.Abort(_("case-folding collision between %s and %s")
159 % (mfn, fn))
160
161 def _forgetremoved(wctx, mctx, branchmerge):
113 def _forgetremoved(wctx, mctx, branchmerge):
162 """
114 """
163 Forget removed files
115 Forget removed files
@@ -186,6 +138,62 b' def _forgetremoved(wctx, mctx, branchmer'
186
138
187 return actions
139 return actions
188
140
141 def _checkcollision(repo, wmf, actions, prompts):
142 # build provisional merged manifest up
143 pmmf = set(wmf)
144
145 def addop(f, args):
146 pmmf.add(f)
147 def removeop(f, args):
148 pmmf.discard(f)
149 def nop(f, args):
150 pass
151
152 def renameop(f, args):
153 f2, fd, flags = args
154 if f:
155 pmmf.discard(f)
156 pmmf.add(fd)
157 def mergeop(f, args):
158 f2, fd, move = args
159 if move:
160 pmmf.discard(f)
161 pmmf.add(fd)
162
163 opmap = {
164 "a": addop,
165 "d": renameop,
166 "dr": nop,
167 "e": nop,
168 "f": addop, # untracked file should be kept in working directory
169 "g": addop,
170 "m": mergeop,
171 "r": removeop,
172 "rd": nop,
173 }
174 for f, m, args, msg in actions:
175 op = opmap.get(m)
176 assert op, m
177 op(f, args)
178
179 opmap = {
180 "cd": addop,
181 "dc": addop,
182 }
183 for f, m in prompts:
184 op = opmap.get(m)
185 assert op, m
186 op(f, None)
187
188 # check case-folding collision in provisional merged manifest
189 foldmap = {}
190 for f in sorted(pmmf):
191 fold = util.normcase(f)
192 if fold in foldmap:
193 raise util.Abort(_("case-folding collision between %s and %s")
194 % (f, foldmap[fold]))
195 foldmap[fold] = f
196
189 def manifestmerge(repo, wctx, p2, pa, branchmerge, force, partial,
197 def manifestmerge(repo, wctx, p2, pa, branchmerge, force, partial,
190 acceptremote=False):
198 acceptremote=False):
191 """
199 """
@@ -342,6 +350,14 b' def manifestmerge(repo, wctx, p2, pa, br'
342 raise util.Abort(_("untracked files in working directory differ "
350 raise util.Abort(_("untracked files in working directory differ "
343 "from files in requested revision"))
351 "from files in requested revision"))
344
352
353 if not util.checkcase(repo.path):
354 # check collision between files only in p2 for clean update
355 if (not branchmerge and
356 (force or not wctx.dirty(missing=True, branch=False))):
357 _checkcollision(repo, m2, [], [])
358 else:
359 _checkcollision(repo, m1, actions, prompts)
360
345 for f, m in sorted(prompts):
361 for f, m in sorted(prompts):
346 if m == "cd":
362 if m == "cd":
347 if acceptremote:
363 if acceptremote:
@@ -541,14 +557,6 b' def calculateupdates(repo, tctx, mctx, a'
541 acceptremote=False):
557 acceptremote=False):
542 "Calculate the actions needed to merge mctx into tctx"
558 "Calculate the actions needed to merge mctx into tctx"
543 actions = []
559 actions = []
544 folding = not util.checkcase(repo.path)
545 if folding:
546 # collision check is not needed for clean update
547 if (not branchmerge and
548 (force or not tctx.dirty(missing=True, branch=False))):
549 _checkcollision(mctx, None)
550 else:
551 _checkcollision(mctx, (tctx, ancestor))
552 actions += manifestmerge(repo, tctx, mctx,
560 actions += manifestmerge(repo, tctx, mctx,
553 ancestor,
561 ancestor,
554 branchmerge, force,
562 branchmerge, force,
@@ -17,14 +17,17 b' this is also case for issue3370.'
17 $ echo a > a
17 $ echo a > a
18 $ hg add a
18 $ hg add a
19 $ hg commit -m '#0'
19 $ hg commit -m '#0'
20 $ hg tag -l A
20 $ hg rename a tmp
21 $ hg rename a tmp
21 $ hg rename tmp A
22 $ hg rename tmp A
22 $ hg commit -m '#1'
23 $ hg commit -m '#1'
24 $ hg tag -l B
23 $ hg update -q 0
25 $ hg update -q 0
24 $ touch x
26 $ touch x
25 $ hg add x
27 $ hg add x
26 $ hg commit -m '#2'
28 $ hg commit -m '#2'
27 created new head
29 created new head
30 $ hg tag -l C
28
31
29 $ hg merge -q
32 $ hg merge -q
30 $ hg status -A
33 $ hg status -A
@@ -37,6 +40,46 b' this is also case for issue3370.'
37 $ hg status -A
40 $ hg status -A
38 M x
41 M x
39 C A
42 C A
43 $ hg commit -m '(D)'
44 $ hg tag -l D
45
46 additional test for issue3452:
47
48 | this assumes the history below.
49 |
50 | (A) -- (C) -- (E) -------
51 | \ \ \
52 | \ \ \
53 | (B) -- (D) -- (F) -- (G)
54 |
55 | A: add file 'a'
56 | B: rename from 'a' to 'A'
57 | C: add 'x' (or operation other than modification of 'a')
58 | D: merge C into B
59 | E: modify 'a'
60 | F: modify 'A'
61 | G: merge E into F
62 |
63 | issue3452 occurs when (B) is recorded before (C)
64
65 $ hg update -q --clean C
66 $ echo "modify 'a' at (E)" > a
67 $ hg commit -m '(E)'
68 created new head
69 $ hg tag -l E
70
71 $ hg update -q --clean D
72 $ echo "modify 'A' at (F)" > A
73 $ hg commit -m '(F)'
74 $ hg tag -l F
75
76 $ hg merge -q --tool internal:other E
77 $ hg status -A
78 M A
79 a
80 C x
81 $ cat A
82 modify 'a' at (E)
40
83
41 $ cd ..
84 $ cd ..
42
85
@@ -63,7 +106,7 b' this is also case for issue3370.'
63 $ hg commit -m '#4'
106 $ hg commit -m '#4'
64
107
65 $ hg merge
108 $ hg merge
66 abort: case-folding collision between A and a
109 abort: case-folding collision between a and A
67 [255]
110 [255]
68 $ hg parents --template '{rev}\n'
111 $ hg parents --template '{rev}\n'
69 4
112 4
General Comments 0
You need to be logged in to leave comments. Login now