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