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