108 wctx._repo.ui.warn(_("%s: untracked file differs\n") % f) |
108 wctx._repo.ui.warn(_("%s: untracked file differs\n") % f) |
109 if error: |
109 if error: |
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 |
164 |
116 |
165 If we're jumping between revisions (as opposed to merging), and if |
117 If we're jumping between revisions (as opposed to merging), and if |
183 for f in wctx.removed(): |
135 for f in wctx.removed(): |
184 if f not in mctx: |
136 if f not in mctx: |
185 actions.append((f, "f", None, "forget removed")) |
137 actions.append((f, "f", None, "forget removed")) |
186 |
138 |
187 return actions |
139 return actions |
|
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 |
188 |
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 """ |
192 Merge p1 and p2 with ancestor pa and generate merge action list |
200 Merge p1 and p2 with ancestor pa and generate merge action list |
340 else: assert False, m |
348 else: assert False, m |
341 if aborts: |
349 if aborts: |
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: |
348 actions.append((f, "r", None, "remote delete")) |
364 actions.append((f, "r", None, "remote delete")) |
349 elif repo.ui.promptchoice( |
365 elif repo.ui.promptchoice( |
539 |
555 |
540 def calculateupdates(repo, tctx, mctx, ancestor, branchmerge, force, partial, |
556 def calculateupdates(repo, tctx, mctx, ancestor, branchmerge, force, partial, |
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, |
555 partial, acceptremote) |
563 partial, acceptremote) |
556 if tctx.rev() is None: |
564 if tctx.rev() is None: |