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