Show More
@@ -110,54 +110,6 b' def _checkunknown(repo, wctx, mctx):' | |||
|
110 | 110 | raise util.Abort(_("untracked files in working directory differ " |
|
111 | 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 | 113 | def _forgetremoved(wctx, mctx, branchmerge): |
|
162 | 114 | """ |
|
163 | 115 | Forget removed files |
@@ -186,6 +138,62 b' def _forgetremoved(wctx, mctx, branchmer' | |||
|
186 | 138 | |
|
187 | 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 | 197 | def manifestmerge(repo, wctx, p2, pa, branchmerge, force, partial, |
|
190 | 198 | acceptremote=False): |
|
191 | 199 | """ |
@@ -342,6 +350,14 b' def manifestmerge(repo, wctx, p2, pa, br' | |||
|
342 | 350 | raise util.Abort(_("untracked files in working directory differ " |
|
343 | 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 | 361 | for f, m in sorted(prompts): |
|
346 | 362 | if m == "cd": |
|
347 | 363 | if acceptremote: |
@@ -541,14 +557,6 b' def calculateupdates(repo, tctx, mctx, a' | |||
|
541 | 557 | acceptremote=False): |
|
542 | 558 | "Calculate the actions needed to merge mctx into tctx" |
|
543 | 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 | 560 | actions += manifestmerge(repo, tctx, mctx, |
|
553 | 561 | ancestor, |
|
554 | 562 | branchmerge, force, |
@@ -17,14 +17,17 b' this is also case for issue3370.' | |||
|
17 | 17 | $ echo a > a |
|
18 | 18 | $ hg add a |
|
19 | 19 | $ hg commit -m '#0' |
|
20 | $ hg tag -l A | |
|
20 | 21 |
$ |
|
21 | 22 | $ hg rename tmp A |
|
22 | 23 | $ hg commit -m '#1' |
|
24 | $ hg tag -l B | |
|
23 | 25 |
$ |
|
24 | 26 | $ touch x |
|
25 | 27 | $ hg add x |
|
26 | 28 | $ hg commit -m '#2' |
|
27 | 29 | created new head |
|
30 | $ hg tag -l C | |
|
28 | 31 | |
|
29 | 32 | $ hg merge -q |
|
30 | 33 | $ hg status -A |
@@ -37,6 +40,46 b' this is also case for issue3370.' | |||
|
37 | 40 | $ hg status -A |
|
38 | 41 | M x |
|
39 | 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 | 84 | $ cd .. |
|
42 | 85 | |
@@ -63,7 +106,7 b' this is also case for issue3370.' | |||
|
63 | 106 | $ hg commit -m '#4' |
|
64 | 107 | |
|
65 | 108 | $ hg merge |
|
66 |
abort: case-folding collision between |
|
|
109 | abort: case-folding collision between a and A | |
|
67 | 110 | [255] |
|
68 | 111 | $ hg parents --template '{rev}\n' |
|
69 | 112 | 4 |
General Comments 0
You need to be logged in to leave comments.
Login now