Mercurial > public > mercurial-scm > hg
comparison mercurial/localrepo.py @ 1680:c21b54f7f7b8
Merge with crew
author | Benoit Boissinot <benoit.boissinot@ens-lyon.org> |
---|---|
date | Wed, 01 Feb 2006 19:18:15 +0100 |
parents | 675ca845c2f8 dee55c4a4963 |
children | 20b621154e17 |
comparison
equal
deleted
inserted
replaced
1679:675ca845c2f8 | 1680:c21b54f7f7b8 |
---|---|
17 if not path: | 17 if not path: |
18 p = os.getcwd() | 18 p = os.getcwd() |
19 while not os.path.isdir(os.path.join(p, ".hg")): | 19 while not os.path.isdir(os.path.join(p, ".hg")): |
20 oldp = p | 20 oldp = p |
21 p = os.path.dirname(p) | 21 p = os.path.dirname(p) |
22 if p == oldp: raise repo.RepoError(_("no repo found")) | 22 if p == oldp: |
23 raise repo.RepoError(_("no repo found")) | |
23 path = p | 24 path = p |
24 self.path = os.path.join(path, ".hg") | 25 self.path = os.path.join(path, ".hg") |
25 | 26 |
26 if not create and not os.path.isdir(self.path): | 27 if not create and not os.path.isdir(self.path): |
27 raise repo.RepoError(_("repository %s not found") % path) | 28 raise repo.RepoError(_("repository %s not found") % path) |
42 os.mkdir(self.join("data")) | 43 os.mkdir(self.join("data")) |
43 | 44 |
44 self.dirstate = dirstate.dirstate(self.opener, ui, self.root) | 45 self.dirstate = dirstate.dirstate(self.opener, ui, self.root) |
45 try: | 46 try: |
46 self.ui.readconfig(self.join("hgrc")) | 47 self.ui.readconfig(self.join("hgrc")) |
47 except IOError: pass | 48 except IOError: |
49 pass | |
48 | 50 |
49 def hook(self, name, **args): | 51 def hook(self, name, **args): |
50 def runhook(name, cmd): | 52 def runhook(name, cmd): |
51 self.ui.note(_("running hook %s: %s\n") % (name, cmd)) | 53 self.ui.note(_("running hook %s: %s\n") % (name, cmd)) |
52 old = {} | 54 old = {} |
124 for t, n in self.tags().items(): | 126 for t, n in self.tags().items(): |
125 try: | 127 try: |
126 r = self.changelog.rev(n) | 128 r = self.changelog.rev(n) |
127 except: | 129 except: |
128 r = -2 # sort to the beginning of the list if unknown | 130 r = -2 # sort to the beginning of the list if unknown |
129 l.append((r,t,n)) | 131 l.append((r, t, n)) |
130 l.sort() | 132 l.sort() |
131 return [(t,n) for r,t,n in l] | 133 return [(t, n) for r, t, n in l] |
132 | 134 |
133 def nodetags(self, node): | 135 def nodetags(self, node): |
134 '''return the tags associated with a node''' | 136 '''return the tags associated with a node''' |
135 if not self.nodetagscache: | 137 if not self.nodetagscache: |
136 self.nodetagscache = {} | 138 self.nodetagscache = {} |
137 for t,n in self.tags().items(): | 139 for t, n in self.tags().items(): |
138 self.nodetagscache.setdefault(n,[]).append(t) | 140 self.nodetagscache.setdefault(n, []).append(t) |
139 return self.nodetagscache.get(node, []) | 141 return self.nodetagscache.get(node, []) |
140 | 142 |
141 def lookup(self, key): | 143 def lookup(self, key): |
142 try: | 144 try: |
143 return self.tags()[key] | 145 return self.tags()[key] |
158 | 160 |
159 def wjoin(self, f): | 161 def wjoin(self, f): |
160 return os.path.join(self.root, f) | 162 return os.path.join(self.root, f) |
161 | 163 |
162 def file(self, f): | 164 def file(self, f): |
163 if f[0] == '/': f = f[1:] | 165 if f[0] == '/': |
166 f = f[1:] | |
164 return filelog.filelog(self.opener, f) | 167 return filelog.filelog(self.opener, f) |
165 | 168 |
166 def getcwd(self): | 169 def getcwd(self): |
167 return self.dirstate.getcwd() | 170 return self.dirstate.getcwd() |
168 | 171 |
224 def recover(self): | 227 def recover(self): |
225 lock = self.lock() | 228 lock = self.lock() |
226 if os.path.exists(self.join("journal")): | 229 if os.path.exists(self.join("journal")): |
227 self.ui.status(_("rolling back interrupted transaction\n")) | 230 self.ui.status(_("rolling back interrupted transaction\n")) |
228 transaction.rollback(self.opener, self.join("journal")) | 231 transaction.rollback(self.opener, self.join("journal")) |
232 self.manifest = manifest.manifest(self.opener) | |
233 self.changelog = changelog.changelog(self.opener) | |
229 return True | 234 return True |
230 else: | 235 else: |
231 self.ui.warn(_("no interrupted transaction available\n")) | 236 self.ui.warn(_("no interrupted transaction available\n")) |
232 return False | 237 return False |
233 | 238 |
332 n = self.changelog.add(mnode, changed, text, tr, p1, p2, user, date) | 337 n = self.changelog.add(mnode, changed, text, tr, p1, p2, user, date) |
333 tr.close() | 338 tr.close() |
334 if update_dirstate: | 339 if update_dirstate: |
335 self.dirstate.setparents(n, nullid) | 340 self.dirstate.setparents(n, nullid) |
336 | 341 |
337 def commit(self, files = None, text = "", user = None, date = None, | 342 def commit(self, files=None, text="", user=None, date=None, |
338 match = util.always, force=False): | 343 match=util.always, force=False): |
339 commit = [] | 344 commit = [] |
340 remove = [] | 345 remove = [] |
341 changed = [] | 346 changed = [] |
342 | 347 |
343 if files: | 348 if files: |
348 elif s == 'r': | 353 elif s == 'r': |
349 remove.append(f) | 354 remove.append(f) |
350 else: | 355 else: |
351 self.ui.warn(_("%s not tracked!\n") % f) | 356 self.ui.warn(_("%s not tracked!\n") % f) |
352 else: | 357 else: |
353 (c, a, d, u) = self.changes(match=match) | 358 modified, added, removed, deleted, unknown = self.changes(match=match) |
354 commit = c + a | 359 commit = modified + added |
355 remove = d | 360 remove = removed |
356 | 361 |
357 p1, p2 = self.dirstate.parents() | 362 p1, p2 = self.dirstate.parents() |
358 c1 = self.changelog.read(p1) | 363 c1 = self.changelog.read(p1) |
359 c2 = self.changelog.read(p2) | 364 c2 = self.changelog.read(p2) |
360 m1 = self.manifest.read(c1[0]) | 365 m1 = self.manifest.read(c1[0]) |
396 fp1, fp2 = nullid, nullid | 401 fp1, fp2 = nullid, nullid |
397 else: | 402 else: |
398 fp1 = m1.get(f, nullid) | 403 fp1 = m1.get(f, nullid) |
399 fp2 = m2.get(f, nullid) | 404 fp2 = m2.get(f, nullid) |
400 | 405 |
401 # is the same revision on two branches of a merge? | |
402 if fp2 == fp1: | |
403 fp2 = nullid | |
404 | |
405 if fp2 != nullid: | 406 if fp2 != nullid: |
406 # is one parent an ancestor of the other? | 407 # is one parent an ancestor of the other? |
407 fpa = r.ancestor(fp1, fp2) | 408 fpa = r.ancestor(fp1, fp2) |
408 if fpa == fp1: | 409 if fpa == fp1: |
409 fp1, fp2 = fp2, nullid | 410 fp1, fp2 = fp2, nullid |
410 elif fpa == fp2: | 411 elif fpa == fp2: |
411 fp2 = nullid | 412 fp2 = nullid |
412 | 413 |
413 # is the file unmodified from the parent? | 414 # is the file unmodified from the parent? |
414 if not meta and t == r.read(fp1): | 415 if not meta and t == r.read(fp1) and fp2 == nullid: |
415 # record the proper existing parent in manifest | 416 # record the proper existing parent in manifest |
416 # no need to add a revision | 417 # no need to add a revision |
417 new[f] = fp1 | 418 new[f] = fp1 |
418 continue | 419 continue |
419 | 420 |
421 # remember what we've added so that we can later calculate | 422 # remember what we've added so that we can later calculate |
422 # the files to pull from a set of changesets | 423 # the files to pull from a set of changesets |
423 changed.append(f) | 424 changed.append(f) |
424 | 425 |
425 # update manifest | 426 # update manifest |
427 m1 = m1.copy() | |
426 m1.update(new) | 428 m1.update(new) |
427 for f in remove: | 429 for f in remove: |
428 if f in m1: | 430 if f in m1: |
429 del m1[f] | 431 del m1[f] |
430 mn = self.manifest.add(m1, mf1, tr, linkrev, c1[0], c2[0], | 432 mn = self.manifest.add(m1, mf1, tr, linkrev, c1[0], c2[0], |
447 if not edittext.rstrip(): | 449 if not edittext.rstrip(): |
448 return None | 450 return None |
449 text = edittext | 451 text = edittext |
450 | 452 |
451 user = user or self.ui.username() | 453 user = user or self.ui.username() |
452 n = self.changelog.add(mn, changed, text, tr, p1, p2, user, date) | 454 n = self.changelog.add(mn, changed + remove, text, tr, p1, p2, user, date) |
453 tr.close() | 455 tr.close() |
454 | 456 |
455 self.dirstate.setparents(n) | 457 self.dirstate.setparents(n) |
456 self.dirstate.update(new, "n") | 458 self.dirstate.update(new, "n") |
457 self.dirstate.forget(remove) | 459 self.dirstate.forget(remove) |
472 util.pathto(self.getcwd(), fn), short(node))) | 474 util.pathto(self.getcwd(), fn), short(node))) |
473 else: | 475 else: |
474 for src, fn in self.dirstate.walk(files, match): | 476 for src, fn in self.dirstate.walk(files, match): |
475 yield src, fn | 477 yield src, fn |
476 | 478 |
477 def changes(self, node1 = None, node2 = None, files = [], | 479 def changes(self, node1=None, node2=None, files=[], match=util.always): |
478 match = util.always): | 480 """return changes between two nodes or node and working directory |
479 mf2, u = None, [] | 481 |
482 If node1 is None, use the first dirstate parent instead. | |
483 If node2 is None, compare node1 with working directory. | |
484 """ | |
480 | 485 |
481 def fcmp(fn, mf): | 486 def fcmp(fn, mf): |
482 t1 = self.wread(fn) | 487 t1 = self.wread(fn) |
483 t2 = self.file(fn).read(mf.get(fn, nullid)) | 488 t2 = self.file(fn).read(mf.get(fn, nullid)) |
484 return cmp(t1, t2) | 489 return cmp(t1, t2) |
485 | 490 |
486 def mfmatches(node): | 491 def mfmatches(node): |
487 mf = dict(self.manifest.read(node)) | 492 change = self.changelog.read(node) |
493 mf = dict(self.manifest.read(change[0])) | |
488 for fn in mf.keys(): | 494 for fn in mf.keys(): |
489 if not match(fn): | 495 if not match(fn): |
490 del mf[fn] | 496 del mf[fn] |
491 return mf | 497 return mf |
492 | 498 |
494 if not node2: | 500 if not node2: |
495 try: | 501 try: |
496 wlock = self.wlock(wait=0) | 502 wlock = self.wlock(wait=0) |
497 except lock.LockHeld: | 503 except lock.LockHeld: |
498 wlock = None | 504 wlock = None |
499 l, c, a, d, u = self.dirstate.changes(files, match) | 505 lookup, modified, added, removed, deleted, unknown = ( |
506 self.dirstate.changes(files, match)) | |
500 | 507 |
501 # are we comparing working dir against its parent? | 508 # are we comparing working dir against its parent? |
502 if not node1: | 509 if not node1: |
503 if l: | 510 if lookup: |
504 # do a full compare of any files that might have changed | 511 # do a full compare of any files that might have changed |
505 change = self.changelog.read(self.dirstate.parents()[0]) | 512 mf2 = mfmatches(self.dirstate.parents()[0]) |
506 mf2 = mfmatches(change[0]) | 513 for f in lookup: |
507 for f in l: | |
508 if fcmp(f, mf2): | 514 if fcmp(f, mf2): |
509 c.append(f) | 515 modified.append(f) |
510 elif wlock is not None: | 516 elif wlock is not None: |
511 self.dirstate.update([f], "n") | 517 self.dirstate.update([f], "n") |
512 | 518 else: |
513 for l in c, a, d, u: | 519 # we are comparing working dir against non-parent |
514 l.sort() | 520 # generate a pseudo-manifest for the working dir |
515 | 521 mf2 = mfmatches(self.dirstate.parents()[0]) |
516 return (c, a, d, u) | 522 for f in lookup + modified + added: |
517 | 523 mf2[f] = "" |
518 # are we comparing working dir against non-tip? | 524 for f in removed: |
519 # generate a pseudo-manifest for the working dir | 525 if f in mf2: |
520 if not node2: | 526 del mf2[f] |
521 if not mf2: | |
522 change = self.changelog.read(self.dirstate.parents()[0]) | |
523 mf2 = mfmatches(change[0]) | |
524 for f in a + c + l: | |
525 mf2[f] = "" | |
526 for f in d: | |
527 if f in mf2: del mf2[f] | |
528 else: | 527 else: |
529 change = self.changelog.read(node2) | 528 # we are comparing two revisions |
530 mf2 = mfmatches(change[0]) | 529 deleted, unknown = [], [] |
531 | 530 mf2 = mfmatches(node2) |
532 # flush lists from dirstate before comparing manifests | 531 |
533 c, a = [], [] | 532 if node1: |
534 | 533 # flush lists from dirstate before comparing manifests |
535 change = self.changelog.read(node1) | 534 modified, added = [], [] |
536 mf1 = mfmatches(change[0]) | 535 |
537 | 536 mf1 = mfmatches(node1) |
538 for fn in mf2: | 537 |
539 if mf1.has_key(fn): | 538 for fn in mf2: |
540 if mf1[fn] != mf2[fn]: | 539 if mf1.has_key(fn): |
541 if mf2[fn] != "" or fcmp(fn, mf1): | 540 if mf1[fn] != mf2[fn] and (mf2[fn] != "" or fcmp(fn, mf1)): |
542 c.append(fn) | 541 modified.append(fn) |
543 del mf1[fn] | 542 del mf1[fn] |
544 else: | 543 else: |
545 a.append(fn) | 544 added.append(fn) |
546 | 545 |
547 d = mf1.keys() | 546 removed = mf1.keys() |
548 | 547 |
549 for l in c, a, d, u: | 548 # sort and return results: |
549 for l in modified, added, removed, deleted, unknown: | |
550 l.sort() | 550 l.sort() |
551 | 551 return (modified, added, removed, deleted, unknown) |
552 return (c, a, d, u) | |
553 | 552 |
554 def add(self, list): | 553 def add(self, list): |
555 wlock = self.wlock() | 554 wlock = self.wlock() |
556 for f in list: | 555 for f in list: |
557 p = self.wjoin(f) | 556 p = self.wjoin(f) |
558 if not os.path.exists(p): | 557 if not os.path.exists(p): |
559 self.ui.warn(_("%s does not exist!\n") % f) | 558 self.ui.warn(_("%s does not exist!\n") % f) |
560 elif not os.path.isfile(p): | 559 elif not os.path.isfile(p): |
561 self.ui.warn(_("%s not added: only files supported currently\n") % f) | 560 self.ui.warn(_("%s not added: only files supported currently\n") |
561 % f) | |
562 elif self.dirstate.state(f) in 'an': | 562 elif self.dirstate.state(f) in 'an': |
563 self.ui.warn(_("%s already tracked!\n") % f) | 563 self.ui.warn(_("%s already tracked!\n") % f) |
564 else: | 564 else: |
565 self.dirstate.update([f], "a") | 565 self.dirstate.update([f], "a") |
566 | 566 |
576 if unlink: | 576 if unlink: |
577 for f in list: | 577 for f in list: |
578 try: | 578 try: |
579 util.unlink(self.wjoin(f)) | 579 util.unlink(self.wjoin(f)) |
580 except OSError, inst: | 580 except OSError, inst: |
581 if inst.errno != errno.ENOENT: raise | 581 if inst.errno != errno.ENOENT: |
582 raise | |
582 wlock = self.wlock() | 583 wlock = self.wlock() |
583 for f in list: | 584 for f in list: |
584 p = self.wjoin(f) | 585 p = self.wjoin(f) |
585 if os.path.exists(p): | 586 if os.path.exists(p): |
586 self.ui.warn(_("%s still exists!\n") % f) | 587 self.ui.warn(_("%s still exists!\n") % f) |
731 l = out.setdefault(h, []) | 732 l = out.setdefault(h, []) |
732 l[len(l):] = self.nodetags(b) | 733 l[len(l):] = self.nodetags(b) |
733 return out | 734 return out |
734 | 735 |
735 def branches(self, nodes): | 736 def branches(self, nodes): |
736 if not nodes: nodes = [self.changelog.tip()] | 737 if not nodes: |
738 nodes = [self.changelog.tip()] | |
737 b = [] | 739 b = [] |
738 for n in nodes: | 740 for n in nodes: |
739 t = n | 741 t = n |
740 while n: | 742 while n: |
741 p = self.changelog.parents(n) | 743 p = self.changelog.parents(n) |
803 while unknown: | 805 while unknown: |
804 n = unknown.pop(0) | 806 n = unknown.pop(0) |
805 if n[0] in seen: | 807 if n[0] in seen: |
806 continue | 808 continue |
807 | 809 |
808 self.ui.debug(_("examining %s:%s\n") % (short(n[0]), short(n[1]))) | 810 self.ui.debug(_("examining %s:%s\n") |
811 % (short(n[0]), short(n[1]))) | |
809 if n[0] == nullid: | 812 if n[0] == nullid: |
810 break | 813 break |
811 if n in seenbranch: | 814 if n in seenbranch: |
812 self.ui.debug(_("branch already found\n")) | 815 self.ui.debug(_("branch already found\n")) |
813 continue | 816 continue |
839 for p in range(0, len(r), 10): | 842 for p in range(0, len(r), 10): |
840 for b in remote.branches(r[p:p+10]): | 843 for b in remote.branches(r[p:p+10]): |
841 self.ui.debug(_("received %s:%s\n") % | 844 self.ui.debug(_("received %s:%s\n") % |
842 (short(b[0]), short(b[1]))) | 845 (short(b[0]), short(b[1]))) |
843 if b[0] in m: | 846 if b[0] in m: |
844 self.ui.debug(_("found base node %s\n") % short(b[0])) | 847 self.ui.debug(_("found base node %s\n") |
848 % short(b[0])) | |
845 base[b[0]] = 1 | 849 base[b[0]] = 1 |
846 elif b[0] not in seen: | 850 elif b[0] not in seen: |
847 unknown.append(b) | 851 unknown.append(b) |
848 | 852 |
849 # do binary search on the branches we found | 853 # do binary search on the branches we found |
912 subset.append(n) | 916 subset.append(n) |
913 | 917 |
914 # this is the set of all roots we have to push | 918 # this is the set of all roots we have to push |
915 return subset | 919 return subset |
916 | 920 |
917 def pull(self, remote, heads = None): | 921 def pull(self, remote, heads=None): |
918 lock = self.lock() | 922 lock = self.lock() |
919 | 923 |
920 # if we have an empty repo, fetch everything | 924 # if we have an empty repo, fetch everything |
921 if self.changelog.tip() == nullid: | 925 if self.changelog.tip() == nullid: |
922 self.ui.status(_("requesting all changes\n")) | 926 self.ui.status(_("requesting all changes\n")) |
1197 # Go through all our files in order sorted by name. | 1201 # Go through all our files in order sorted by name. |
1198 for fname in changedfiles: | 1202 for fname in changedfiles: |
1199 filerevlog = self.file(fname) | 1203 filerevlog = self.file(fname) |
1200 # Toss out the filenodes that the recipient isn't really | 1204 # Toss out the filenodes that the recipient isn't really |
1201 # missing. | 1205 # missing. |
1202 prune_filenodes(fname, filerevlog) | 1206 if msng_filenode_set.has_key(fname): |
1203 msng_filenode_lst = msng_filenode_set[fname].keys() | 1207 prune_filenodes(fname, filerevlog) |
1208 msng_filenode_lst = msng_filenode_set[fname].keys() | |
1209 else: | |
1210 msng_filenode_lst = [] | |
1204 # If any filenodes are left, generate the group for them, | 1211 # If any filenodes are left, generate the group for them, |
1205 # otherwise don't bother. | 1212 # otherwise don't bother. |
1206 if len(msng_filenode_lst) > 0: | 1213 if len(msng_filenode_lst) > 0: |
1207 yield struct.pack(">l", len(fname) + 4) + fname | 1214 yield struct.pack(">l", len(fname) + 4) + fname |
1208 # Sort the filenodes by their revision # | 1215 # Sort the filenodes by their revision # |
1212 # from filenodes. | 1219 # from filenodes. |
1213 group = filerevlog.group(msng_filenode_lst, | 1220 group = filerevlog.group(msng_filenode_lst, |
1214 lookup_filenode_link_func(fname)) | 1221 lookup_filenode_link_func(fname)) |
1215 for chnk in group: | 1222 for chnk in group: |
1216 yield chnk | 1223 yield chnk |
1217 # Don't need this anymore, toss it to free memory. | 1224 if msng_filenode_set.has_key(fname): |
1218 del msng_filenode_set[fname] | 1225 # Don't need this anymore, toss it to free memory. |
1226 del msng_filenode_set[fname] | |
1219 # Signal that no more groups are left. | 1227 # Signal that no more groups are left. |
1220 yield struct.pack(">l", 0) | 1228 yield struct.pack(">l", 0) |
1221 | 1229 |
1222 return util.chunkbuffer(gengroup()) | 1230 return util.chunkbuffer(gengroup()) |
1223 | 1231 |
1283 | 1291 |
1284 def addchangegroup(self, source): | 1292 def addchangegroup(self, source): |
1285 | 1293 |
1286 def getchunk(): | 1294 def getchunk(): |
1287 d = source.read(4) | 1295 d = source.read(4) |
1288 if not d: return "" | 1296 if not d: |
1297 return "" | |
1289 l = struct.unpack(">l", d)[0] | 1298 l = struct.unpack(">l", d)[0] |
1290 if l <= 4: return "" | 1299 if l <= 4: |
1300 return "" | |
1291 d = source.read(l - 4) | 1301 d = source.read(l - 4) |
1292 if len(d) < l - 4: | 1302 if len(d) < l - 4: |
1293 raise repo.RepoError(_("premature EOF reading chunk" | 1303 raise repo.RepoError(_("premature EOF reading chunk" |
1294 " (got %d bytes, expected %d)") | 1304 " (got %d bytes, expected %d)") |
1295 % (len(d), l - 4)) | 1305 % (len(d), l - 4)) |
1296 return d | 1306 return d |
1297 | 1307 |
1298 def getgroup(): | 1308 def getgroup(): |
1299 while 1: | 1309 while 1: |
1300 c = getchunk() | 1310 c = getchunk() |
1301 if not c: break | 1311 if not c: |
1312 break | |
1302 yield c | 1313 yield c |
1303 | 1314 |
1304 def csmap(x): | 1315 def csmap(x): |
1305 self.ui.debug(_("add changeset %s\n") % short(x)) | 1316 self.ui.debug(_("add changeset %s\n") % short(x)) |
1306 return self.changelog.count() | 1317 return self.changelog.count() |
1307 | 1318 |
1308 def revmap(x): | 1319 def revmap(x): |
1309 return self.changelog.rev(x) | 1320 return self.changelog.rev(x) |
1310 | 1321 |
1311 if not source: return | 1322 if not source: |
1323 return | |
1312 changesets = files = revisions = 0 | 1324 changesets = files = revisions = 0 |
1313 | 1325 |
1314 tr = self.transaction() | 1326 tr = self.transaction() |
1315 | 1327 |
1316 oldheads = len(self.changelog.heads()) | 1328 oldheads = len(self.changelog.heads()) |
1331 | 1343 |
1332 # process the files | 1344 # process the files |
1333 self.ui.status(_("adding file changes\n")) | 1345 self.ui.status(_("adding file changes\n")) |
1334 while 1: | 1346 while 1: |
1335 f = getchunk() | 1347 f = getchunk() |
1336 if not f: break | 1348 if not f: |
1349 break | |
1337 self.ui.debug(_("adding %s revisions\n") % f) | 1350 self.ui.debug(_("adding %s revisions\n") % f) |
1338 fl = self.file(f) | 1351 fl = self.file(f) |
1339 o = fl.count() | 1352 o = fl.count() |
1340 n = fl.addgroup(getgroup(), revmap, tr) | 1353 n = fl.addgroup(getgroup(), revmap, tr) |
1341 revisions += fl.count() - o | 1354 revisions += fl.count() - o |
1352 | 1365 |
1353 tr.close() | 1366 tr.close() |
1354 | 1367 |
1355 if changesets > 0: | 1368 if changesets > 0: |
1356 if not self.hook("changegroup", | 1369 if not self.hook("changegroup", |
1357 node=hex(self.changelog.node(cor+1))): | 1370 node=hex(self.changelog.node(cor+1))): |
1358 self.ui.warn(_("abort: changegroup hook returned failure!\n")) | 1371 self.ui.warn(_("abort: changegroup hook returned failure!\n")) |
1359 return 1 | 1372 return 1 |
1360 | 1373 |
1361 for i in range(cor + 1, cnr + 1): | 1374 for i in range(cor + 1, cnr + 1): |
1362 self.hook("commit", node=hex(self.changelog.node(i))) | 1375 self.hook("commit", node=hex(self.changelog.node(i))) |
1367 moddirstate=True, forcemerge=False): | 1380 moddirstate=True, forcemerge=False): |
1368 pl = self.dirstate.parents() | 1381 pl = self.dirstate.parents() |
1369 if not force and pl[1] != nullid: | 1382 if not force and pl[1] != nullid: |
1370 self.ui.warn(_("aborting: outstanding uncommitted merges\n")) | 1383 self.ui.warn(_("aborting: outstanding uncommitted merges\n")) |
1371 return 1 | 1384 return 1 |
1385 | |
1386 err = False | |
1372 | 1387 |
1373 p1, p2 = pl[0], node | 1388 p1, p2 = pl[0], node |
1374 pa = self.changelog.ancestor(p1, p2) | 1389 pa = self.changelog.ancestor(p1, p2) |
1375 m1n = self.changelog.read(p1)[0] | 1390 m1n = self.changelog.read(p1)[0] |
1376 m2n = self.changelog.read(p2)[0] | 1391 m2n = self.changelog.read(p2)[0] |
1377 man = self.manifest.ancestor(m1n, m2n) | 1392 man = self.manifest.ancestor(m1n, m2n) |
1378 m1 = self.manifest.read(m1n) | 1393 m1 = self.manifest.read(m1n) |
1379 mf1 = self.manifest.readflags(m1n) | 1394 mf1 = self.manifest.readflags(m1n) |
1380 m2 = self.manifest.read(m2n) | 1395 m2 = self.manifest.read(m2n).copy() |
1381 mf2 = self.manifest.readflags(m2n) | 1396 mf2 = self.manifest.readflags(m2n) |
1382 ma = self.manifest.read(man) | 1397 ma = self.manifest.read(man) |
1383 mfa = self.manifest.readflags(man) | 1398 mfa = self.manifest.readflags(man) |
1384 | 1399 |
1385 (c, a, d, u) = self.changes() | 1400 modified, added, removed, deleted, unknown = self.changes() |
1386 | |
1387 if allow and not forcemerge: | |
1388 if c or a or d: | |
1389 raise util.Abort(_("outstanding uncommited changes")) | |
1390 if not forcemerge and not force: | |
1391 for f in u: | |
1392 if f in m2: | |
1393 t1 = self.wread(f) | |
1394 t2 = self.file(f).read(m2[f]) | |
1395 if cmp(t1, t2) != 0: | |
1396 raise util.Abort(_("'%s' already exists in the working" | |
1397 " dir and differs from remote") % f) | |
1398 | 1401 |
1399 # is this a jump, or a merge? i.e. is there a linear path | 1402 # is this a jump, or a merge? i.e. is there a linear path |
1400 # from p1 to p2? | 1403 # from p1 to p2? |
1401 linear_path = (pa == p1 or pa == p2) | 1404 linear_path = (pa == p1 or pa == p2) |
1405 | |
1406 if allow and linear_path: | |
1407 raise util.Abort(_("there is nothing to merge, " | |
1408 "just use 'hg update'")) | |
1409 if allow and not forcemerge: | |
1410 if modified or added or removed: | |
1411 raise util.Abort(_("outstanding uncommited changes")) | |
1412 if not forcemerge and not force: | |
1413 for f in unknown: | |
1414 if f in m2: | |
1415 t1 = self.wread(f) | |
1416 t2 = self.file(f).read(m2[f]) | |
1417 if cmp(t1, t2) != 0: | |
1418 raise util.Abort(_("'%s' already exists in the working" | |
1419 " dir and differs from remote") % f) | |
1402 | 1420 |
1403 # resolve the manifest to determine which files | 1421 # resolve the manifest to determine which files |
1404 # we care about merging | 1422 # we care about merging |
1405 self.ui.note(_("resolving manifests\n")) | 1423 self.ui.note(_("resolving manifests\n")) |
1406 self.ui.debug(_(" force %s allow %s moddirstate %s linear %s\n") % | 1424 self.ui.debug(_(" force %s allow %s moddirstate %s linear %s\n") % |
1413 remove = [] | 1431 remove = [] |
1414 | 1432 |
1415 # construct a working dir manifest | 1433 # construct a working dir manifest |
1416 mw = m1.copy() | 1434 mw = m1.copy() |
1417 mfw = mf1.copy() | 1435 mfw = mf1.copy() |
1418 umap = dict.fromkeys(u) | 1436 umap = dict.fromkeys(unknown) |
1419 | 1437 |
1420 for f in a + c + u: | 1438 for f in added + modified + unknown: |
1421 mw[f] = "" | 1439 mw[f] = "" |
1422 mfw[f] = util.is_exec(self.wjoin(f), mfw.get(f, False)) | 1440 mfw[f] = util.is_exec(self.wjoin(f), mfw.get(f, False)) |
1423 | 1441 |
1424 if moddirstate: | 1442 if moddirstate: |
1425 wlock = self.wlock() | 1443 wlock = self.wlock() |
1426 | 1444 |
1427 for f in d: | 1445 for f in deleted + removed: |
1428 if f in mw: del mw[f] | 1446 if f in mw: |
1447 del mw[f] | |
1429 | 1448 |
1430 # If we're jumping between revisions (as opposed to merging), | 1449 # If we're jumping between revisions (as opposed to merging), |
1431 # and if neither the working directory nor the target rev has | 1450 # and if neither the working directory nor the target rev has |
1432 # the file, then we need to remove it from the dirstate, to | 1451 # the file, then we need to remove it from the dirstate, to |
1433 # prevent the dirstate from listing the file when it is no | 1452 # prevent the dirstate from listing the file when it is no |
1435 if moddirstate and linear_path and f not in m2: | 1454 if moddirstate and linear_path and f not in m2: |
1436 self.dirstate.forget((f,)) | 1455 self.dirstate.forget((f,)) |
1437 | 1456 |
1438 # Compare manifests | 1457 # Compare manifests |
1439 for f, n in mw.iteritems(): | 1458 for f, n in mw.iteritems(): |
1440 if choose and not choose(f): continue | 1459 if choose and not choose(f): |
1460 continue | |
1441 if f in m2: | 1461 if f in m2: |
1442 s = 0 | 1462 s = 0 |
1443 | 1463 |
1444 # is the wfile new since m1, and match m2? | 1464 # is the wfile new since m1, and match m2? |
1445 if f not in m1: | 1465 if f not in m1: |
1478 util.set_exec(self.wjoin(f), mf2[f]) | 1498 util.set_exec(self.wjoin(f), mf2[f]) |
1479 else: | 1499 else: |
1480 a, b, c = mfa.get(f, 0), mfw[f], mf2[f] | 1500 a, b, c = mfa.get(f, 0), mfw[f], mf2[f] |
1481 mode = ((a^b) | (a^c)) ^ a | 1501 mode = ((a^b) | (a^c)) ^ a |
1482 if mode != b: | 1502 if mode != b: |
1483 self.ui.debug(_(" updating permissions for %s\n") % f) | 1503 self.ui.debug(_(" updating permissions for %s\n") |
1504 % f) | |
1484 util.set_exec(self.wjoin(f), mode) | 1505 util.set_exec(self.wjoin(f), mode) |
1485 del m2[f] | 1506 del m2[f] |
1486 elif f in ma: | 1507 elif f in ma: |
1487 if n != ma[f]: | 1508 if n != ma[f]: |
1488 r = _("d") | 1509 r = _("d") |
1508 self.ui.debug(_("local modified %s, keeping\n") % f) | 1529 self.ui.debug(_("local modified %s, keeping\n") % f) |
1509 else: | 1530 else: |
1510 self.ui.debug(_("working dir created %s, keeping\n") % f) | 1531 self.ui.debug(_("working dir created %s, keeping\n") % f) |
1511 | 1532 |
1512 for f, n in m2.iteritems(): | 1533 for f, n in m2.iteritems(): |
1513 if choose and not choose(f): continue | 1534 if choose and not choose(f): |
1514 if f[0] == "/": continue | 1535 continue |
1536 if f[0] == "/": | |
1537 continue | |
1515 if f in ma and n != ma[f]: | 1538 if f in ma and n != ma[f]: |
1516 r = _("k") | 1539 r = _("k") |
1517 if not force and (linear_path or allow): | 1540 if not force and (linear_path or allow): |
1518 r = self.ui.prompt( | 1541 r = self.ui.prompt( |
1519 (_("remote changed %s which local deleted\n") % f) + | 1542 (_("remote changed %s which local deleted\n") % f) + |
1520 _("(k)eep or (d)elete?"), _("[kd]"), _("k")) | 1543 _("(k)eep or (d)elete?"), _("[kd]"), _("k")) |
1521 if r == _("k"): get[f] = n | 1544 if r == _("k"): |
1545 get[f] = n | |
1522 elif f not in ma: | 1546 elif f not in ma: |
1523 self.ui.debug(_("remote created %s\n") % f) | 1547 self.ui.debug(_("remote created %s\n") % f) |
1524 get[f] = n | 1548 get[f] = n |
1525 else: | 1549 else: |
1526 if force or p2 == pa: # going backwards? | 1550 if force or p2 == pa: # going backwards? |
1546 " affecting the following files:\n")) | 1570 " affecting the following files:\n")) |
1547 fl = merge.keys() + get.keys() | 1571 fl = merge.keys() + get.keys() |
1548 fl.sort() | 1572 fl.sort() |
1549 for f in fl: | 1573 for f in fl: |
1550 cf = "" | 1574 cf = "" |
1551 if f in merge: cf = _(" (resolve)") | 1575 if f in merge: |
1576 cf = _(" (resolve)") | |
1552 self.ui.status(" %s%s\n" % (f, cf)) | 1577 self.ui.status(" %s%s\n" % (f, cf)) |
1553 self.ui.warn(_("aborting update spanning branches!\n")) | 1578 self.ui.warn(_("aborting update spanning branches!\n")) |
1554 self.ui.status(_("(use update -m to merge across branches" | 1579 self.ui.status(_("(use update -m to merge across branches" |
1555 " or -C to lose changes)\n")) | 1580 " or -C to lose changes)\n")) |
1556 return 1 | 1581 return 1 |
1558 | 1583 |
1559 # get the files we don't need to change | 1584 # get the files we don't need to change |
1560 files = get.keys() | 1585 files = get.keys() |
1561 files.sort() | 1586 files.sort() |
1562 for f in files: | 1587 for f in files: |
1563 if f[0] == "/": continue | 1588 if f[0] == "/": |
1589 continue | |
1564 self.ui.note(_("getting %s\n") % f) | 1590 self.ui.note(_("getting %s\n") % f) |
1565 t = self.file(f).read(get[f]) | 1591 t = self.file(f).read(get[f]) |
1566 self.wwrite(f, t) | 1592 self.wwrite(f, t) |
1567 util.set_exec(self.wjoin(f), mf2[f]) | 1593 util.set_exec(self.wjoin(f), mf2[f]) |
1568 if moddirstate: | 1594 if moddirstate: |
1575 files = merge.keys() | 1601 files = merge.keys() |
1576 files.sort() | 1602 files.sort() |
1577 for f in files: | 1603 for f in files: |
1578 self.ui.status(_("merging %s\n") % f) | 1604 self.ui.status(_("merging %s\n") % f) |
1579 my, other, flag = merge[f] | 1605 my, other, flag = merge[f] |
1580 self.merge3(f, my, other) | 1606 ret = self.merge3(f, my, other) |
1607 if ret: | |
1608 err = True | |
1581 util.set_exec(self.wjoin(f), flag) | 1609 util.set_exec(self.wjoin(f), flag) |
1582 if moddirstate: | 1610 if moddirstate: |
1583 if branch_merge: | 1611 if branch_merge: |
1584 # We've done a branch merge, mark this file as merged | 1612 # We've done a branch merge, mark this file as merged |
1585 # so that we properly record the merger later | 1613 # so that we properly record the merger later |
1608 else: | 1636 else: |
1609 self.dirstate.forget(remove) | 1637 self.dirstate.forget(remove) |
1610 | 1638 |
1611 if moddirstate: | 1639 if moddirstate: |
1612 self.dirstate.setparents(p1, p2) | 1640 self.dirstate.setparents(p1, p2) |
1641 return err | |
1613 | 1642 |
1614 def merge3(self, fn, my, other): | 1643 def merge3(self, fn, my, other): |
1615 """perform a 3-way merge in the working directory""" | 1644 """perform a 3-way merge in the working directory""" |
1616 | 1645 |
1617 def temp(prefix, node): | 1646 def temp(prefix, node): |
1638 if r: | 1667 if r: |
1639 self.ui.warn(_("merging %s failed!\n") % fn) | 1668 self.ui.warn(_("merging %s failed!\n") % fn) |
1640 | 1669 |
1641 os.unlink(b) | 1670 os.unlink(b) |
1642 os.unlink(c) | 1671 os.unlink(c) |
1672 return r | |
1643 | 1673 |
1644 def verify(self): | 1674 def verify(self): |
1645 filelinkrevs = {} | 1675 filelinkrevs = {} |
1646 filenodes = {} | 1676 filenodes = {} |
1647 changesets = revisions = files = 0 | 1677 changesets = revisions = files = 0 |
1650 | 1680 |
1651 def err(msg): | 1681 def err(msg): |
1652 self.ui.warn(msg + "\n") | 1682 self.ui.warn(msg + "\n") |
1653 errors[0] += 1 | 1683 errors[0] += 1 |
1654 | 1684 |
1685 def checksize(obj, name): | |
1686 d = obj.checksize() | |
1687 if d[0]: | |
1688 err(_("%s data length off by %d bytes") % (name, d[0])) | |
1689 if d[1]: | |
1690 err(_("%s index contains %d extra bytes") % (name, d[1])) | |
1691 | |
1655 seen = {} | 1692 seen = {} |
1656 self.ui.status(_("checking changesets\n")) | 1693 self.ui.status(_("checking changesets\n")) |
1657 d = self.changelog.checksize() | 1694 checksize(self.changelog, "changelog") |
1658 if d: | 1695 |
1659 err(_("changeset data short %d bytes") % d) | |
1660 for i in range(self.changelog.count()): | 1696 for i in range(self.changelog.count()): |
1661 changesets += 1 | 1697 changesets += 1 |
1662 n = self.changelog.node(i) | 1698 n = self.changelog.node(i) |
1663 l = self.changelog.linkrev(n) | 1699 l = self.changelog.linkrev(n) |
1664 if l != i: | 1700 if l != i: |
1684 for f in changes[3]: | 1720 for f in changes[3]: |
1685 filelinkrevs.setdefault(f, []).append(i) | 1721 filelinkrevs.setdefault(f, []).append(i) |
1686 | 1722 |
1687 seen = {} | 1723 seen = {} |
1688 self.ui.status(_("checking manifests\n")) | 1724 self.ui.status(_("checking manifests\n")) |
1689 d = self.manifest.checksize() | 1725 checksize(self.manifest, "manifest") |
1690 if d: | 1726 |
1691 err(_("manifest data short %d bytes") % d) | |
1692 for i in range(self.manifest.count()): | 1727 for i in range(self.manifest.count()): |
1693 n = self.manifest.node(i) | 1728 n = self.manifest.node(i) |
1694 l = self.manifest.linkrev(n) | 1729 l = self.manifest.linkrev(n) |
1695 | 1730 |
1696 if l < 0 or l >= self.changelog.count(): | 1731 if l < 0 or l >= self.changelog.count(): |
1721 for f, fn in ff: | 1756 for f, fn in ff: |
1722 filenodes.setdefault(f, {})[bin(fn[:40])] = 1 | 1757 filenodes.setdefault(f, {})[bin(fn[:40])] = 1 |
1723 | 1758 |
1724 self.ui.status(_("crosschecking files in changesets and manifests\n")) | 1759 self.ui.status(_("crosschecking files in changesets and manifests\n")) |
1725 | 1760 |
1726 for m,c in neededmanifests.items(): | 1761 for m, c in neededmanifests.items(): |
1727 err(_("Changeset %s refers to unknown manifest %s") % | 1762 err(_("Changeset %s refers to unknown manifest %s") % |
1728 (short(m), short(c))) | 1763 (short(m), short(c))) |
1729 del neededmanifests | 1764 del neededmanifests |
1730 | 1765 |
1731 for f in filenodes: | 1766 for f in filenodes: |
1738 | 1773 |
1739 self.ui.status(_("checking files\n")) | 1774 self.ui.status(_("checking files\n")) |
1740 ff = filenodes.keys() | 1775 ff = filenodes.keys() |
1741 ff.sort() | 1776 ff.sort() |
1742 for f in ff: | 1777 for f in ff: |
1743 if f == "/dev/null": continue | 1778 if f == "/dev/null": |
1779 continue | |
1744 files += 1 | 1780 files += 1 |
1745 fl = self.file(f) | 1781 fl = self.file(f) |
1746 d = fl.checksize() | 1782 checksize(fl, f) |
1747 if d: | 1783 |
1748 err(_("%s file data short %d bytes") % (f, d)) | 1784 nodes = {nullid: 1} |
1749 | |
1750 nodes = { nullid: 1 } | |
1751 seen = {} | 1785 seen = {} |
1752 for i in range(fl.count()): | 1786 for i in range(fl.count()): |
1753 revisions += 1 | 1787 revisions += 1 |
1754 n = fl.node(i) | 1788 n = fl.node(i) |
1755 | 1789 |