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