##// END OF EJS Templates
mergestate: add a method to compute actions to perform on dirstate...
Siddharth Agarwal -
r27079:a88a10a9 default
parent child Browse files
Show More
@@ -1,1443 +1,1451
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 def actions(self):
513 """return lists of actions to perform on the dirstate"""
514 actions = {'r': [], 'a': [], 'g': []}
515 for f, (r, action) in self._results.iteritems():
516 if action is not None:
517 actions[action].append((f, None, "merge result"))
518 return actions
519
512 520 def _checkunknownfile(repo, wctx, mctx, f, f2=None):
513 521 if f2 is None:
514 522 f2 = f
515 523 return (os.path.isfile(repo.wjoin(f))
516 524 and repo.wvfs.audit.check(f)
517 525 and repo.dirstate.normalize(f) not in repo.dirstate
518 526 and mctx[f2].cmp(wctx[f]))
519 527
520 528 def _checkunknownfiles(repo, wctx, mctx, force, actions):
521 529 """
522 530 Considers any actions that care about the presence of conflicting unknown
523 531 files. For some actions, the result is to abort; for others, it is to
524 532 choose a different action.
525 533 """
526 534 aborts = []
527 535 if not force:
528 536 for f, (m, args, msg) in actions.iteritems():
529 537 if m in ('c', 'dc'):
530 538 if _checkunknownfile(repo, wctx, mctx, f):
531 539 aborts.append(f)
532 540 elif m == 'dg':
533 541 if _checkunknownfile(repo, wctx, mctx, f, args[0]):
534 542 aborts.append(f)
535 543
536 544 for f in sorted(aborts):
537 545 repo.ui.warn(_("%s: untracked file differs\n") % f)
538 546 if aborts:
539 547 raise error.Abort(_("untracked files in working directory differ "
540 548 "from files in requested revision"))
541 549
542 550 for f, (m, args, msg) in actions.iteritems():
543 551 if m == 'c':
544 552 actions[f] = ('g', args, msg)
545 553 elif m == 'cm':
546 554 fl2, anc = args
547 555 different = _checkunknownfile(repo, wctx, mctx, f)
548 556 if different:
549 557 actions[f] = ('m', (f, f, None, False, anc),
550 558 "remote differs from untracked local")
551 559 else:
552 560 actions[f] = ('g', (fl2,), "remote created")
553 561
554 562 def _forgetremoved(wctx, mctx, branchmerge):
555 563 """
556 564 Forget removed files
557 565
558 566 If we're jumping between revisions (as opposed to merging), and if
559 567 neither the working directory nor the target rev has the file,
560 568 then we need to remove it from the dirstate, to prevent the
561 569 dirstate from listing the file when it is no longer in the
562 570 manifest.
563 571
564 572 If we're merging, and the other revision has removed a file
565 573 that is not present in the working directory, we need to mark it
566 574 as removed.
567 575 """
568 576
569 577 actions = {}
570 578 m = 'f'
571 579 if branchmerge:
572 580 m = 'r'
573 581 for f in wctx.deleted():
574 582 if f not in mctx:
575 583 actions[f] = m, None, "forget deleted"
576 584
577 585 if not branchmerge:
578 586 for f in wctx.removed():
579 587 if f not in mctx:
580 588 actions[f] = 'f', None, "forget removed"
581 589
582 590 return actions
583 591
584 592 def _checkcollision(repo, wmf, actions):
585 593 # build provisional merged manifest up
586 594 pmmf = set(wmf)
587 595
588 596 if actions:
589 597 # k, dr, e and rd are no-op
590 598 for m in 'a', 'f', 'g', 'cd', 'dc':
591 599 for f, args, msg in actions[m]:
592 600 pmmf.add(f)
593 601 for f, args, msg in actions['r']:
594 602 pmmf.discard(f)
595 603 for f, args, msg in actions['dm']:
596 604 f2, flags = args
597 605 pmmf.discard(f2)
598 606 pmmf.add(f)
599 607 for f, args, msg in actions['dg']:
600 608 pmmf.add(f)
601 609 for f, args, msg in actions['m']:
602 610 f1, f2, fa, move, anc = args
603 611 if move:
604 612 pmmf.discard(f1)
605 613 pmmf.add(f)
606 614
607 615 # check case-folding collision in provisional merged manifest
608 616 foldmap = {}
609 617 for f in sorted(pmmf):
610 618 fold = util.normcase(f)
611 619 if fold in foldmap:
612 620 raise error.Abort(_("case-folding collision between %s and %s")
613 621 % (f, foldmap[fold]))
614 622 foldmap[fold] = f
615 623
616 624 # check case-folding of directories
617 625 foldprefix = unfoldprefix = lastfull = ''
618 626 for fold, f in sorted(foldmap.items()):
619 627 if fold.startswith(foldprefix) and not f.startswith(unfoldprefix):
620 628 # the folded prefix matches but actual casing is different
621 629 raise error.Abort(_("case-folding collision between "
622 630 "%s and directory of %s") % (lastfull, f))
623 631 foldprefix = fold + '/'
624 632 unfoldprefix = f + '/'
625 633 lastfull = f
626 634
627 635 def driverpreprocess(repo, ms, wctx, labels=None):
628 636 """run the preprocess step of the merge driver, if any
629 637
630 638 This is currently not implemented -- it's an extension point."""
631 639 return True
632 640
633 641 def driverconclude(repo, ms, wctx, labels=None):
634 642 """run the conclude step of the merge driver, if any
635 643
636 644 This is currently not implemented -- it's an extension point."""
637 645 return True
638 646
639 647 def manifestmerge(repo, wctx, p2, pa, branchmerge, force, partial,
640 648 acceptremote, followcopies):
641 649 """
642 650 Merge p1 and p2 with ancestor pa and generate merge action list
643 651
644 652 branchmerge and force are as passed in to update
645 653 partial = function to filter file lists
646 654 acceptremote = accept the incoming changes without prompting
647 655 """
648 656
649 657 copy, movewithdir, diverge, renamedelete = {}, {}, {}, {}
650 658
651 659 # manifests fetched in order are going to be faster, so prime the caches
652 660 [x.manifest() for x in
653 661 sorted(wctx.parents() + [p2, pa], key=lambda x: x.rev())]
654 662
655 663 if followcopies:
656 664 ret = copies.mergecopies(repo, wctx, p2, pa)
657 665 copy, movewithdir, diverge, renamedelete = ret
658 666
659 667 repo.ui.note(_("resolving manifests\n"))
660 668 repo.ui.debug(" branchmerge: %s, force: %s, partial: %s\n"
661 669 % (bool(branchmerge), bool(force), bool(partial)))
662 670 repo.ui.debug(" ancestor: %s, local: %s, remote: %s\n" % (pa, wctx, p2))
663 671
664 672 m1, m2, ma = wctx.manifest(), p2.manifest(), pa.manifest()
665 673 copied = set(copy.values())
666 674 copied.update(movewithdir.values())
667 675
668 676 if '.hgsubstate' in m1:
669 677 # check whether sub state is modified
670 678 for s in sorted(wctx.substate):
671 679 if wctx.sub(s).dirty():
672 680 m1['.hgsubstate'] += '+'
673 681 break
674 682
675 683 # Compare manifests
676 684 diff = m1.diff(m2)
677 685
678 686 actions = {}
679 687 for f, ((n1, fl1), (n2, fl2)) in diff.iteritems():
680 688 if partial and not partial(f):
681 689 continue
682 690 if n1 and n2: # file exists on both local and remote side
683 691 if f not in ma:
684 692 fa = copy.get(f, None)
685 693 if fa is not None:
686 694 actions[f] = ('m', (f, f, fa, False, pa.node()),
687 695 "both renamed from " + fa)
688 696 else:
689 697 actions[f] = ('m', (f, f, None, False, pa.node()),
690 698 "both created")
691 699 else:
692 700 a = ma[f]
693 701 fla = ma.flags(f)
694 702 nol = 'l' not in fl1 + fl2 + fla
695 703 if n2 == a and fl2 == fla:
696 704 actions[f] = ('k' , (), "remote unchanged")
697 705 elif n1 == a and fl1 == fla: # local unchanged - use remote
698 706 if n1 == n2: # optimization: keep local content
699 707 actions[f] = ('e', (fl2,), "update permissions")
700 708 else:
701 709 actions[f] = ('g', (fl2,), "remote is newer")
702 710 elif nol and n2 == a: # remote only changed 'x'
703 711 actions[f] = ('e', (fl2,), "update permissions")
704 712 elif nol and n1 == a: # local only changed 'x'
705 713 actions[f] = ('g', (fl1,), "remote is newer")
706 714 else: # both changed something
707 715 actions[f] = ('m', (f, f, f, False, pa.node()),
708 716 "versions differ")
709 717 elif n1: # file exists only on local side
710 718 if f in copied:
711 719 pass # we'll deal with it on m2 side
712 720 elif f in movewithdir: # directory rename, move local
713 721 f2 = movewithdir[f]
714 722 if f2 in m2:
715 723 actions[f2] = ('m', (f, f2, None, True, pa.node()),
716 724 "remote directory rename, both created")
717 725 else:
718 726 actions[f2] = ('dm', (f, fl1),
719 727 "remote directory rename - move from " + f)
720 728 elif f in copy:
721 729 f2 = copy[f]
722 730 actions[f] = ('m', (f, f2, f2, False, pa.node()),
723 731 "local copied/moved from " + f2)
724 732 elif f in ma: # clean, a different, no remote
725 733 if n1 != ma[f]:
726 734 if acceptremote:
727 735 actions[f] = ('r', None, "remote delete")
728 736 else:
729 737 actions[f] = ('cd', (f, None, f, False, pa.node()),
730 738 "prompt changed/deleted")
731 739 elif n1[20:] == 'a':
732 740 # This extra 'a' is added by working copy manifest to mark
733 741 # the file as locally added. We should forget it instead of
734 742 # deleting it.
735 743 actions[f] = ('f', None, "remote deleted")
736 744 else:
737 745 actions[f] = ('r', None, "other deleted")
738 746 elif n2: # file exists only on remote side
739 747 if f in copied:
740 748 pass # we'll deal with it on m1 side
741 749 elif f in movewithdir:
742 750 f2 = movewithdir[f]
743 751 if f2 in m1:
744 752 actions[f2] = ('m', (f2, f, None, False, pa.node()),
745 753 "local directory rename, both created")
746 754 else:
747 755 actions[f2] = ('dg', (f, fl2),
748 756 "local directory rename - get from " + f)
749 757 elif f in copy:
750 758 f2 = copy[f]
751 759 if f2 in m2:
752 760 actions[f] = ('m', (f2, f, f2, False, pa.node()),
753 761 "remote copied from " + f2)
754 762 else:
755 763 actions[f] = ('m', (f2, f, f2, True, pa.node()),
756 764 "remote moved from " + f2)
757 765 elif f not in ma:
758 766 # local unknown, remote created: the logic is described by the
759 767 # following table:
760 768 #
761 769 # force branchmerge different | action
762 770 # n * * | create
763 771 # y n * | create
764 772 # y y n | create
765 773 # y y y | merge
766 774 #
767 775 # Checking whether the files are different is expensive, so we
768 776 # don't do that when we can avoid it.
769 777 if not force:
770 778 actions[f] = ('c', (fl2,), "remote created")
771 779 elif not branchmerge:
772 780 actions[f] = ('c', (fl2,), "remote created")
773 781 else:
774 782 actions[f] = ('cm', (fl2, pa.node()),
775 783 "remote created, get or merge")
776 784 elif n2 != ma[f]:
777 785 if acceptremote:
778 786 actions[f] = ('c', (fl2,), "remote recreating")
779 787 else:
780 788 actions[f] = ('dc', (None, f, f, False, pa.node()),
781 789 "prompt deleted/changed")
782 790
783 791 return actions, diverge, renamedelete
784 792
785 793 def _resolvetrivial(repo, wctx, mctx, ancestor, actions):
786 794 """Resolves false conflicts where the nodeid changed but the content
787 795 remained the same."""
788 796
789 797 for f, (m, args, msg) in actions.items():
790 798 if m == 'cd' and f in ancestor and not wctx[f].cmp(ancestor[f]):
791 799 # local did change but ended up with same content
792 800 actions[f] = 'r', None, "prompt same"
793 801 elif m == 'dc' and f in ancestor and not mctx[f].cmp(ancestor[f]):
794 802 # remote did change but ended up with same content
795 803 del actions[f] # don't get = keep local deleted
796 804
797 805 def calculateupdates(repo, wctx, mctx, ancestors, branchmerge, force, partial,
798 806 acceptremote, followcopies):
799 807 "Calculate the actions needed to merge mctx into wctx using ancestors"
800 808
801 809 if len(ancestors) == 1: # default
802 810 actions, diverge, renamedelete = manifestmerge(
803 811 repo, wctx, mctx, ancestors[0], branchmerge, force, partial,
804 812 acceptremote, followcopies)
805 813 _checkunknownfiles(repo, wctx, mctx, force, actions)
806 814
807 815 else: # only when merge.preferancestor=* - the default
808 816 repo.ui.note(
809 817 _("note: merging %s and %s using bids from ancestors %s\n") %
810 818 (wctx, mctx, _(' and ').join(str(anc) for anc in ancestors)))
811 819
812 820 # Call for bids
813 821 fbids = {} # mapping filename to bids (action method to list af actions)
814 822 diverge, renamedelete = None, None
815 823 for ancestor in ancestors:
816 824 repo.ui.note(_('\ncalculating bids for ancestor %s\n') % ancestor)
817 825 actions, diverge1, renamedelete1 = manifestmerge(
818 826 repo, wctx, mctx, ancestor, branchmerge, force, partial,
819 827 acceptremote, followcopies)
820 828 _checkunknownfiles(repo, wctx, mctx, force, actions)
821 829
822 830 # Track the shortest set of warning on the theory that bid
823 831 # merge will correctly incorporate more information
824 832 if diverge is None or len(diverge1) < len(diverge):
825 833 diverge = diverge1
826 834 if renamedelete is None or len(renamedelete) < len(renamedelete1):
827 835 renamedelete = renamedelete1
828 836
829 837 for f, a in sorted(actions.iteritems()):
830 838 m, args, msg = a
831 839 repo.ui.debug(' %s: %s -> %s\n' % (f, msg, m))
832 840 if f in fbids:
833 841 d = fbids[f]
834 842 if m in d:
835 843 d[m].append(a)
836 844 else:
837 845 d[m] = [a]
838 846 else:
839 847 fbids[f] = {m: [a]}
840 848
841 849 # Pick the best bid for each file
842 850 repo.ui.note(_('\nauction for merging merge bids\n'))
843 851 actions = {}
844 852 for f, bids in sorted(fbids.items()):
845 853 # bids is a mapping from action method to list af actions
846 854 # Consensus?
847 855 if len(bids) == 1: # all bids are the same kind of method
848 856 m, l = bids.items()[0]
849 857 if all(a == l[0] for a in l[1:]): # len(bids) is > 1
850 858 repo.ui.note(" %s: consensus for %s\n" % (f, m))
851 859 actions[f] = l[0]
852 860 continue
853 861 # If keep is an option, just do it.
854 862 if 'k' in bids:
855 863 repo.ui.note(" %s: picking 'keep' action\n" % f)
856 864 actions[f] = bids['k'][0]
857 865 continue
858 866 # If there are gets and they all agree [how could they not?], do it.
859 867 if 'g' in bids:
860 868 ga0 = bids['g'][0]
861 869 if all(a == ga0 for a in bids['g'][1:]):
862 870 repo.ui.note(" %s: picking 'get' action\n" % f)
863 871 actions[f] = ga0
864 872 continue
865 873 # TODO: Consider other simple actions such as mode changes
866 874 # Handle inefficient democrazy.
867 875 repo.ui.note(_(' %s: multiple bids for merge action:\n') % f)
868 876 for m, l in sorted(bids.items()):
869 877 for _f, args, msg in l:
870 878 repo.ui.note(' %s -> %s\n' % (msg, m))
871 879 # Pick random action. TODO: Instead, prompt user when resolving
872 880 m, l = bids.items()[0]
873 881 repo.ui.warn(_(' %s: ambiguous merge - picked %s action\n') %
874 882 (f, m))
875 883 actions[f] = l[0]
876 884 continue
877 885 repo.ui.note(_('end of auction\n\n'))
878 886
879 887 _resolvetrivial(repo, wctx, mctx, ancestors[0], actions)
880 888
881 889 if wctx.rev() is None:
882 890 fractions = _forgetremoved(wctx, mctx, branchmerge)
883 891 actions.update(fractions)
884 892
885 893 return actions, diverge, renamedelete
886 894
887 895 def batchremove(repo, actions):
888 896 """apply removes to the working directory
889 897
890 898 yields tuples for progress updates
891 899 """
892 900 verbose = repo.ui.verbose
893 901 unlink = util.unlinkpath
894 902 wjoin = repo.wjoin
895 903 audit = repo.wvfs.audit
896 904 i = 0
897 905 for f, args, msg in actions:
898 906 repo.ui.debug(" %s: %s -> r\n" % (f, msg))
899 907 if verbose:
900 908 repo.ui.note(_("removing %s\n") % f)
901 909 audit(f)
902 910 try:
903 911 unlink(wjoin(f), ignoremissing=True)
904 912 except OSError as inst:
905 913 repo.ui.warn(_("update failed to remove %s: %s!\n") %
906 914 (f, inst.strerror))
907 915 if i == 100:
908 916 yield i, f
909 917 i = 0
910 918 i += 1
911 919 if i > 0:
912 920 yield i, f
913 921
914 922 def batchget(repo, mctx, actions):
915 923 """apply gets to the working directory
916 924
917 925 mctx is the context to get from
918 926
919 927 yields tuples for progress updates
920 928 """
921 929 verbose = repo.ui.verbose
922 930 fctx = mctx.filectx
923 931 wwrite = repo.wwrite
924 932 i = 0
925 933 for f, args, msg in actions:
926 934 repo.ui.debug(" %s: %s -> g\n" % (f, msg))
927 935 if verbose:
928 936 repo.ui.note(_("getting %s\n") % f)
929 937 wwrite(f, fctx(f).data(), args[0])
930 938 if i == 100:
931 939 yield i, f
932 940 i = 0
933 941 i += 1
934 942 if i > 0:
935 943 yield i, f
936 944
937 945 def applyupdates(repo, actions, wctx, mctx, overwrite, labels=None):
938 946 """apply the merge action list to the working directory
939 947
940 948 wctx is the working copy context
941 949 mctx is the context to be merged into the working copy
942 950
943 951 Return a tuple of counts (updated, merged, removed, unresolved) that
944 952 describes how many files were affected by the update.
945 953 """
946 954
947 955 updated, merged, removed = 0, 0, 0
948 956 ms = mergestate.clean(repo, wctx.p1().node(), mctx.node())
949 957 moves = []
950 958 for m, l in actions.items():
951 959 l.sort()
952 960
953 961 # prescan for merges
954 962 for f, args, msg in actions['m']:
955 963 f1, f2, fa, move, anc = args
956 964 if f == '.hgsubstate': # merged internally
957 965 continue
958 966 repo.ui.debug(" preserving %s for resolve of %s\n" % (f1, f))
959 967 fcl = wctx[f1]
960 968 fco = mctx[f2]
961 969 actx = repo[anc]
962 970 if fa in actx:
963 971 fca = actx[fa]
964 972 else:
965 973 fca = repo.filectx(f1, fileid=nullrev)
966 974 ms.add(fcl, fco, fca, f)
967 975 if f1 != f and move:
968 976 moves.append(f1)
969 977
970 978 audit = repo.wvfs.audit
971 979 _updating = _('updating')
972 980 _files = _('files')
973 981 progress = repo.ui.progress
974 982
975 983 # remove renamed files after safely stored
976 984 for f in moves:
977 985 if os.path.lexists(repo.wjoin(f)):
978 986 repo.ui.debug("removing %s\n" % f)
979 987 audit(f)
980 988 util.unlinkpath(repo.wjoin(f))
981 989
982 990 numupdates = sum(len(l) for m, l in actions.items() if m != 'k')
983 991
984 992 if [a for a in actions['r'] if a[0] == '.hgsubstate']:
985 993 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
986 994
987 995 # remove in parallel (must come first)
988 996 z = 0
989 997 prog = worker.worker(repo.ui, 0.001, batchremove, (repo,), actions['r'])
990 998 for i, item in prog:
991 999 z += i
992 1000 progress(_updating, z, item=item, total=numupdates, unit=_files)
993 1001 removed = len(actions['r'])
994 1002
995 1003 # get in parallel
996 1004 prog = worker.worker(repo.ui, 0.001, batchget, (repo, mctx), actions['g'])
997 1005 for i, item in prog:
998 1006 z += i
999 1007 progress(_updating, z, item=item, total=numupdates, unit=_files)
1000 1008 updated = len(actions['g'])
1001 1009
1002 1010 if [a for a in actions['g'] if a[0] == '.hgsubstate']:
1003 1011 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
1004 1012
1005 1013 # forget (manifest only, just log it) (must come first)
1006 1014 for f, args, msg in actions['f']:
1007 1015 repo.ui.debug(" %s: %s -> f\n" % (f, msg))
1008 1016 z += 1
1009 1017 progress(_updating, z, item=f, total=numupdates, unit=_files)
1010 1018
1011 1019 # re-add (manifest only, just log it)
1012 1020 for f, args, msg in actions['a']:
1013 1021 repo.ui.debug(" %s: %s -> a\n" % (f, msg))
1014 1022 z += 1
1015 1023 progress(_updating, z, item=f, total=numupdates, unit=_files)
1016 1024
1017 1025 # keep (noop, just log it)
1018 1026 for f, args, msg in actions['k']:
1019 1027 repo.ui.debug(" %s: %s -> k\n" % (f, msg))
1020 1028 # no progress
1021 1029
1022 1030 # directory rename, move local
1023 1031 for f, args, msg in actions['dm']:
1024 1032 repo.ui.debug(" %s: %s -> dm\n" % (f, msg))
1025 1033 z += 1
1026 1034 progress(_updating, z, item=f, total=numupdates, unit=_files)
1027 1035 f0, flags = args
1028 1036 repo.ui.note(_("moving %s to %s\n") % (f0, f))
1029 1037 audit(f)
1030 1038 repo.wwrite(f, wctx.filectx(f0).data(), flags)
1031 1039 util.unlinkpath(repo.wjoin(f0))
1032 1040 updated += 1
1033 1041
1034 1042 # local directory rename, get
1035 1043 for f, args, msg in actions['dg']:
1036 1044 repo.ui.debug(" %s: %s -> dg\n" % (f, msg))
1037 1045 z += 1
1038 1046 progress(_updating, z, item=f, total=numupdates, unit=_files)
1039 1047 f0, flags = args
1040 1048 repo.ui.note(_("getting %s to %s\n") % (f0, f))
1041 1049 repo.wwrite(f, mctx.filectx(f0).data(), flags)
1042 1050 updated += 1
1043 1051
1044 1052 # exec
1045 1053 for f, args, msg in actions['e']:
1046 1054 repo.ui.debug(" %s: %s -> e\n" % (f, msg))
1047 1055 z += 1
1048 1056 progress(_updating, z, item=f, total=numupdates, unit=_files)
1049 1057 flags, = args
1050 1058 audit(f)
1051 1059 util.setflags(repo.wjoin(f), 'l' in flags, 'x' in flags)
1052 1060 updated += 1
1053 1061
1054 1062 mergeactions = actions['m']
1055 1063 # the ordering is important here -- ms.mergedriver will raise if the merge
1056 1064 # driver has changed, and we want to be able to bypass it when overwrite is
1057 1065 # True
1058 1066 usemergedriver = not overwrite and mergeactions and ms.mergedriver
1059 1067
1060 1068 if usemergedriver:
1061 1069 ms.commit()
1062 1070 proceed = driverpreprocess(repo, ms, wctx, labels=labels)
1063 1071 # the driver might leave some files unresolved
1064 1072 unresolvedf = set(ms.unresolved())
1065 1073 if not proceed:
1066 1074 # XXX setting unresolved to at least 1 is a hack to make sure we
1067 1075 # error out
1068 1076 return updated, merged, removed, max(len(unresolvedf), 1)
1069 1077 newactions = []
1070 1078 for f, args, msg in mergeactions:
1071 1079 if f in unresolvedf:
1072 1080 newactions.append((f, args, msg))
1073 1081 mergeactions = newactions
1074 1082
1075 1083 # premerge
1076 1084 tocomplete = []
1077 1085 for f, args, msg in mergeactions:
1078 1086 repo.ui.debug(" %s: %s -> m (premerge)\n" % (f, msg))
1079 1087 z += 1
1080 1088 progress(_updating, z, item=f, total=numupdates, unit=_files)
1081 1089 if f == '.hgsubstate': # subrepo states need updating
1082 1090 subrepo.submerge(repo, wctx, mctx, wctx.ancestor(mctx),
1083 1091 overwrite)
1084 1092 continue
1085 1093 audit(f)
1086 1094 complete, r = ms.preresolve(f, wctx, labels=labels)
1087 1095 if not complete:
1088 1096 numupdates += 1
1089 1097 tocomplete.append((f, args, msg))
1090 1098
1091 1099 # merge
1092 1100 for f, args, msg in tocomplete:
1093 1101 repo.ui.debug(" %s: %s -> m (merge)\n" % (f, msg))
1094 1102 z += 1
1095 1103 progress(_updating, z, item=f, total=numupdates, unit=_files)
1096 1104 ms.resolve(f, wctx, labels=labels)
1097 1105
1098 1106 ms.commit()
1099 1107
1100 1108 unresolved = ms.unresolvedcount()
1101 1109
1102 1110 if usemergedriver and not unresolved and ms.mdstate() != 's':
1103 1111 if not driverconclude(repo, ms, wctx, labels=labels):
1104 1112 # XXX setting unresolved to at least 1 is a hack to make sure we
1105 1113 # error out
1106 1114 unresolved = max(unresolved, 1)
1107 1115
1108 1116 ms.commit()
1109 1117
1110 1118 msupdated, msmerged, msremoved = ms.counts()
1111 1119 updated += msupdated
1112 1120 merged += msmerged
1113 1121 removed += msremoved
1114 1122 progress(_updating, None, total=numupdates, unit=_files)
1115 1123
1116 1124 return updated, merged, removed, unresolved
1117 1125
1118 1126 def recordupdates(repo, actions, branchmerge):
1119 1127 "record merge actions to the dirstate"
1120 1128 # remove (must come first)
1121 1129 for f, args, msg in actions['r']:
1122 1130 if branchmerge:
1123 1131 repo.dirstate.remove(f)
1124 1132 else:
1125 1133 repo.dirstate.drop(f)
1126 1134
1127 1135 # forget (must come first)
1128 1136 for f, args, msg in actions['f']:
1129 1137 repo.dirstate.drop(f)
1130 1138
1131 1139 # re-add
1132 1140 for f, args, msg in actions['a']:
1133 1141 if not branchmerge:
1134 1142 repo.dirstate.add(f)
1135 1143
1136 1144 # exec change
1137 1145 for f, args, msg in actions['e']:
1138 1146 repo.dirstate.normallookup(f)
1139 1147
1140 1148 # keep
1141 1149 for f, args, msg in actions['k']:
1142 1150 pass
1143 1151
1144 1152 # get
1145 1153 for f, args, msg in actions['g']:
1146 1154 if branchmerge:
1147 1155 repo.dirstate.otherparent(f)
1148 1156 else:
1149 1157 repo.dirstate.normal(f)
1150 1158
1151 1159 # merge
1152 1160 for f, args, msg in actions['m']:
1153 1161 f1, f2, fa, move, anc = args
1154 1162 if branchmerge:
1155 1163 # We've done a branch merge, mark this file as merged
1156 1164 # so that we properly record the merger later
1157 1165 repo.dirstate.merge(f)
1158 1166 if f1 != f2: # copy/rename
1159 1167 if move:
1160 1168 repo.dirstate.remove(f1)
1161 1169 if f1 != f:
1162 1170 repo.dirstate.copy(f1, f)
1163 1171 else:
1164 1172 repo.dirstate.copy(f2, f)
1165 1173 else:
1166 1174 # We've update-merged a locally modified file, so
1167 1175 # we set the dirstate to emulate a normal checkout
1168 1176 # of that file some time in the past. Thus our
1169 1177 # merge will appear as a normal local file
1170 1178 # modification.
1171 1179 if f2 == f: # file not locally copied/moved
1172 1180 repo.dirstate.normallookup(f)
1173 1181 if move:
1174 1182 repo.dirstate.drop(f1)
1175 1183
1176 1184 # directory rename, move local
1177 1185 for f, args, msg in actions['dm']:
1178 1186 f0, flag = args
1179 1187 if branchmerge:
1180 1188 repo.dirstate.add(f)
1181 1189 repo.dirstate.remove(f0)
1182 1190 repo.dirstate.copy(f0, f)
1183 1191 else:
1184 1192 repo.dirstate.normal(f)
1185 1193 repo.dirstate.drop(f0)
1186 1194
1187 1195 # directory rename, get
1188 1196 for f, args, msg in actions['dg']:
1189 1197 f0, flag = args
1190 1198 if branchmerge:
1191 1199 repo.dirstate.add(f)
1192 1200 repo.dirstate.copy(f0, f)
1193 1201 else:
1194 1202 repo.dirstate.normal(f)
1195 1203
1196 1204 def update(repo, node, branchmerge, force, partial, ancestor=None,
1197 1205 mergeancestor=False, labels=None):
1198 1206 """
1199 1207 Perform a merge between the working directory and the given node
1200 1208
1201 1209 node = the node to update to, or None if unspecified
1202 1210 branchmerge = whether to merge between branches
1203 1211 force = whether to force branch merging or file overwriting
1204 1212 partial = a function to filter file lists (dirstate not updated)
1205 1213 mergeancestor = whether it is merging with an ancestor. If true,
1206 1214 we should accept the incoming changes for any prompts that occur.
1207 1215 If false, merging with an ancestor (fast-forward) is only allowed
1208 1216 between different named branches. This flag is used by rebase extension
1209 1217 as a temporary fix and should be avoided in general.
1210 1218
1211 1219 The table below shows all the behaviors of the update command
1212 1220 given the -c and -C or no options, whether the working directory
1213 1221 is dirty, whether a revision is specified, and the relationship of
1214 1222 the parent rev to the target rev (linear, on the same named
1215 1223 branch, or on another named branch).
1216 1224
1217 1225 This logic is tested by test-update-branches.t.
1218 1226
1219 1227 -c -C dirty rev | linear same cross
1220 1228 n n n n | ok (1) x
1221 1229 n n n y | ok ok ok
1222 1230 n n y n | merge (2) (2)
1223 1231 n n y y | merge (3) (3)
1224 1232 n y * * | discard discard discard
1225 1233 y n y * | (4) (4) (4)
1226 1234 y n n * | ok ok ok
1227 1235 y y * * | (5) (5) (5)
1228 1236
1229 1237 x = can't happen
1230 1238 * = don't-care
1231 1239 1 = abort: not a linear update (merge or update --check to force update)
1232 1240 2 = abort: uncommitted changes (commit and merge, or update --clean to
1233 1241 discard changes)
1234 1242 3 = abort: uncommitted changes (commit or update --clean to discard changes)
1235 1243 4 = abort: uncommitted changes (checked in commands.py)
1236 1244 5 = incompatible options (checked in commands.py)
1237 1245
1238 1246 Return the same tuple as applyupdates().
1239 1247 """
1240 1248
1241 1249 onode = node
1242 1250 wlock = repo.wlock()
1243 1251 try:
1244 1252 wc = repo[None]
1245 1253 pl = wc.parents()
1246 1254 p1 = pl[0]
1247 1255 pas = [None]
1248 1256 if ancestor is not None:
1249 1257 pas = [repo[ancestor]]
1250 1258
1251 1259 if node is None:
1252 1260 if (repo.ui.configbool('devel', 'all-warnings')
1253 1261 or repo.ui.configbool('devel', 'oldapi')):
1254 1262 repo.ui.develwarn('update with no target')
1255 1263 rev, _mark, _act = destutil.destupdate(repo)
1256 1264 node = repo[rev].node()
1257 1265
1258 1266 overwrite = force and not branchmerge
1259 1267
1260 1268 p2 = repo[node]
1261 1269 if pas[0] is None:
1262 1270 if repo.ui.configlist('merge', 'preferancestor', ['*']) == ['*']:
1263 1271 cahs = repo.changelog.commonancestorsheads(p1.node(), p2.node())
1264 1272 pas = [repo[anc] for anc in (sorted(cahs) or [nullid])]
1265 1273 else:
1266 1274 pas = [p1.ancestor(p2, warn=branchmerge)]
1267 1275
1268 1276 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2)
1269 1277
1270 1278 ### check phase
1271 1279 if not overwrite and len(pl) > 1:
1272 1280 raise error.Abort(_("outstanding uncommitted merge"))
1273 1281 if branchmerge:
1274 1282 if pas == [p2]:
1275 1283 raise error.Abort(_("merging with a working directory ancestor"
1276 1284 " has no effect"))
1277 1285 elif pas == [p1]:
1278 1286 if not mergeancestor and p1.branch() == p2.branch():
1279 1287 raise error.Abort(_("nothing to merge"),
1280 1288 hint=_("use 'hg update' "
1281 1289 "or check 'hg heads'"))
1282 1290 if not force and (wc.files() or wc.deleted()):
1283 1291 raise error.Abort(_("uncommitted changes"),
1284 1292 hint=_("use 'hg status' to list changes"))
1285 1293 for s in sorted(wc.substate):
1286 1294 wc.sub(s).bailifchanged()
1287 1295
1288 1296 elif not overwrite:
1289 1297 if p1 == p2: # no-op update
1290 1298 # call the hooks and exit early
1291 1299 repo.hook('preupdate', throw=True, parent1=xp2, parent2='')
1292 1300 repo.hook('update', parent1=xp2, parent2='', error=0)
1293 1301 return 0, 0, 0, 0
1294 1302
1295 1303 if pas not in ([p1], [p2]): # nonlinear
1296 1304 dirty = wc.dirty(missing=True)
1297 1305 if dirty or onode is None:
1298 1306 # Branching is a bit strange to ensure we do the minimal
1299 1307 # amount of call to obsolete.background.
1300 1308 foreground = obsolete.foreground(repo, [p1.node()])
1301 1309 # note: the <node> variable contains a random identifier
1302 1310 if repo[node].node() in foreground:
1303 1311 pas = [p1] # allow updating to successors
1304 1312 elif dirty:
1305 1313 msg = _("uncommitted changes")
1306 1314 if onode is None:
1307 1315 hint = _("commit and merge, or update --clean to"
1308 1316 " discard changes")
1309 1317 else:
1310 1318 hint = _("commit or update --clean to discard"
1311 1319 " changes")
1312 1320 raise error.Abort(msg, hint=hint)
1313 1321 else: # node is none
1314 1322 msg = _("not a linear update")
1315 1323 hint = _("merge or update --check to force update")
1316 1324 raise error.Abort(msg, hint=hint)
1317 1325 else:
1318 1326 # Allow jumping branches if clean and specific rev given
1319 1327 pas = [p1]
1320 1328
1321 1329 # deprecated config: merge.followcopies
1322 1330 followcopies = False
1323 1331 if overwrite:
1324 1332 pas = [wc]
1325 1333 elif pas == [p2]: # backwards
1326 1334 pas = [wc.p1()]
1327 1335 elif not branchmerge and not wc.dirty(missing=True):
1328 1336 pass
1329 1337 elif pas[0] and repo.ui.configbool('merge', 'followcopies', True):
1330 1338 followcopies = True
1331 1339
1332 1340 ### calculate phase
1333 1341 actionbyfile, diverge, renamedelete = calculateupdates(
1334 1342 repo, wc, p2, pas, branchmerge, force, partial, mergeancestor,
1335 1343 followcopies)
1336 1344 # Convert to dictionary-of-lists format
1337 1345 actions = dict((m, []) for m in 'a f g cd dc r dm dg m e k'.split())
1338 1346 for f, (m, args, msg) in actionbyfile.iteritems():
1339 1347 if m not in actions:
1340 1348 actions[m] = []
1341 1349 actions[m].append((f, args, msg))
1342 1350
1343 1351 if not util.checkcase(repo.path):
1344 1352 # check collision between files only in p2 for clean update
1345 1353 if (not branchmerge and
1346 1354 (force or not wc.dirty(missing=True, branch=False))):
1347 1355 _checkcollision(repo, p2.manifest(), None)
1348 1356 else:
1349 1357 _checkcollision(repo, wc.manifest(), actions)
1350 1358
1351 1359 # Prompt and create actions. TODO: Move this towards resolve phase.
1352 1360 for f, args, msg in sorted(actions['cd']):
1353 1361 if repo.ui.promptchoice(
1354 1362 _("local changed %s which remote deleted\n"
1355 1363 "use (c)hanged version or (d)elete?"
1356 1364 "$$ &Changed $$ &Delete") % f, 0):
1357 1365 actions['r'].append((f, None, "prompt delete"))
1358 1366 else:
1359 1367 actions['a'].append((f, None, "prompt keep"))
1360 1368
1361 1369 for f, args, msg in sorted(actions['dc']):
1362 1370 f1, f2, fa, move, anc = args
1363 1371 flags = p2[f2].flags()
1364 1372 if repo.ui.promptchoice(
1365 1373 _("remote changed %s which local deleted\n"
1366 1374 "use (c)hanged version or leave (d)eleted?"
1367 1375 "$$ &Changed $$ &Deleted") % f, 0) == 0:
1368 1376 actions['g'].append((f, (flags,), "prompt recreating"))
1369 1377
1370 1378 # divergent renames
1371 1379 for f, fl in sorted(diverge.iteritems()):
1372 1380 repo.ui.warn(_("note: possible conflict - %s was renamed "
1373 1381 "multiple times to:\n") % f)
1374 1382 for nf in fl:
1375 1383 repo.ui.warn(" %s\n" % nf)
1376 1384
1377 1385 # rename and delete
1378 1386 for f, fl in sorted(renamedelete.iteritems()):
1379 1387 repo.ui.warn(_("note: possible conflict - %s was deleted "
1380 1388 "and renamed to:\n") % f)
1381 1389 for nf in fl:
1382 1390 repo.ui.warn(" %s\n" % nf)
1383 1391
1384 1392 ### apply phase
1385 1393 if not branchmerge: # just jump to the new rev
1386 1394 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
1387 1395 if not partial:
1388 1396 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
1389 1397 # note that we're in the middle of an update
1390 1398 repo.vfs.write('updatestate', p2.hex())
1391 1399
1392 1400 stats = applyupdates(repo, actions, wc, p2, overwrite, labels=labels)
1393 1401
1394 1402 if not partial:
1395 1403 repo.dirstate.beginparentchange()
1396 1404 repo.setparents(fp1, fp2)
1397 1405 recordupdates(repo, actions, branchmerge)
1398 1406 # update completed, clear state
1399 1407 util.unlink(repo.join('updatestate'))
1400 1408
1401 1409 if not branchmerge:
1402 1410 repo.dirstate.setbranch(p2.branch())
1403 1411 repo.dirstate.endparentchange()
1404 1412 finally:
1405 1413 wlock.release()
1406 1414
1407 1415 if not partial:
1408 1416 repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3])
1409 1417 return stats
1410 1418
1411 1419 def graft(repo, ctx, pctx, labels):
1412 1420 """Do a graft-like merge.
1413 1421
1414 1422 This is a merge where the merge ancestor is chosen such that one
1415 1423 or more changesets are grafted onto the current changeset. In
1416 1424 addition to the merge, this fixes up the dirstate to include only
1417 1425 a single parent and tries to duplicate any renames/copies
1418 1426 appropriately.
1419 1427
1420 1428 ctx - changeset to rebase
1421 1429 pctx - merge base, usually ctx.p1()
1422 1430 labels - merge labels eg ['local', 'graft']
1423 1431
1424 1432 """
1425 1433 # If we're grafting a descendant onto an ancestor, be sure to pass
1426 1434 # mergeancestor=True to update. This does two things: 1) allows the merge if
1427 1435 # the destination is the same as the parent of the ctx (so we can use graft
1428 1436 # to copy commits), and 2) informs update that the incoming changes are
1429 1437 # newer than the destination so it doesn't prompt about "remote changed foo
1430 1438 # which local deleted".
1431 1439 mergeancestor = repo.changelog.isancestor(repo['.'].node(), ctx.node())
1432 1440
1433 1441 stats = update(repo, ctx.node(), True, True, False, pctx.node(),
1434 1442 mergeancestor=mergeancestor, labels=labels)
1435 1443
1436 1444 # drop the second merge parent
1437 1445 repo.dirstate.beginparentchange()
1438 1446 repo.setparents(repo['.'].node(), nullid)
1439 1447 repo.dirstate.write(repo.currenttransaction())
1440 1448 # fix up dirstate for copies and renames
1441 1449 copies.duplicatecopies(repo, ctx.rev(), pctx.rev())
1442 1450 repo.dirstate.endparentchange()
1443 1451 return stats
General Comments 0
You need to be logged in to leave comments. Login now