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 |
$ |
|
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 |
$ |
|
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 |
|
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