Show More
@@ -30,42 +30,6 b' class filelog(revlog):' | |||
|
30 | 30 | def add(self, text, transaction, link, p1=None, p2=None): |
|
31 | 31 | return self.addrevision(text, transaction, link, p1, p2) |
|
32 | 32 | |
|
33 | def resolvedag(self, old, new, transaction, link): | |
|
34 | """resolve unmerged heads in our DAG""" | |
|
35 | if old == new: return None | |
|
36 | a = self.ancestor(old, new) | |
|
37 | if old == a: return None | |
|
38 | return self.merge3(old, new, a, transaction, link) | |
|
39 | ||
|
40 | def merge3(self, my, other, base, transaction, link): | |
|
41 | """perform a 3-way merge and append the result""" | |
|
42 | def temp(prefix, node): | |
|
43 | (fd, name) = tempfile.mkstemp(prefix) | |
|
44 | f = os.fdopen(fd, "w") | |
|
45 | f.write(self.revision(node)) | |
|
46 | f.close() | |
|
47 | return name | |
|
48 | ||
|
49 | a = temp("local", my) | |
|
50 | b = temp("remote", other) | |
|
51 | c = temp("parent", base) | |
|
52 | ||
|
53 | cmd = os.environ["HGMERGE"] | |
|
54 | r = os.system("%s %s %s %s" % (cmd, a, b, c)) | |
|
55 | if r: | |
|
56 | raise "Merge failed, implement rollback!" | |
|
57 | ||
|
58 | t = open(a).read() | |
|
59 | os.unlink(a) | |
|
60 | os.unlink(b) | |
|
61 | os.unlink(c) | |
|
62 | return self.addrevision(t, transaction, link, my, other) | |
|
63 | ||
|
64 | def merge(self, other, transaction, linkseq, link): | |
|
65 | """perform a merge and resolve resulting heads""" | |
|
66 | (o, n) = self.mergedag(other, transaction, linkseq) | |
|
67 | return self.resolvedag(o, n, transaction, link) | |
|
68 | ||
|
69 | 33 | def annotate(self, node): |
|
70 | 34 | revs = [] |
|
71 | 35 | while node != nullid: |
@@ -160,9 +124,6 b' class changelog(revlog):' | |||
|
160 | 124 | text = "\n".join(l) |
|
161 | 125 | return self.addrevision(text, transaction, self.count(), p1, p2) |
|
162 | 126 | |
|
163 | def merge3(self, my, other, base): | |
|
164 | pass | |
|
165 | ||
|
166 | 127 | class dircache: |
|
167 | 128 | def __init__(self, opener, ui): |
|
168 | 129 | self.opener = opener |
@@ -335,122 +296,6 b' class localrepository:' | |||
|
335 | 296 | def transaction(self): |
|
336 | 297 | return transaction(self.opener, self.join("journal")) |
|
337 | 298 | |
|
338 | def merge(self, other): | |
|
339 | tr = self.transaction() | |
|
340 | changed = {} | |
|
341 | new = {} | |
|
342 | seqrev = self.changelog.count() | |
|
343 | # some magic to allow fiddling in nested scope | |
|
344 | nextrev = [seqrev] | |
|
345 | ||
|
346 | # helpers for back-linking file revisions to local changeset | |
|
347 | # revisions so we can immediately get to changeset from annotate | |
|
348 | def accumulate(text): | |
|
349 | # track which files are added in which changeset and the | |
|
350 | # corresponding _local_ changeset revision | |
|
351 | files = self.changelog.extract(text)[3] | |
|
352 | for f in files: | |
|
353 | changed.setdefault(f, []).append(nextrev[0]) | |
|
354 | nextrev[0] += 1 | |
|
355 | ||
|
356 | def seq(start): | |
|
357 | while 1: | |
|
358 | yield start | |
|
359 | start += 1 | |
|
360 | ||
|
361 | def lseq(l): | |
|
362 | for r in l: | |
|
363 | yield r | |
|
364 | ||
|
365 | # begin the import/merge of changesets | |
|
366 | self.ui.status("merging new changesets\n") | |
|
367 | (co, cn) = self.changelog.mergedag(other.changelog, tr, | |
|
368 | seq(seqrev), accumulate) | |
|
369 | resolverev = self.changelog.count() | |
|
370 | ||
|
371 | # is there anything to do? | |
|
372 | if co == cn: | |
|
373 | tr.close() | |
|
374 | return | |
|
375 | ||
|
376 | # do we need to resolve? | |
|
377 | simple = (co == self.changelog.ancestor(co, cn)) | |
|
378 | ||
|
379 | # merge all files changed by the changesets, | |
|
380 | # keeping track of the new tips | |
|
381 | changelist = changed.keys() | |
|
382 | changelist.sort() | |
|
383 | for f in changelist: | |
|
384 | sys.stdout.write(".") | |
|
385 | sys.stdout.flush() | |
|
386 | r = self.file(f) | |
|
387 | node = r.merge(other.file(f), tr, lseq(changed[f]), resolverev) | |
|
388 | if node: | |
|
389 | new[f] = node | |
|
390 | sys.stdout.write("\n") | |
|
391 | ||
|
392 | # begin the merge of the manifest | |
|
393 | self.ui.status("merging manifests\n") | |
|
394 | (mm, mo) = self.manifest.mergedag(other.manifest, tr, seq(seqrev)) | |
|
395 | ||
|
396 | # For simple merges, we don't need to resolve manifests or changesets | |
|
397 | if simple: | |
|
398 | tr.close() | |
|
399 | return | |
|
400 | ||
|
401 | ma = self.manifest.ancestor(mm, mo) | |
|
402 | ||
|
403 | # resolve the manifest to point to all the merged files | |
|
404 | self.ui.status("resolving manifests\n") | |
|
405 | omap = self.manifest.read(mo) # other | |
|
406 | amap = self.manifest.read(ma) # ancestor | |
|
407 | mmap = self.manifest.read(mm) # mine | |
|
408 | nmap = {} | |
|
409 | ||
|
410 | for f, mid in mmap.iteritems(): | |
|
411 | if f in omap: | |
|
412 | if mid != omap[f]: | |
|
413 | nmap[f] = new.get(f, mid) # use merged version | |
|
414 | else: | |
|
415 | nmap[f] = new.get(f, mid) # they're the same | |
|
416 | del omap[f] | |
|
417 | elif f in amap: | |
|
418 | if mid != amap[f]: | |
|
419 | pass # we should prompt here | |
|
420 | else: | |
|
421 | pass # other deleted it | |
|
422 | else: | |
|
423 | nmap[f] = new.get(f, mid) # we created it | |
|
424 | ||
|
425 | del mmap | |
|
426 | ||
|
427 | for f, oid in omap.iteritems(): | |
|
428 | if f in amap: | |
|
429 | if oid != amap[f]: | |
|
430 | pass # this is the nasty case, we should prompt | |
|
431 | else: | |
|
432 | pass # probably safe | |
|
433 | else: | |
|
434 | nmap[f] = new.get(f, oid) # remote created it | |
|
435 | ||
|
436 | del omap | |
|
437 | del amap | |
|
438 | ||
|
439 | node = self.manifest.add(nmap, tr, resolverev, mm, mo) | |
|
440 | ||
|
441 | # Now all files and manifests are merged, we add the changed files | |
|
442 | # and manifest id to the changelog | |
|
443 | self.ui.status("committing merge changeset\n") | |
|
444 | new = new.keys() | |
|
445 | new.sort() | |
|
446 | if co == cn: cn = -1 | |
|
447 | ||
|
448 | edittext = "\n"+"".join(["HG: changed %s\n" % f for f in new]) | |
|
449 | edittext = self.ui.edit(edittext) | |
|
450 | n = self.changelog.add(node, new, edittext, tr, co, cn) | |
|
451 | ||
|
452 | tr.close() | |
|
453 | ||
|
454 | 299 | def commit(self, parent, update = None, text = ""): |
|
455 | 300 | tr = self.transaction() |
|
456 | 301 | |
@@ -640,19 +485,26 b' class localrepository:' | |||
|
640 | 485 | def newer(self, nodes): |
|
641 | 486 | m = {} |
|
642 | 487 | nl = [] |
|
488 | pm = {} | |
|
643 | 489 | cl = self.changelog |
|
644 | 490 | t = l = cl.count() |
|
491 | ||
|
492 | # find the lowest numbered node | |
|
645 | 493 | for n in nodes: |
|
646 | 494 | l = min(l, cl.rev(n)) |
|
647 | for p in cl.parents(n): | |
|
648 | m[p] = 1 | |
|
495 | m[n] = 1 | |
|
649 | 496 | |
|
650 | 497 | for i in xrange(l, t): |
|
651 | 498 | n = cl.node(i) |
|
499 | if n in m: # explicitly listed | |
|
500 | pm[n] = 1 | |
|
501 | nl.append(n) | |
|
502 | continue | |
|
652 | 503 | for p in cl.parents(n): |
|
653 |
if p in m |
|
|
654 | m[n] = 1 | |
|
504 | if p in pm: # parent listed | |
|
505 | pm[n] = 1 | |
|
655 | 506 | nl.append(n) |
|
507 | break | |
|
656 | 508 | |
|
657 | 509 | return nl |
|
658 | 510 | |
@@ -676,13 +528,14 b' class localrepository:' | |||
|
676 | 528 | self.ui.debug("found incomplete branch %s\n" % short(n[1])) |
|
677 | 529 | search.append(n) # schedule branch range for scanning |
|
678 | 530 | else: |
|
679 |
f |
|
|
680 | if b[0] in m: | |
|
531 | if n[2] in m and n[3] in m: | |
|
681 | 532 |
|
|
682 | 533 |
|
|
683 | 534 |
|
|
684 | 535 |
|
|
685 |
e |
|
|
536 | continue | |
|
537 | for b in remote.branches([n[2], n[3]]): | |
|
538 | if b[0] not in m: | |
|
686 | 539 | unknown.append(b) |
|
687 | 540 | |
|
688 | 541 | while search: |
@@ -707,7 +560,7 b' class localrepository:' | |||
|
707 | 560 | if f in m: |
|
708 | 561 | raise "already have", short(f[:4]) |
|
709 | 562 | |
|
710 |
self.ui.note(" |
|
|
563 | self.ui.note("adding new changesets starting at " + | |
|
711 | 564 | " ".join([short(f) for f in fetch]) + "\n") |
|
712 | 565 | |
|
713 | 566 | return remote.changegroup(fetch) |
@@ -767,13 +620,17 b' class localrepository:' | |||
|
767 | 620 | tr = self.transaction() |
|
768 | 621 | simple = True |
|
769 | 622 | |
|
770 |
self.ui.status(" |
|
|
623 | self.ui.status("adding changesets\n") | |
|
771 | 624 | # pull off the changeset group |
|
625 | def report(x): | |
|
626 | self.ui.debug("add changeset %s\n" % short(x)) | |
|
627 | return self.changelog.count() | |
|
628 | ||
|
772 | 629 | csg = getchunk() |
|
773 | 630 | co = self.changelog.tip() |
|
774 |
cn = self.changelog.addgroup(csg, |
|
|
631 | cn = self.changelog.addgroup(csg, report, tr) | |
|
775 | 632 | |
|
776 |
self.ui.status(" |
|
|
633 | self.ui.status("adding manifests\n") | |
|
777 | 634 | # pull off the manifest group |
|
778 | 635 | mfg = getchunk() |
|
779 | 636 | mm = self.manifest.tip() |
@@ -785,21 +642,21 b' class localrepository:' | |||
|
785 | 642 | resolverev = self.changelog.count() |
|
786 | 643 | |
|
787 | 644 | # process the files |
|
788 |
self.ui.status(" |
|
|
645 | self.ui.status("adding files\n") | |
|
789 | 646 | new = {} |
|
790 | 647 | while 1: |
|
791 | 648 | f = getchunk(4) |
|
792 | 649 | if not f: break |
|
793 | 650 | fg = getchunk() |
|
794 | ||
|
651 | self.ui.debug("adding %s revisions\n" % f) | |
|
795 | 652 | fl = self.file(f) |
|
796 | 653 | o = fl.tip() |
|
797 | 654 | n = fl.addgroup(fg, lambda x: self.changelog.rev(x), tr) |
|
798 | 655 | if not simple: |
|
799 | nn = fl.resolvedag(o, n, tr, resolverev) | |
|
800 | if nn: | |
|
801 | self.ui.note("merged %s\n", f) | |
|
802 | new[f] = nn | |
|
656 | if o == n: continue | |
|
657 | # this file has changed between branches, so it must be | |
|
658 | # represented in the merge changeset | |
|
659 | new[f] = self.merge3(fl, f, o, n, tr, resolverev) | |
|
803 | 660 | |
|
804 | 661 | # For simple merges, we don't need to resolve manifests or changesets |
|
805 | 662 | if simple: |
@@ -821,8 +678,9 b' class localrepository:' | |||
|
821 | 678 | if f in omap: |
|
822 | 679 | if mid != omap[f]: |
|
823 | 680 | self.ui.debug("%s versions differ\n" % f) |
|
824 |
if f in new: self.ui. |
|
|
825 |
|
|
|
681 | if f in new: self.ui.debug("%s updated in resolve\n" % f) | |
|
682 | # use merged version or local version | |
|
683 | nmap[f] = new.get(f, mid) | |
|
826 | 684 | else: |
|
827 | 685 | nmap[f] = mid # keep ours |
|
828 | 686 | del omap[f] |
@@ -143,12 +143,6 b' class revlog:' | |||
|
143 | 143 | |
|
144 | 144 | return None |
|
145 | 145 | |
|
146 | def revisions(self, list): | |
|
147 | # this can be optimized to do spans, etc | |
|
148 | # be stupid for now | |
|
149 | for node in list: | |
|
150 | yield self.revision(node) | |
|
151 | ||
|
152 | 146 | def diff(self, a, b): |
|
153 | 147 | return mdiff.textdiff(a, b) |
|
154 | 148 | |
@@ -272,34 +266,9 b' class revlog:' | |||
|
272 | 266 | |
|
273 | 267 | return nullid |
|
274 | 268 | |
|
275 | def mergedag(self, other, transaction, linkseq, accumulate = None): | |
|
276 | """combine the nodes from other's DAG into ours""" | |
|
277 | old = self.tip() | |
|
278 | i = self.count() | |
|
279 | l = [] | |
|
280 | ||
|
281 | # merge the other revision log into our DAG | |
|
282 | for r in range(other.count()): | |
|
283 | id = other.node(r) | |
|
284 | if id not in self.nodemap: | |
|
285 | (xn, yn) = other.parents(id) | |
|
286 | l.append((id, xn, yn)) | |
|
287 | self.nodemap[id] = i | |
|
288 | i += 1 | |
|
289 | ||
|
290 | # merge node date for new nodes | |
|
291 | r = other.revisions([e[0] for e in l]) | |
|
292 | for e in l: | |
|
293 | t = r.next() | |
|
294 | if accumulate: accumulate(t) | |
|
295 | self.addrevision(t, transaction, linkseq.next(), e[1], e[2]) | |
|
296 | ||
|
297 | # return the unmerged heads for later resolving | |
|
298 | return (old, self.tip()) | |
|
299 | ||
|
300 | 269 | def group(self, linkmap): |
|
301 | 270 | # given a list of changeset revs, return a set of deltas and |
|
302 | # metadata corresponding to nodes the first delta is | |
|
271 | # metadata corresponding to nodes. the first delta is | |
|
303 | 272 | # parent(nodes[0]) -> nodes[0] the receiver is guaranteed to |
|
304 | 273 | # have this parent as it has all history before these |
|
305 | 274 | # changesets. parent is parent[0] |
@@ -440,9 +409,9 b' class revlog:' | |||
|
440 | 409 | while pos < len(data): |
|
441 | 410 | l, node, p1, p2, cs = struct.unpack(">l20s20s20s20s", |
|
442 | 411 | data[pos:pos+84]) |
|
412 | link = linkmapper(cs) | |
|
443 | 413 | if node in self.nodemap: |
|
444 | 414 | raise "already have %s" % hex(node[:4]) |
|
445 | link = linkmapper(cs) | |
|
446 | 415 | delta = data[pos + 84:pos + l] |
|
447 | 416 | pos += l |
|
448 | 417 |
General Comments 0
You need to be logged in to leave comments.
Login now