##// END OF EJS Templates
_checkunknownfiles: turn 'conflicts' into a set...
Siddharth Agarwal -
r27654:95dc67f1 default
parent child Browse files
Show More
@@ -1,1543 +1,1543 b''
1 1 # merge.py - directory-level update/merge handling for Mercurial
2 2 #
3 3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import errno
11 11 import os
12 12 import shutil
13 13 import struct
14 14
15 15 from .i18n import _
16 16 from .node import (
17 17 bin,
18 18 hex,
19 19 nullhex,
20 20 nullid,
21 21 nullrev,
22 22 )
23 23 from . import (
24 24 copies,
25 25 destutil,
26 26 error,
27 27 filemerge,
28 28 obsolete,
29 29 subrepo,
30 30 util,
31 31 worker,
32 32 )
33 33
34 34 _pack = struct.pack
35 35 _unpack = struct.unpack
36 36
37 37 def _droponode(data):
38 38 # used for compatibility for v1
39 39 bits = data.split('\0')
40 40 bits = bits[:-2] + bits[-1:]
41 41 return '\0'.join(bits)
42 42
43 43 class mergestate(object):
44 44 '''track 3-way merge state of individual files
45 45
46 46 The merge state is stored on disk when needed. Two files are used: one with
47 47 an old format (version 1), and one with a new format (version 2). Version 2
48 48 stores a superset of the data in version 1, including new kinds of records
49 49 in the future. For more about the new format, see the documentation for
50 50 `_readrecordsv2`.
51 51
52 52 Each record can contain arbitrary content, and has an associated type. This
53 53 `type` should be a letter. If `type` is uppercase, the record is mandatory:
54 54 versions of Mercurial that don't support it should abort. If `type` is
55 55 lowercase, the record can be safely ignored.
56 56
57 57 Currently known records:
58 58
59 59 L: the node of the "local" part of the merge (hexified version)
60 60 O: the node of the "other" part of the merge (hexified version)
61 61 F: a file to be merged entry
62 62 C: a change/delete or delete/change conflict
63 63 D: a file that the external merge driver will merge internally
64 64 (experimental)
65 65 m: the external merge driver defined for this merge plus its run state
66 66 (experimental)
67 67 X: unsupported mandatory record type (used in tests)
68 68 x: unsupported advisory record type (used in tests)
69 69
70 70 Merge driver run states (experimental):
71 71 u: driver-resolved files unmarked -- needs to be run next time we're about
72 72 to resolve or commit
73 73 m: driver-resolved files marked -- only needs to be run before commit
74 74 s: success/skipped -- does not need to be run any more
75 75
76 76 '''
77 77 statepathv1 = 'merge/state'
78 78 statepathv2 = 'merge/state2'
79 79
80 80 @staticmethod
81 81 def clean(repo, node=None, other=None):
82 82 """Initialize a brand new merge state, removing any existing state on
83 83 disk."""
84 84 ms = mergestate(repo)
85 85 ms.reset(node, other)
86 86 return ms
87 87
88 88 @staticmethod
89 89 def read(repo):
90 90 """Initialize the merge state, reading it from disk."""
91 91 ms = mergestate(repo)
92 92 ms._read()
93 93 return ms
94 94
95 95 def __init__(self, repo):
96 96 """Initialize the merge state.
97 97
98 98 Do not use this directly! Instead call read() or clean()."""
99 99 self._repo = repo
100 100 self._dirty = False
101 101
102 102 def reset(self, node=None, other=None):
103 103 self._state = {}
104 104 self._local = None
105 105 self._other = None
106 106 for var in ('localctx', 'otherctx'):
107 107 if var in vars(self):
108 108 delattr(self, var)
109 109 if node:
110 110 self._local = node
111 111 self._other = other
112 112 self._readmergedriver = None
113 113 if self.mergedriver:
114 114 self._mdstate = 's'
115 115 else:
116 116 self._mdstate = 'u'
117 117 shutil.rmtree(self._repo.join('merge'), True)
118 118 self._results = {}
119 119 self._dirty = False
120 120
121 121 def _read(self):
122 122 """Analyse each record content to restore a serialized state from disk
123 123
124 124 This function process "record" entry produced by the de-serialization
125 125 of on disk file.
126 126 """
127 127 self._state = {}
128 128 self._local = None
129 129 self._other = None
130 130 for var in ('localctx', 'otherctx'):
131 131 if var in vars(self):
132 132 delattr(self, var)
133 133 self._readmergedriver = None
134 134 self._mdstate = 's'
135 135 unsupported = set()
136 136 records = self._readrecords()
137 137 for rtype, record in records:
138 138 if rtype == 'L':
139 139 self._local = bin(record)
140 140 elif rtype == 'O':
141 141 self._other = bin(record)
142 142 elif rtype == 'm':
143 143 bits = record.split('\0', 1)
144 144 mdstate = bits[1]
145 145 if len(mdstate) != 1 or mdstate not in 'ums':
146 146 # the merge driver should be idempotent, so just rerun it
147 147 mdstate = 'u'
148 148
149 149 self._readmergedriver = bits[0]
150 150 self._mdstate = mdstate
151 151 elif rtype in 'FDC':
152 152 bits = record.split('\0')
153 153 self._state[bits[0]] = bits[1:]
154 154 elif not rtype.islower():
155 155 unsupported.add(rtype)
156 156 self._results = {}
157 157 self._dirty = False
158 158
159 159 if unsupported:
160 160 raise error.UnsupportedMergeRecords(unsupported)
161 161
162 162 def _readrecords(self):
163 163 """Read merge state from disk and return a list of record (TYPE, data)
164 164
165 165 We read data from both v1 and v2 files and decide which one to use.
166 166
167 167 V1 has been used by version prior to 2.9.1 and contains less data than
168 168 v2. We read both versions and check if no data in v2 contradicts
169 169 v1. If there is not contradiction we can safely assume that both v1
170 170 and v2 were written at the same time and use the extract data in v2. If
171 171 there is contradiction we ignore v2 content as we assume an old version
172 172 of Mercurial has overwritten the mergestate file and left an old v2
173 173 file around.
174 174
175 175 returns list of record [(TYPE, data), ...]"""
176 176 v1records = self._readrecordsv1()
177 177 v2records = self._readrecordsv2()
178 178 if self._v1v2match(v1records, v2records):
179 179 return v2records
180 180 else:
181 181 # v1 file is newer than v2 file, use it
182 182 # we have to infer the "other" changeset of the merge
183 183 # we cannot do better than that with v1 of the format
184 184 mctx = self._repo[None].parents()[-1]
185 185 v1records.append(('O', mctx.hex()))
186 186 # add place holder "other" file node information
187 187 # nobody is using it yet so we do no need to fetch the data
188 188 # if mctx was wrong `mctx[bits[-2]]` may fails.
189 189 for idx, r in enumerate(v1records):
190 190 if r[0] == 'F':
191 191 bits = r[1].split('\0')
192 192 bits.insert(-2, '')
193 193 v1records[idx] = (r[0], '\0'.join(bits))
194 194 return v1records
195 195
196 196 def _v1v2match(self, v1records, v2records):
197 197 oldv2 = set() # old format version of v2 record
198 198 for rec in v2records:
199 199 if rec[0] == 'L':
200 200 oldv2.add(rec)
201 201 elif rec[0] == 'F':
202 202 # drop the onode data (not contained in v1)
203 203 oldv2.add(('F', _droponode(rec[1])))
204 204 for rec in v1records:
205 205 if rec not in oldv2:
206 206 return False
207 207 else:
208 208 return True
209 209
210 210 def _readrecordsv1(self):
211 211 """read on disk merge state for version 1 file
212 212
213 213 returns list of record [(TYPE, data), ...]
214 214
215 215 Note: the "F" data from this file are one entry short
216 216 (no "other file node" entry)
217 217 """
218 218 records = []
219 219 try:
220 220 f = self._repo.vfs(self.statepathv1)
221 221 for i, l in enumerate(f):
222 222 if i == 0:
223 223 records.append(('L', l[:-1]))
224 224 else:
225 225 records.append(('F', l[:-1]))
226 226 f.close()
227 227 except IOError as err:
228 228 if err.errno != errno.ENOENT:
229 229 raise
230 230 return records
231 231
232 232 def _readrecordsv2(self):
233 233 """read on disk merge state for version 2 file
234 234
235 235 This format is a list of arbitrary records of the form:
236 236
237 237 [type][length][content]
238 238
239 239 `type` is a single character, `length` is a 4 byte integer, and
240 240 `content` is an arbitrary byte sequence of length `length`.
241 241
242 242 Mercurial versions prior to 3.7 have a bug where if there are
243 243 unsupported mandatory merge records, attempting to clear out the merge
244 244 state with hg update --clean or similar aborts. The 't' record type
245 245 works around that by writing out what those versions treat as an
246 246 advisory record, but later versions interpret as special: the first
247 247 character is the 'real' record type and everything onwards is the data.
248 248
249 249 Returns list of records [(TYPE, data), ...]."""
250 250 records = []
251 251 try:
252 252 f = self._repo.vfs(self.statepathv2)
253 253 data = f.read()
254 254 off = 0
255 255 end = len(data)
256 256 while off < end:
257 257 rtype = data[off]
258 258 off += 1
259 259 length = _unpack('>I', data[off:(off + 4)])[0]
260 260 off += 4
261 261 record = data[off:(off + length)]
262 262 off += length
263 263 if rtype == 't':
264 264 rtype, record = record[0], record[1:]
265 265 records.append((rtype, record))
266 266 f.close()
267 267 except IOError as err:
268 268 if err.errno != errno.ENOENT:
269 269 raise
270 270 return records
271 271
272 272 @util.propertycache
273 273 def mergedriver(self):
274 274 # protect against the following:
275 275 # - A configures a malicious merge driver in their hgrc, then
276 276 # pauses the merge
277 277 # - A edits their hgrc to remove references to the merge driver
278 278 # - A gives a copy of their entire repo, including .hg, to B
279 279 # - B inspects .hgrc and finds it to be clean
280 280 # - B then continues the merge and the malicious merge driver
281 281 # gets invoked
282 282 configmergedriver = self._repo.ui.config('experimental', 'mergedriver')
283 283 if (self._readmergedriver is not None
284 284 and self._readmergedriver != configmergedriver):
285 285 raise error.ConfigError(
286 286 _("merge driver changed since merge started"),
287 287 hint=_("revert merge driver change or abort merge"))
288 288
289 289 return configmergedriver
290 290
291 291 @util.propertycache
292 292 def localctx(self):
293 293 if self._local is None:
294 294 raise RuntimeError("localctx accessed but self._local isn't set")
295 295 return self._repo[self._local]
296 296
297 297 @util.propertycache
298 298 def otherctx(self):
299 299 if self._other is None:
300 300 raise RuntimeError("localctx accessed but self._local isn't set")
301 301 return self._repo[self._other]
302 302
303 303 def active(self):
304 304 """Whether mergestate is active.
305 305
306 306 Returns True if there appears to be mergestate. This is a rough proxy
307 307 for "is a merge in progress."
308 308 """
309 309 # Check local variables before looking at filesystem for performance
310 310 # reasons.
311 311 return bool(self._local) or bool(self._state) or \
312 312 self._repo.vfs.exists(self.statepathv1) or \
313 313 self._repo.vfs.exists(self.statepathv2)
314 314
315 315 def commit(self):
316 316 """Write current state on disk (if necessary)"""
317 317 if self._dirty:
318 318 records = self._makerecords()
319 319 self._writerecords(records)
320 320 self._dirty = False
321 321
322 322 def _makerecords(self):
323 323 records = []
324 324 records.append(('L', hex(self._local)))
325 325 records.append(('O', hex(self._other)))
326 326 if self.mergedriver:
327 327 records.append(('m', '\0'.join([
328 328 self.mergedriver, self._mdstate])))
329 329 for d, v in self._state.iteritems():
330 330 if v[0] == 'd':
331 331 records.append(('D', '\0'.join([d] + v)))
332 332 # v[1] == local ('cd'), v[6] == other ('dc') -- not supported by
333 333 # older versions of Mercurial
334 334 elif v[1] == nullhex or v[6] == nullhex:
335 335 records.append(('C', '\0'.join([d] + v)))
336 336 else:
337 337 records.append(('F', '\0'.join([d] + v)))
338 338 return records
339 339
340 340 def _writerecords(self, records):
341 341 """Write current state on disk (both v1 and v2)"""
342 342 self._writerecordsv1(records)
343 343 self._writerecordsv2(records)
344 344
345 345 def _writerecordsv1(self, records):
346 346 """Write current state on disk in a version 1 file"""
347 347 f = self._repo.vfs(self.statepathv1, 'w')
348 348 irecords = iter(records)
349 349 lrecords = irecords.next()
350 350 assert lrecords[0] == 'L'
351 351 f.write(hex(self._local) + '\n')
352 352 for rtype, data in irecords:
353 353 if rtype == 'F':
354 354 f.write('%s\n' % _droponode(data))
355 355 f.close()
356 356
357 357 def _writerecordsv2(self, records):
358 358 """Write current state on disk in a version 2 file
359 359
360 360 See the docstring for _readrecordsv2 for why we use 't'."""
361 361 # these are the records that all version 2 clients can read
362 362 whitelist = 'LOF'
363 363 f = self._repo.vfs(self.statepathv2, 'w')
364 364 for key, data in records:
365 365 assert len(key) == 1
366 366 if key not in whitelist:
367 367 key, data = 't', '%s%s' % (key, data)
368 368 format = '>sI%is' % len(data)
369 369 f.write(_pack(format, key, len(data), data))
370 370 f.close()
371 371
372 372 def add(self, fcl, fco, fca, fd):
373 373 """add a new (potentially?) conflicting file the merge state
374 374 fcl: file context for local,
375 375 fco: file context for remote,
376 376 fca: file context for ancestors,
377 377 fd: file path of the resulting merge.
378 378
379 379 note: also write the local version to the `.hg/merge` directory.
380 380 """
381 381 if fcl.isabsent():
382 382 hash = nullhex
383 383 else:
384 384 hash = util.sha1(fcl.path()).hexdigest()
385 385 self._repo.vfs.write('merge/' + hash, fcl.data())
386 386 self._state[fd] = ['u', hash, fcl.path(),
387 387 fca.path(), hex(fca.filenode()),
388 388 fco.path(), hex(fco.filenode()),
389 389 fcl.flags()]
390 390 self._dirty = True
391 391
392 392 def __contains__(self, dfile):
393 393 return dfile in self._state
394 394
395 395 def __getitem__(self, dfile):
396 396 return self._state[dfile][0]
397 397
398 398 def __iter__(self):
399 399 return iter(sorted(self._state))
400 400
401 401 def files(self):
402 402 return self._state.keys()
403 403
404 404 def mark(self, dfile, state):
405 405 self._state[dfile][0] = state
406 406 self._dirty = True
407 407
408 408 def mdstate(self):
409 409 return self._mdstate
410 410
411 411 def unresolved(self):
412 412 """Obtain the paths of unresolved files."""
413 413
414 414 for f, entry in self._state.items():
415 415 if entry[0] == 'u':
416 416 yield f
417 417
418 418 def driverresolved(self):
419 419 """Obtain the paths of driver-resolved files."""
420 420
421 421 for f, entry in self._state.items():
422 422 if entry[0] == 'd':
423 423 yield f
424 424
425 425 def _resolve(self, preresolve, dfile, wctx, labels=None):
426 426 """rerun merge process for file path `dfile`"""
427 427 if self[dfile] in 'rd':
428 428 return True, 0
429 429 stateentry = self._state[dfile]
430 430 state, hash, lfile, afile, anode, ofile, onode, flags = stateentry
431 431 octx = self._repo[self._other]
432 432 fcd = self._filectxorabsent(hash, wctx, dfile)
433 433 fco = self._filectxorabsent(onode, octx, ofile)
434 434 # TODO: move this to filectxorabsent
435 435 fca = self._repo.filectx(afile, fileid=anode)
436 436 # "premerge" x flags
437 437 flo = fco.flags()
438 438 fla = fca.flags()
439 439 if 'x' in flags + flo + fla and 'l' not in flags + flo + fla:
440 440 if fca.node() == nullid:
441 441 if preresolve:
442 442 self._repo.ui.warn(
443 443 _('warning: cannot merge flags for %s\n') % afile)
444 444 elif flags == fla:
445 445 flags = flo
446 446 if preresolve:
447 447 # restore local
448 448 if hash != nullhex:
449 449 f = self._repo.vfs('merge/' + hash)
450 450 self._repo.wwrite(dfile, f.read(), flags)
451 451 f.close()
452 452 else:
453 453 self._repo.wvfs.unlinkpath(dfile, ignoremissing=True)
454 454 complete, r, deleted = filemerge.premerge(self._repo, self._local,
455 455 lfile, fcd, fco, fca,
456 456 labels=labels)
457 457 else:
458 458 complete, r, deleted = filemerge.filemerge(self._repo, self._local,
459 459 lfile, fcd, fco, fca,
460 460 labels=labels)
461 461 if r is None:
462 462 # no real conflict
463 463 del self._state[dfile]
464 464 self._dirty = True
465 465 elif not r:
466 466 self.mark(dfile, 'r')
467 467
468 468 if complete:
469 469 action = None
470 470 if deleted:
471 471 if fcd.isabsent():
472 472 # dc: local picked. Need to drop if present, which may
473 473 # happen on re-resolves.
474 474 action = 'f'
475 475 else:
476 476 # cd: remote picked (or otherwise deleted)
477 477 action = 'r'
478 478 else:
479 479 if fcd.isabsent(): # dc: remote picked
480 480 action = 'g'
481 481 elif fco.isabsent(): # cd: local picked
482 482 if dfile in self.localctx:
483 483 action = 'am'
484 484 else:
485 485 action = 'a'
486 486 # else: regular merges (no action necessary)
487 487 self._results[dfile] = r, action
488 488
489 489 return complete, r
490 490
491 491 def _filectxorabsent(self, hexnode, ctx, f):
492 492 if hexnode == nullhex:
493 493 return filemerge.absentfilectx(ctx, f)
494 494 else:
495 495 return ctx[f]
496 496
497 497 def preresolve(self, dfile, wctx, labels=None):
498 498 """run premerge process for dfile
499 499
500 500 Returns whether the merge is complete, and the exit code."""
501 501 return self._resolve(True, dfile, wctx, labels=labels)
502 502
503 503 def resolve(self, dfile, wctx, labels=None):
504 504 """run merge process (assuming premerge was run) for dfile
505 505
506 506 Returns the exit code of the merge."""
507 507 return self._resolve(False, dfile, wctx, labels=labels)[1]
508 508
509 509 def counts(self):
510 510 """return counts for updated, merged and removed files in this
511 511 session"""
512 512 updated, merged, removed = 0, 0, 0
513 513 for r, action in self._results.itervalues():
514 514 if r is None:
515 515 updated += 1
516 516 elif r == 0:
517 517 if action == 'r':
518 518 removed += 1
519 519 else:
520 520 merged += 1
521 521 return updated, merged, removed
522 522
523 523 def unresolvedcount(self):
524 524 """get unresolved count for this merge (persistent)"""
525 525 return len([True for f, entry in self._state.iteritems()
526 526 if entry[0] == 'u'])
527 527
528 528 def actions(self):
529 529 """return lists of actions to perform on the dirstate"""
530 530 actions = {'r': [], 'f': [], 'a': [], 'am': [], 'g': []}
531 531 for f, (r, action) in self._results.iteritems():
532 532 if action is not None:
533 533 actions[action].append((f, None, "merge result"))
534 534 return actions
535 535
536 536 def recordactions(self):
537 537 """record remove/add/get actions in the dirstate"""
538 538 branchmerge = self._repo.dirstate.p2() != nullid
539 539 recordupdates(self._repo, self.actions(), branchmerge)
540 540
541 541 def queueremove(self, f):
542 542 """queues a file to be removed from the dirstate
543 543
544 544 Meant for use by custom merge drivers."""
545 545 self._results[f] = 0, 'r'
546 546
547 547 def queueadd(self, f):
548 548 """queues a file to be added to the dirstate
549 549
550 550 Meant for use by custom merge drivers."""
551 551 self._results[f] = 0, 'a'
552 552
553 553 def queueget(self, f):
554 554 """queues a file to be marked modified in the dirstate
555 555
556 556 Meant for use by custom merge drivers."""
557 557 self._results[f] = 0, 'g'
558 558
559 559 def _checkunknownfile(repo, wctx, mctx, f, f2=None):
560 560 if f2 is None:
561 561 f2 = f
562 562 return (repo.wvfs.isfileorlink(f)
563 563 and repo.wvfs.audit.check(f)
564 564 and repo.dirstate.normalize(f) not in repo.dirstate
565 565 and mctx[f2].cmp(wctx[f]))
566 566
567 567 def _checkunknownfiles(repo, wctx, mctx, force, actions):
568 568 """
569 569 Considers any actions that care about the presence of conflicting unknown
570 570 files. For some actions, the result is to abort; for others, it is to
571 571 choose a different action.
572 572 """
573 conflicts = []
573 conflicts = set()
574 574 if not force:
575 575 for f, (m, args, msg) in actions.iteritems():
576 576 if m in ('c', 'dc'):
577 577 if _checkunknownfile(repo, wctx, mctx, f):
578 conflicts.append(f)
578 conflicts.add(f)
579 579 elif m == 'dg':
580 580 if _checkunknownfile(repo, wctx, mctx, f, args[0]):
581 conflicts.append(f)
581 conflicts.add(f)
582 582
583 583 for f in sorted(conflicts):
584 584 repo.ui.warn(_("%s: untracked file differs\n") % f)
585 585 if conflicts:
586 586 raise error.Abort(_("untracked files in working directory differ "
587 587 "from files in requested revision"))
588 588
589 589 for f, (m, args, msg) in actions.iteritems():
590 590 if m == 'c':
591 591 actions[f] = ('g', args, msg)
592 592 elif m == 'cm':
593 593 fl2, anc = args
594 594 different = _checkunknownfile(repo, wctx, mctx, f)
595 595 if different:
596 596 actions[f] = ('m', (f, f, None, False, anc),
597 597 "remote differs from untracked local")
598 598 else:
599 599 actions[f] = ('g', (fl2,), "remote created")
600 600
601 601 def _forgetremoved(wctx, mctx, branchmerge):
602 602 """
603 603 Forget removed files
604 604
605 605 If we're jumping between revisions (as opposed to merging), and if
606 606 neither the working directory nor the target rev has the file,
607 607 then we need to remove it from the dirstate, to prevent the
608 608 dirstate from listing the file when it is no longer in the
609 609 manifest.
610 610
611 611 If we're merging, and the other revision has removed a file
612 612 that is not present in the working directory, we need to mark it
613 613 as removed.
614 614 """
615 615
616 616 actions = {}
617 617 m = 'f'
618 618 if branchmerge:
619 619 m = 'r'
620 620 for f in wctx.deleted():
621 621 if f not in mctx:
622 622 actions[f] = m, None, "forget deleted"
623 623
624 624 if not branchmerge:
625 625 for f in wctx.removed():
626 626 if f not in mctx:
627 627 actions[f] = 'f', None, "forget removed"
628 628
629 629 return actions
630 630
631 631 def _checkcollision(repo, wmf, actions):
632 632 # build provisional merged manifest up
633 633 pmmf = set(wmf)
634 634
635 635 if actions:
636 636 # k, dr, e and rd are no-op
637 637 for m in 'a', 'am', 'f', 'g', 'cd', 'dc':
638 638 for f, args, msg in actions[m]:
639 639 pmmf.add(f)
640 640 for f, args, msg in actions['r']:
641 641 pmmf.discard(f)
642 642 for f, args, msg in actions['dm']:
643 643 f2, flags = args
644 644 pmmf.discard(f2)
645 645 pmmf.add(f)
646 646 for f, args, msg in actions['dg']:
647 647 pmmf.add(f)
648 648 for f, args, msg in actions['m']:
649 649 f1, f2, fa, move, anc = args
650 650 if move:
651 651 pmmf.discard(f1)
652 652 pmmf.add(f)
653 653
654 654 # check case-folding collision in provisional merged manifest
655 655 foldmap = {}
656 656 for f in sorted(pmmf):
657 657 fold = util.normcase(f)
658 658 if fold in foldmap:
659 659 raise error.Abort(_("case-folding collision between %s and %s")
660 660 % (f, foldmap[fold]))
661 661 foldmap[fold] = f
662 662
663 663 # check case-folding of directories
664 664 foldprefix = unfoldprefix = lastfull = ''
665 665 for fold, f in sorted(foldmap.items()):
666 666 if fold.startswith(foldprefix) and not f.startswith(unfoldprefix):
667 667 # the folded prefix matches but actual casing is different
668 668 raise error.Abort(_("case-folding collision between "
669 669 "%s and directory of %s") % (lastfull, f))
670 670 foldprefix = fold + '/'
671 671 unfoldprefix = f + '/'
672 672 lastfull = f
673 673
674 674 def driverpreprocess(repo, ms, wctx, labels=None):
675 675 """run the preprocess step of the merge driver, if any
676 676
677 677 This is currently not implemented -- it's an extension point."""
678 678 return True
679 679
680 680 def driverconclude(repo, ms, wctx, labels=None):
681 681 """run the conclude step of the merge driver, if any
682 682
683 683 This is currently not implemented -- it's an extension point."""
684 684 return True
685 685
686 686 def manifestmerge(repo, wctx, p2, pa, branchmerge, force, matcher,
687 687 acceptremote, followcopies):
688 688 """
689 689 Merge p1 and p2 with ancestor pa and generate merge action list
690 690
691 691 branchmerge and force are as passed in to update
692 692 matcher = matcher to filter file lists
693 693 acceptremote = accept the incoming changes without prompting
694 694 """
695 695 if matcher is not None and matcher.always():
696 696 matcher = None
697 697
698 698 copy, movewithdir, diverge, renamedelete = {}, {}, {}, {}
699 699
700 700 # manifests fetched in order are going to be faster, so prime the caches
701 701 [x.manifest() for x in
702 702 sorted(wctx.parents() + [p2, pa], key=lambda x: x.rev())]
703 703
704 704 if followcopies:
705 705 ret = copies.mergecopies(repo, wctx, p2, pa)
706 706 copy, movewithdir, diverge, renamedelete = ret
707 707
708 708 repo.ui.note(_("resolving manifests\n"))
709 709 repo.ui.debug(" branchmerge: %s, force: %s, partial: %s\n"
710 710 % (bool(branchmerge), bool(force), bool(matcher)))
711 711 repo.ui.debug(" ancestor: %s, local: %s, remote: %s\n" % (pa, wctx, p2))
712 712
713 713 m1, m2, ma = wctx.manifest(), p2.manifest(), pa.manifest()
714 714 copied = set(copy.values())
715 715 copied.update(movewithdir.values())
716 716
717 717 if '.hgsubstate' in m1:
718 718 # check whether sub state is modified
719 719 for s in sorted(wctx.substate):
720 720 if wctx.sub(s).dirty():
721 721 m1['.hgsubstate'] += '+'
722 722 break
723 723
724 724 # Compare manifests
725 725 if matcher is not None:
726 726 m1 = m1.matches(matcher)
727 727 m2 = m2.matches(matcher)
728 728 diff = m1.diff(m2)
729 729
730 730 actions = {}
731 731 for f, ((n1, fl1), (n2, fl2)) in diff.iteritems():
732 732 if n1 and n2: # file exists on both local and remote side
733 733 if f not in ma:
734 734 fa = copy.get(f, None)
735 735 if fa is not None:
736 736 actions[f] = ('m', (f, f, fa, False, pa.node()),
737 737 "both renamed from " + fa)
738 738 else:
739 739 actions[f] = ('m', (f, f, None, False, pa.node()),
740 740 "both created")
741 741 else:
742 742 a = ma[f]
743 743 fla = ma.flags(f)
744 744 nol = 'l' not in fl1 + fl2 + fla
745 745 if n2 == a and fl2 == fla:
746 746 actions[f] = ('k' , (), "remote unchanged")
747 747 elif n1 == a and fl1 == fla: # local unchanged - use remote
748 748 if n1 == n2: # optimization: keep local content
749 749 actions[f] = ('e', (fl2,), "update permissions")
750 750 else:
751 751 actions[f] = ('g', (fl2,), "remote is newer")
752 752 elif nol and n2 == a: # remote only changed 'x'
753 753 actions[f] = ('e', (fl2,), "update permissions")
754 754 elif nol and n1 == a: # local only changed 'x'
755 755 actions[f] = ('g', (fl1,), "remote is newer")
756 756 else: # both changed something
757 757 actions[f] = ('m', (f, f, f, False, pa.node()),
758 758 "versions differ")
759 759 elif n1: # file exists only on local side
760 760 if f in copied:
761 761 pass # we'll deal with it on m2 side
762 762 elif f in movewithdir: # directory rename, move local
763 763 f2 = movewithdir[f]
764 764 if f2 in m2:
765 765 actions[f2] = ('m', (f, f2, None, True, pa.node()),
766 766 "remote directory rename, both created")
767 767 else:
768 768 actions[f2] = ('dm', (f, fl1),
769 769 "remote directory rename - move from " + f)
770 770 elif f in copy:
771 771 f2 = copy[f]
772 772 actions[f] = ('m', (f, f2, f2, False, pa.node()),
773 773 "local copied/moved from " + f2)
774 774 elif f in ma: # clean, a different, no remote
775 775 if n1 != ma[f]:
776 776 if acceptremote:
777 777 actions[f] = ('r', None, "remote delete")
778 778 else:
779 779 actions[f] = ('cd', (f, None, f, False, pa.node()),
780 780 "prompt changed/deleted")
781 781 elif n1[20:] == 'a':
782 782 # This extra 'a' is added by working copy manifest to mark
783 783 # the file as locally added. We should forget it instead of
784 784 # deleting it.
785 785 actions[f] = ('f', None, "remote deleted")
786 786 else:
787 787 actions[f] = ('r', None, "other deleted")
788 788 elif n2: # file exists only on remote side
789 789 if f in copied:
790 790 pass # we'll deal with it on m1 side
791 791 elif f in movewithdir:
792 792 f2 = movewithdir[f]
793 793 if f2 in m1:
794 794 actions[f2] = ('m', (f2, f, None, False, pa.node()),
795 795 "local directory rename, both created")
796 796 else:
797 797 actions[f2] = ('dg', (f, fl2),
798 798 "local directory rename - get from " + f)
799 799 elif f in copy:
800 800 f2 = copy[f]
801 801 if f2 in m2:
802 802 actions[f] = ('m', (f2, f, f2, False, pa.node()),
803 803 "remote copied from " + f2)
804 804 else:
805 805 actions[f] = ('m', (f2, f, f2, True, pa.node()),
806 806 "remote moved from " + f2)
807 807 elif f not in ma:
808 808 # local unknown, remote created: the logic is described by the
809 809 # following table:
810 810 #
811 811 # force branchmerge different | action
812 812 # n * * | create
813 813 # y n * | create
814 814 # y y n | create
815 815 # y y y | merge
816 816 #
817 817 # Checking whether the files are different is expensive, so we
818 818 # don't do that when we can avoid it.
819 819 if not force:
820 820 actions[f] = ('c', (fl2,), "remote created")
821 821 elif not branchmerge:
822 822 actions[f] = ('c', (fl2,), "remote created")
823 823 else:
824 824 actions[f] = ('cm', (fl2, pa.node()),
825 825 "remote created, get or merge")
826 826 elif n2 != ma[f]:
827 827 if acceptremote:
828 828 actions[f] = ('c', (fl2,), "remote recreating")
829 829 else:
830 830 actions[f] = ('dc', (None, f, f, False, pa.node()),
831 831 "prompt deleted/changed")
832 832
833 833 return actions, diverge, renamedelete
834 834
835 835 def _resolvetrivial(repo, wctx, mctx, ancestor, actions):
836 836 """Resolves false conflicts where the nodeid changed but the content
837 837 remained the same."""
838 838
839 839 for f, (m, args, msg) in actions.items():
840 840 if m == 'cd' and f in ancestor and not wctx[f].cmp(ancestor[f]):
841 841 # local did change but ended up with same content
842 842 actions[f] = 'r', None, "prompt same"
843 843 elif m == 'dc' and f in ancestor and not mctx[f].cmp(ancestor[f]):
844 844 # remote did change but ended up with same content
845 845 del actions[f] # don't get = keep local deleted
846 846
847 847 def calculateupdates(repo, wctx, mctx, ancestors, branchmerge, force,
848 848 acceptremote, followcopies, matcher=None):
849 849 "Calculate the actions needed to merge mctx into wctx using ancestors"
850 850 if len(ancestors) == 1: # default
851 851 actions, diverge, renamedelete = manifestmerge(
852 852 repo, wctx, mctx, ancestors[0], branchmerge, force, matcher,
853 853 acceptremote, followcopies)
854 854 _checkunknownfiles(repo, wctx, mctx, force, actions)
855 855
856 856 else: # only when merge.preferancestor=* - the default
857 857 repo.ui.note(
858 858 _("note: merging %s and %s using bids from ancestors %s\n") %
859 859 (wctx, mctx, _(' and ').join(str(anc) for anc in ancestors)))
860 860
861 861 # Call for bids
862 862 fbids = {} # mapping filename to bids (action method to list af actions)
863 863 diverge, renamedelete = None, None
864 864 for ancestor in ancestors:
865 865 repo.ui.note(_('\ncalculating bids for ancestor %s\n') % ancestor)
866 866 actions, diverge1, renamedelete1 = manifestmerge(
867 867 repo, wctx, mctx, ancestor, branchmerge, force, matcher,
868 868 acceptremote, followcopies)
869 869 _checkunknownfiles(repo, wctx, mctx, force, actions)
870 870
871 871 # Track the shortest set of warning on the theory that bid
872 872 # merge will correctly incorporate more information
873 873 if diverge is None or len(diverge1) < len(diverge):
874 874 diverge = diverge1
875 875 if renamedelete is None or len(renamedelete) < len(renamedelete1):
876 876 renamedelete = renamedelete1
877 877
878 878 for f, a in sorted(actions.iteritems()):
879 879 m, args, msg = a
880 880 repo.ui.debug(' %s: %s -> %s\n' % (f, msg, m))
881 881 if f in fbids:
882 882 d = fbids[f]
883 883 if m in d:
884 884 d[m].append(a)
885 885 else:
886 886 d[m] = [a]
887 887 else:
888 888 fbids[f] = {m: [a]}
889 889
890 890 # Pick the best bid for each file
891 891 repo.ui.note(_('\nauction for merging merge bids\n'))
892 892 actions = {}
893 893 for f, bids in sorted(fbids.items()):
894 894 # bids is a mapping from action method to list af actions
895 895 # Consensus?
896 896 if len(bids) == 1: # all bids are the same kind of method
897 897 m, l = bids.items()[0]
898 898 if all(a == l[0] for a in l[1:]): # len(bids) is > 1
899 899 repo.ui.note(" %s: consensus for %s\n" % (f, m))
900 900 actions[f] = l[0]
901 901 continue
902 902 # If keep is an option, just do it.
903 903 if 'k' in bids:
904 904 repo.ui.note(" %s: picking 'keep' action\n" % f)
905 905 actions[f] = bids['k'][0]
906 906 continue
907 907 # If there are gets and they all agree [how could they not?], do it.
908 908 if 'g' in bids:
909 909 ga0 = bids['g'][0]
910 910 if all(a == ga0 for a in bids['g'][1:]):
911 911 repo.ui.note(" %s: picking 'get' action\n" % f)
912 912 actions[f] = ga0
913 913 continue
914 914 # TODO: Consider other simple actions such as mode changes
915 915 # Handle inefficient democrazy.
916 916 repo.ui.note(_(' %s: multiple bids for merge action:\n') % f)
917 917 for m, l in sorted(bids.items()):
918 918 for _f, args, msg in l:
919 919 repo.ui.note(' %s -> %s\n' % (msg, m))
920 920 # Pick random action. TODO: Instead, prompt user when resolving
921 921 m, l = bids.items()[0]
922 922 repo.ui.warn(_(' %s: ambiguous merge - picked %s action\n') %
923 923 (f, m))
924 924 actions[f] = l[0]
925 925 continue
926 926 repo.ui.note(_('end of auction\n\n'))
927 927
928 928 _resolvetrivial(repo, wctx, mctx, ancestors[0], actions)
929 929
930 930 if wctx.rev() is None:
931 931 fractions = _forgetremoved(wctx, mctx, branchmerge)
932 932 actions.update(fractions)
933 933
934 934 return actions, diverge, renamedelete
935 935
936 936 def batchremove(repo, actions):
937 937 """apply removes to the working directory
938 938
939 939 yields tuples for progress updates
940 940 """
941 941 verbose = repo.ui.verbose
942 942 unlink = util.unlinkpath
943 943 wjoin = repo.wjoin
944 944 audit = repo.wvfs.audit
945 945 i = 0
946 946 for f, args, msg in actions:
947 947 repo.ui.debug(" %s: %s -> r\n" % (f, msg))
948 948 if verbose:
949 949 repo.ui.note(_("removing %s\n") % f)
950 950 audit(f)
951 951 try:
952 952 unlink(wjoin(f), ignoremissing=True)
953 953 except OSError as inst:
954 954 repo.ui.warn(_("update failed to remove %s: %s!\n") %
955 955 (f, inst.strerror))
956 956 if i == 100:
957 957 yield i, f
958 958 i = 0
959 959 i += 1
960 960 if i > 0:
961 961 yield i, f
962 962
963 963 def batchget(repo, mctx, actions):
964 964 """apply gets to the working directory
965 965
966 966 mctx is the context to get from
967 967
968 968 yields tuples for progress updates
969 969 """
970 970 verbose = repo.ui.verbose
971 971 fctx = mctx.filectx
972 972 wwrite = repo.wwrite
973 973 i = 0
974 974 for f, args, msg in actions:
975 975 repo.ui.debug(" %s: %s -> g\n" % (f, msg))
976 976 if verbose:
977 977 repo.ui.note(_("getting %s\n") % f)
978 978 wwrite(f, fctx(f).data(), args[0])
979 979 if i == 100:
980 980 yield i, f
981 981 i = 0
982 982 i += 1
983 983 if i > 0:
984 984 yield i, f
985 985
986 986 def applyupdates(repo, actions, wctx, mctx, overwrite, labels=None):
987 987 """apply the merge action list to the working directory
988 988
989 989 wctx is the working copy context
990 990 mctx is the context to be merged into the working copy
991 991
992 992 Return a tuple of counts (updated, merged, removed, unresolved) that
993 993 describes how many files were affected by the update.
994 994 """
995 995
996 996 updated, merged, removed = 0, 0, 0
997 997 ms = mergestate.clean(repo, wctx.p1().node(), mctx.node())
998 998 moves = []
999 999 for m, l in actions.items():
1000 1000 l.sort()
1001 1001
1002 1002 # 'cd' and 'dc' actions are treated like other merge conflicts
1003 1003 mergeactions = sorted(actions['cd'])
1004 1004 mergeactions.extend(sorted(actions['dc']))
1005 1005 mergeactions.extend(actions['m'])
1006 1006 for f, args, msg in mergeactions:
1007 1007 f1, f2, fa, move, anc = args
1008 1008 if f == '.hgsubstate': # merged internally
1009 1009 continue
1010 1010 if f1 is None:
1011 1011 fcl = filemerge.absentfilectx(wctx, fa)
1012 1012 else:
1013 1013 repo.ui.debug(" preserving %s for resolve of %s\n" % (f1, f))
1014 1014 fcl = wctx[f1]
1015 1015 if f2 is None:
1016 1016 fco = filemerge.absentfilectx(mctx, fa)
1017 1017 else:
1018 1018 fco = mctx[f2]
1019 1019 actx = repo[anc]
1020 1020 if fa in actx:
1021 1021 fca = actx[fa]
1022 1022 else:
1023 1023 # TODO: move to absentfilectx
1024 1024 fca = repo.filectx(f1, fileid=nullrev)
1025 1025 ms.add(fcl, fco, fca, f)
1026 1026 if f1 != f and move:
1027 1027 moves.append(f1)
1028 1028
1029 1029 audit = repo.wvfs.audit
1030 1030 _updating = _('updating')
1031 1031 _files = _('files')
1032 1032 progress = repo.ui.progress
1033 1033
1034 1034 # remove renamed files after safely stored
1035 1035 for f in moves:
1036 1036 if os.path.lexists(repo.wjoin(f)):
1037 1037 repo.ui.debug("removing %s\n" % f)
1038 1038 audit(f)
1039 1039 util.unlinkpath(repo.wjoin(f))
1040 1040
1041 1041 numupdates = sum(len(l) for m, l in actions.items() if m != 'k')
1042 1042
1043 1043 if [a for a in actions['r'] if a[0] == '.hgsubstate']:
1044 1044 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
1045 1045
1046 1046 # remove in parallel (must come first)
1047 1047 z = 0
1048 1048 prog = worker.worker(repo.ui, 0.001, batchremove, (repo,), actions['r'])
1049 1049 for i, item in prog:
1050 1050 z += i
1051 1051 progress(_updating, z, item=item, total=numupdates, unit=_files)
1052 1052 removed = len(actions['r'])
1053 1053
1054 1054 # get in parallel
1055 1055 prog = worker.worker(repo.ui, 0.001, batchget, (repo, mctx), actions['g'])
1056 1056 for i, item in prog:
1057 1057 z += i
1058 1058 progress(_updating, z, item=item, total=numupdates, unit=_files)
1059 1059 updated = len(actions['g'])
1060 1060
1061 1061 if [a for a in actions['g'] if a[0] == '.hgsubstate']:
1062 1062 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
1063 1063
1064 1064 # forget (manifest only, just log it) (must come first)
1065 1065 for f, args, msg in actions['f']:
1066 1066 repo.ui.debug(" %s: %s -> f\n" % (f, msg))
1067 1067 z += 1
1068 1068 progress(_updating, z, item=f, total=numupdates, unit=_files)
1069 1069
1070 1070 # re-add (manifest only, just log it)
1071 1071 for f, args, msg in actions['a']:
1072 1072 repo.ui.debug(" %s: %s -> a\n" % (f, msg))
1073 1073 z += 1
1074 1074 progress(_updating, z, item=f, total=numupdates, unit=_files)
1075 1075
1076 1076 # re-add/mark as modified (manifest only, just log it)
1077 1077 for f, args, msg in actions['am']:
1078 1078 repo.ui.debug(" %s: %s -> am\n" % (f, msg))
1079 1079 z += 1
1080 1080 progress(_updating, z, item=f, total=numupdates, unit=_files)
1081 1081
1082 1082 # keep (noop, just log it)
1083 1083 for f, args, msg in actions['k']:
1084 1084 repo.ui.debug(" %s: %s -> k\n" % (f, msg))
1085 1085 # no progress
1086 1086
1087 1087 # directory rename, move local
1088 1088 for f, args, msg in actions['dm']:
1089 1089 repo.ui.debug(" %s: %s -> dm\n" % (f, msg))
1090 1090 z += 1
1091 1091 progress(_updating, z, item=f, total=numupdates, unit=_files)
1092 1092 f0, flags = args
1093 1093 repo.ui.note(_("moving %s to %s\n") % (f0, f))
1094 1094 audit(f)
1095 1095 repo.wwrite(f, wctx.filectx(f0).data(), flags)
1096 1096 util.unlinkpath(repo.wjoin(f0))
1097 1097 updated += 1
1098 1098
1099 1099 # local directory rename, get
1100 1100 for f, args, msg in actions['dg']:
1101 1101 repo.ui.debug(" %s: %s -> dg\n" % (f, msg))
1102 1102 z += 1
1103 1103 progress(_updating, z, item=f, total=numupdates, unit=_files)
1104 1104 f0, flags = args
1105 1105 repo.ui.note(_("getting %s to %s\n") % (f0, f))
1106 1106 repo.wwrite(f, mctx.filectx(f0).data(), flags)
1107 1107 updated += 1
1108 1108
1109 1109 # exec
1110 1110 for f, args, msg in actions['e']:
1111 1111 repo.ui.debug(" %s: %s -> e\n" % (f, msg))
1112 1112 z += 1
1113 1113 progress(_updating, z, item=f, total=numupdates, unit=_files)
1114 1114 flags, = args
1115 1115 audit(f)
1116 1116 util.setflags(repo.wjoin(f), 'l' in flags, 'x' in flags)
1117 1117 updated += 1
1118 1118
1119 1119 # the ordering is important here -- ms.mergedriver will raise if the merge
1120 1120 # driver has changed, and we want to be able to bypass it when overwrite is
1121 1121 # True
1122 1122 usemergedriver = not overwrite and mergeactions and ms.mergedriver
1123 1123
1124 1124 if usemergedriver:
1125 1125 ms.commit()
1126 1126 proceed = driverpreprocess(repo, ms, wctx, labels=labels)
1127 1127 # the driver might leave some files unresolved
1128 1128 unresolvedf = set(ms.unresolved())
1129 1129 if not proceed:
1130 1130 # XXX setting unresolved to at least 1 is a hack to make sure we
1131 1131 # error out
1132 1132 return updated, merged, removed, max(len(unresolvedf), 1)
1133 1133 newactions = []
1134 1134 for f, args, msg in mergeactions:
1135 1135 if f in unresolvedf:
1136 1136 newactions.append((f, args, msg))
1137 1137 mergeactions = newactions
1138 1138
1139 1139 # premerge
1140 1140 tocomplete = []
1141 1141 for f, args, msg in mergeactions:
1142 1142 repo.ui.debug(" %s: %s -> m (premerge)\n" % (f, msg))
1143 1143 z += 1
1144 1144 progress(_updating, z, item=f, total=numupdates, unit=_files)
1145 1145 if f == '.hgsubstate': # subrepo states need updating
1146 1146 subrepo.submerge(repo, wctx, mctx, wctx.ancestor(mctx),
1147 1147 overwrite)
1148 1148 continue
1149 1149 audit(f)
1150 1150 complete, r = ms.preresolve(f, wctx, labels=labels)
1151 1151 if not complete:
1152 1152 numupdates += 1
1153 1153 tocomplete.append((f, args, msg))
1154 1154
1155 1155 # merge
1156 1156 for f, args, msg in tocomplete:
1157 1157 repo.ui.debug(" %s: %s -> m (merge)\n" % (f, msg))
1158 1158 z += 1
1159 1159 progress(_updating, z, item=f, total=numupdates, unit=_files)
1160 1160 ms.resolve(f, wctx, labels=labels)
1161 1161
1162 1162 ms.commit()
1163 1163
1164 1164 unresolved = ms.unresolvedcount()
1165 1165
1166 1166 if usemergedriver and not unresolved and ms.mdstate() != 's':
1167 1167 if not driverconclude(repo, ms, wctx, labels=labels):
1168 1168 # XXX setting unresolved to at least 1 is a hack to make sure we
1169 1169 # error out
1170 1170 unresolved = max(unresolved, 1)
1171 1171
1172 1172 ms.commit()
1173 1173
1174 1174 msupdated, msmerged, msremoved = ms.counts()
1175 1175 updated += msupdated
1176 1176 merged += msmerged
1177 1177 removed += msremoved
1178 1178
1179 1179 extraactions = ms.actions()
1180 1180 for k, acts in extraactions.iteritems():
1181 1181 actions[k].extend(acts)
1182 1182
1183 1183 progress(_updating, None, total=numupdates, unit=_files)
1184 1184
1185 1185 return updated, merged, removed, unresolved
1186 1186
1187 1187 def recordupdates(repo, actions, branchmerge):
1188 1188 "record merge actions to the dirstate"
1189 1189 # remove (must come first)
1190 1190 for f, args, msg in actions.get('r', []):
1191 1191 if branchmerge:
1192 1192 repo.dirstate.remove(f)
1193 1193 else:
1194 1194 repo.dirstate.drop(f)
1195 1195
1196 1196 # forget (must come first)
1197 1197 for f, args, msg in actions.get('f', []):
1198 1198 repo.dirstate.drop(f)
1199 1199
1200 1200 # re-add
1201 1201 for f, args, msg in actions.get('a', []):
1202 1202 repo.dirstate.add(f)
1203 1203
1204 1204 # re-add/mark as modified
1205 1205 for f, args, msg in actions.get('am', []):
1206 1206 if branchmerge:
1207 1207 repo.dirstate.normallookup(f)
1208 1208 else:
1209 1209 repo.dirstate.add(f)
1210 1210
1211 1211 # exec change
1212 1212 for f, args, msg in actions.get('e', []):
1213 1213 repo.dirstate.normallookup(f)
1214 1214
1215 1215 # keep
1216 1216 for f, args, msg in actions.get('k', []):
1217 1217 pass
1218 1218
1219 1219 # get
1220 1220 for f, args, msg in actions.get('g', []):
1221 1221 if branchmerge:
1222 1222 repo.dirstate.otherparent(f)
1223 1223 else:
1224 1224 repo.dirstate.normal(f)
1225 1225
1226 1226 # merge
1227 1227 for f, args, msg in actions.get('m', []):
1228 1228 f1, f2, fa, move, anc = args
1229 1229 if branchmerge:
1230 1230 # We've done a branch merge, mark this file as merged
1231 1231 # so that we properly record the merger later
1232 1232 repo.dirstate.merge(f)
1233 1233 if f1 != f2: # copy/rename
1234 1234 if move:
1235 1235 repo.dirstate.remove(f1)
1236 1236 if f1 != f:
1237 1237 repo.dirstate.copy(f1, f)
1238 1238 else:
1239 1239 repo.dirstate.copy(f2, f)
1240 1240 else:
1241 1241 # We've update-merged a locally modified file, so
1242 1242 # we set the dirstate to emulate a normal checkout
1243 1243 # of that file some time in the past. Thus our
1244 1244 # merge will appear as a normal local file
1245 1245 # modification.
1246 1246 if f2 == f: # file not locally copied/moved
1247 1247 repo.dirstate.normallookup(f)
1248 1248 if move:
1249 1249 repo.dirstate.drop(f1)
1250 1250
1251 1251 # directory rename, move local
1252 1252 for f, args, msg in actions.get('dm', []):
1253 1253 f0, flag = args
1254 1254 if branchmerge:
1255 1255 repo.dirstate.add(f)
1256 1256 repo.dirstate.remove(f0)
1257 1257 repo.dirstate.copy(f0, f)
1258 1258 else:
1259 1259 repo.dirstate.normal(f)
1260 1260 repo.dirstate.drop(f0)
1261 1261
1262 1262 # directory rename, get
1263 1263 for f, args, msg in actions.get('dg', []):
1264 1264 f0, flag = args
1265 1265 if branchmerge:
1266 1266 repo.dirstate.add(f)
1267 1267 repo.dirstate.copy(f0, f)
1268 1268 else:
1269 1269 repo.dirstate.normal(f)
1270 1270
1271 1271 def update(repo, node, branchmerge, force, ancestor=None,
1272 1272 mergeancestor=False, labels=None, matcher=None):
1273 1273 """
1274 1274 Perform a merge between the working directory and the given node
1275 1275
1276 1276 node = the node to update to, or None if unspecified
1277 1277 branchmerge = whether to merge between branches
1278 1278 force = whether to force branch merging or file overwriting
1279 1279 matcher = a matcher to filter file lists (dirstate not updated)
1280 1280 mergeancestor = whether it is merging with an ancestor. If true,
1281 1281 we should accept the incoming changes for any prompts that occur.
1282 1282 If false, merging with an ancestor (fast-forward) is only allowed
1283 1283 between different named branches. This flag is used by rebase extension
1284 1284 as a temporary fix and should be avoided in general.
1285 1285
1286 1286 The table below shows all the behaviors of the update command
1287 1287 given the -c and -C or no options, whether the working directory
1288 1288 is dirty, whether a revision is specified, and the relationship of
1289 1289 the parent rev to the target rev (linear, on the same named
1290 1290 branch, or on another named branch).
1291 1291
1292 1292 This logic is tested by test-update-branches.t.
1293 1293
1294 1294 -c -C dirty rev | linear same cross
1295 1295 n n n n | ok (1) x
1296 1296 n n n y | ok ok ok
1297 1297 n n y n | merge (2) (2)
1298 1298 n n y y | merge (3) (3)
1299 1299 n y * * | discard discard discard
1300 1300 y n y * | (4) (4) (4)
1301 1301 y n n * | ok ok ok
1302 1302 y y * * | (5) (5) (5)
1303 1303
1304 1304 x = can't happen
1305 1305 * = don't-care
1306 1306 1 = abort: not a linear update (merge or update --check to force update)
1307 1307 2 = abort: uncommitted changes (commit and merge, or update --clean to
1308 1308 discard changes)
1309 1309 3 = abort: uncommitted changes (commit or update --clean to discard changes)
1310 1310 4 = abort: uncommitted changes (checked in commands.py)
1311 1311 5 = incompatible options (checked in commands.py)
1312 1312
1313 1313 Return the same tuple as applyupdates().
1314 1314 """
1315 1315
1316 1316 onode = node
1317 1317 wlock = repo.wlock()
1318 1318 # If we're doing a partial update, we need to skip updating
1319 1319 # the dirstate, so make a note of any partial-ness to the
1320 1320 # update here.
1321 1321 if matcher is None or matcher.always():
1322 1322 partial = False
1323 1323 else:
1324 1324 partial = True
1325 1325 try:
1326 1326 wc = repo[None]
1327 1327 pl = wc.parents()
1328 1328 p1 = pl[0]
1329 1329 pas = [None]
1330 1330 if ancestor is not None:
1331 1331 pas = [repo[ancestor]]
1332 1332
1333 1333 if node is None:
1334 1334 if (repo.ui.configbool('devel', 'all-warnings')
1335 1335 or repo.ui.configbool('devel', 'oldapi')):
1336 1336 repo.ui.develwarn('update with no target')
1337 1337 rev, _mark, _act = destutil.destupdate(repo)
1338 1338 node = repo[rev].node()
1339 1339
1340 1340 overwrite = force and not branchmerge
1341 1341
1342 1342 p2 = repo[node]
1343 1343 if pas[0] is None:
1344 1344 if repo.ui.configlist('merge', 'preferancestor', ['*']) == ['*']:
1345 1345 cahs = repo.changelog.commonancestorsheads(p1.node(), p2.node())
1346 1346 pas = [repo[anc] for anc in (sorted(cahs) or [nullid])]
1347 1347 else:
1348 1348 pas = [p1.ancestor(p2, warn=branchmerge)]
1349 1349
1350 1350 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2)
1351 1351
1352 1352 ### check phase
1353 1353 if not overwrite:
1354 1354 if len(pl) > 1:
1355 1355 raise error.Abort(_("outstanding uncommitted merge"))
1356 1356 ms = mergestate.read(repo)
1357 1357 if list(ms.unresolved()):
1358 1358 raise error.Abort(_("outstanding merge conflicts"))
1359 1359 if branchmerge:
1360 1360 if pas == [p2]:
1361 1361 raise error.Abort(_("merging with a working directory ancestor"
1362 1362 " has no effect"))
1363 1363 elif pas == [p1]:
1364 1364 if not mergeancestor and p1.branch() == p2.branch():
1365 1365 raise error.Abort(_("nothing to merge"),
1366 1366 hint=_("use 'hg update' "
1367 1367 "or check 'hg heads'"))
1368 1368 if not force and (wc.files() or wc.deleted()):
1369 1369 raise error.Abort(_("uncommitted changes"),
1370 1370 hint=_("use 'hg status' to list changes"))
1371 1371 for s in sorted(wc.substate):
1372 1372 wc.sub(s).bailifchanged()
1373 1373
1374 1374 elif not overwrite:
1375 1375 if p1 == p2: # no-op update
1376 1376 # call the hooks and exit early
1377 1377 repo.hook('preupdate', throw=True, parent1=xp2, parent2='')
1378 1378 repo.hook('update', parent1=xp2, parent2='', error=0)
1379 1379 return 0, 0, 0, 0
1380 1380
1381 1381 if pas not in ([p1], [p2]): # nonlinear
1382 1382 dirty = wc.dirty(missing=True)
1383 1383 if dirty or onode is None:
1384 1384 # Branching is a bit strange to ensure we do the minimal
1385 1385 # amount of call to obsolete.background.
1386 1386 foreground = obsolete.foreground(repo, [p1.node()])
1387 1387 # note: the <node> variable contains a random identifier
1388 1388 if repo[node].node() in foreground:
1389 1389 pas = [p1] # allow updating to successors
1390 1390 elif dirty:
1391 1391 msg = _("uncommitted changes")
1392 1392 if onode is None:
1393 1393 hint = _("commit and merge, or update --clean to"
1394 1394 " discard changes")
1395 1395 else:
1396 1396 hint = _("commit or update --clean to discard"
1397 1397 " changes")
1398 1398 raise error.Abort(msg, hint=hint)
1399 1399 else: # node is none
1400 1400 msg = _("not a linear update")
1401 1401 hint = _("merge or update --check to force update")
1402 1402 raise error.Abort(msg, hint=hint)
1403 1403 else:
1404 1404 # Allow jumping branches if clean and specific rev given
1405 1405 pas = [p1]
1406 1406
1407 1407 # deprecated config: merge.followcopies
1408 1408 followcopies = False
1409 1409 if overwrite:
1410 1410 pas = [wc]
1411 1411 elif pas == [p2]: # backwards
1412 1412 pas = [wc.p1()]
1413 1413 elif not branchmerge and not wc.dirty(missing=True):
1414 1414 pass
1415 1415 elif pas[0] and repo.ui.configbool('merge', 'followcopies', True):
1416 1416 followcopies = True
1417 1417
1418 1418 ### calculate phase
1419 1419 actionbyfile, diverge, renamedelete = calculateupdates(
1420 1420 repo, wc, p2, pas, branchmerge, force, mergeancestor,
1421 1421 followcopies, matcher=matcher)
1422 1422 # Convert to dictionary-of-lists format
1423 1423 actions = dict((m, []) for m in 'a am f g cd dc r dm dg m e k'.split())
1424 1424 for f, (m, args, msg) in actionbyfile.iteritems():
1425 1425 if m not in actions:
1426 1426 actions[m] = []
1427 1427 actions[m].append((f, args, msg))
1428 1428
1429 1429 if not util.checkcase(repo.path):
1430 1430 # check collision between files only in p2 for clean update
1431 1431 if (not branchmerge and
1432 1432 (force or not wc.dirty(missing=True, branch=False))):
1433 1433 _checkcollision(repo, p2.manifest(), None)
1434 1434 else:
1435 1435 _checkcollision(repo, wc.manifest(), actions)
1436 1436
1437 1437 # Prompt and create actions. Most of this is in the resolve phase
1438 1438 # already, but we can't handle .hgsubstate in filemerge or
1439 1439 # subrepo.submerge yet so we have to keep prompting for it.
1440 1440 for f, args, msg in sorted(actions['cd']):
1441 1441 if f != '.hgsubstate':
1442 1442 continue
1443 1443 if repo.ui.promptchoice(
1444 1444 _("local changed %s which remote deleted\n"
1445 1445 "use (c)hanged version or (d)elete?"
1446 1446 "$$ &Changed $$ &Delete") % f, 0):
1447 1447 actions['r'].append((f, None, "prompt delete"))
1448 1448 elif f in p1:
1449 1449 actions['am'].append((f, None, "prompt keep"))
1450 1450 else:
1451 1451 actions['a'].append((f, None, "prompt keep"))
1452 1452
1453 1453 for f, args, msg in sorted(actions['dc']):
1454 1454 if f != '.hgsubstate':
1455 1455 continue
1456 1456 f1, f2, fa, move, anc = args
1457 1457 flags = p2[f2].flags()
1458 1458 if repo.ui.promptchoice(
1459 1459 _("remote changed %s which local deleted\n"
1460 1460 "use (c)hanged version or leave (d)eleted?"
1461 1461 "$$ &Changed $$ &Deleted") % f, 0) == 0:
1462 1462 actions['g'].append((f, (flags,), "prompt recreating"))
1463 1463
1464 1464 # divergent renames
1465 1465 for f, fl in sorted(diverge.iteritems()):
1466 1466 repo.ui.warn(_("note: possible conflict - %s was renamed "
1467 1467 "multiple times to:\n") % f)
1468 1468 for nf in fl:
1469 1469 repo.ui.warn(" %s\n" % nf)
1470 1470
1471 1471 # rename and delete
1472 1472 for f, fl in sorted(renamedelete.iteritems()):
1473 1473 repo.ui.warn(_("note: possible conflict - %s was deleted "
1474 1474 "and renamed to:\n") % f)
1475 1475 for nf in fl:
1476 1476 repo.ui.warn(" %s\n" % nf)
1477 1477
1478 1478 ### apply phase
1479 1479 if not branchmerge: # just jump to the new rev
1480 1480 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
1481 1481 if not partial:
1482 1482 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
1483 1483 # note that we're in the middle of an update
1484 1484 repo.vfs.write('updatestate', p2.hex())
1485 1485
1486 1486 stats = applyupdates(repo, actions, wc, p2, overwrite, labels=labels)
1487 1487
1488 1488 if not partial:
1489 1489 repo.dirstate.beginparentchange()
1490 1490 repo.setparents(fp1, fp2)
1491 1491 recordupdates(repo, actions, branchmerge)
1492 1492 # update completed, clear state
1493 1493 util.unlink(repo.join('updatestate'))
1494 1494
1495 1495 if not branchmerge:
1496 1496 repo.dirstate.setbranch(p2.branch())
1497 1497 repo.dirstate.endparentchange()
1498 1498 finally:
1499 1499 wlock.release()
1500 1500
1501 1501 if not partial:
1502 1502 repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3])
1503 1503 return stats
1504 1504
1505 1505 def graft(repo, ctx, pctx, labels, keepparent=False):
1506 1506 """Do a graft-like merge.
1507 1507
1508 1508 This is a merge where the merge ancestor is chosen such that one
1509 1509 or more changesets are grafted onto the current changeset. In
1510 1510 addition to the merge, this fixes up the dirstate to include only
1511 1511 a single parent (if keepparent is False) and tries to duplicate any
1512 1512 renames/copies appropriately.
1513 1513
1514 1514 ctx - changeset to rebase
1515 1515 pctx - merge base, usually ctx.p1()
1516 1516 labels - merge labels eg ['local', 'graft']
1517 1517 keepparent - keep second parent if any
1518 1518
1519 1519 """
1520 1520 # If we're grafting a descendant onto an ancestor, be sure to pass
1521 1521 # mergeancestor=True to update. This does two things: 1) allows the merge if
1522 1522 # the destination is the same as the parent of the ctx (so we can use graft
1523 1523 # to copy commits), and 2) informs update that the incoming changes are
1524 1524 # newer than the destination so it doesn't prompt about "remote changed foo
1525 1525 # which local deleted".
1526 1526 mergeancestor = repo.changelog.isancestor(repo['.'].node(), ctx.node())
1527 1527
1528 1528 stats = update(repo, ctx.node(), True, True, pctx.node(),
1529 1529 mergeancestor=mergeancestor, labels=labels)
1530 1530
1531 1531 pother = nullid
1532 1532 parents = ctx.parents()
1533 1533 if keepparent and len(parents) == 2 and pctx in parents:
1534 1534 parents.remove(pctx)
1535 1535 pother = parents[0].node()
1536 1536
1537 1537 repo.dirstate.beginparentchange()
1538 1538 repo.setparents(repo['.'].node(), pother)
1539 1539 repo.dirstate.write(repo.currenttransaction())
1540 1540 # fix up dirstate for copies and renames
1541 1541 copies.duplicatecopies(repo, ctx.rev(), pctx.rev())
1542 1542 repo.dirstate.endparentchange()
1543 1543 return stats
General Comments 0
You need to be logged in to leave comments. Login now