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