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