Show More
@@ -0,0 +1,45 b'' | |||||
|
1 | #!/bin/sh | |||
|
2 | # http://www.selenic.com/mercurial/bts/issue322 | |||
|
3 | ||||
|
4 | echo % file replaced with directory | |||
|
5 | ||||
|
6 | hg init a | |||
|
7 | cd a | |||
|
8 | echo a > a | |||
|
9 | hg commit -Ama | |||
|
10 | rm a | |||
|
11 | mkdir a | |||
|
12 | echo a > a/a | |||
|
13 | ||||
|
14 | echo % should fail - would corrupt dirstate | |||
|
15 | hg add a/a | |||
|
16 | ||||
|
17 | echo % should fail - if add succeeded, would corrupt manifest | |||
|
18 | hg commit -mb | |||
|
19 | ||||
|
20 | echo % should fail if commit succeeded - manifest is corrupt | |||
|
21 | hg verify | |||
|
22 | ||||
|
23 | cd .. | |||
|
24 | echo % should succeed, but manifest is corrupt | |||
|
25 | hg --debug --traceback clone a b | |||
|
26 | ||||
|
27 | echo % directory replaced with file | |||
|
28 | ||||
|
29 | hg init c | |||
|
30 | cd c | |||
|
31 | mkdir a | |||
|
32 | echo a > a/a | |||
|
33 | hg commit -Ama | |||
|
34 | ||||
|
35 | rm -rf a | |||
|
36 | echo a > a | |||
|
37 | ||||
|
38 | echo % should fail - would corrupt dirstate | |||
|
39 | hg add a | |||
|
40 | ||||
|
41 | echo % should fail - if add succeeded, would corrupt manifest | |||
|
42 | hg commit -mb a | |||
|
43 | ||||
|
44 | echo % should fail if commit succeeded - manifest is corrupt | |||
|
45 | hg verify |
@@ -4,6 +4,7 b' Goffredo Baroncelli <kreijack at libero.' | |||||
4 | Muli Ben-Yehuda <mulix at mulix.org> |
|
4 | Muli Ben-Yehuda <mulix at mulix.org> | |
5 | Mikael Berthe <mikael at lilotux.net> |
|
5 | Mikael Berthe <mikael at lilotux.net> | |
6 | Benoit Boissinot <bboissin at gmail.com> |
|
6 | Benoit Boissinot <bboissin at gmail.com> | |
|
7 | Brendan Cully <brendan at kublai.com> | |||
7 | Vincent Danjean <vdanjean.ml at free.fr> |
|
8 | Vincent Danjean <vdanjean.ml at free.fr> | |
8 | Jake Edge <jake at edge2.net> |
|
9 | Jake Edge <jake at edge2.net> | |
9 | Michael Fetterman <michael.fetterman at intel.com> |
|
10 | Michael Fetterman <michael.fetterman at intel.com> |
@@ -252,6 +252,9 b' class queue:' | |||||
252 |
|
252 | |||
253 | for line in file(pf): |
|
253 | for line in file(pf): | |
254 | line = line.rstrip() |
|
254 | line = line.rstrip() | |
|
255 | if line.startswith('diff --git'): | |||
|
256 | diffstart = 2 | |||
|
257 | break | |||
255 | if diffstart: |
|
258 | if diffstart: | |
256 | if line.startswith('+++ '): |
|
259 | if line.startswith('+++ '): | |
257 | diffstart = 2 |
|
260 | diffstart = 2 | |
@@ -298,8 +301,10 b' class queue:' | |||||
298 | return (message, comments, user, date, diffstart > 1) |
|
301 | return (message, comments, user, date, diffstart > 1) | |
299 |
|
302 | |||
300 | def printdiff(self, repo, node1, node2=None, files=None, |
|
303 | def printdiff(self, repo, node1, node2=None, files=None, | |
301 |
fp=None, changes=None, opts= |
|
304 | fp=None, changes=None, opts={}): | |
302 | patch.diff(repo, node1, node2, files, |
|
305 | fns, matchfn, anypats = cmdutil.matchpats(repo, files, opts) | |
|
306 | ||||
|
307 | patch.diff(repo, node1, node2, fns, match=matchfn, | |||
303 | fp=fp, changes=changes, opts=self.diffopts()) |
|
308 | fp=fp, changes=changes, opts=self.diffopts()) | |
304 |
|
309 | |||
305 | def mergeone(self, repo, mergeq, head, patch, rev, wlock): |
|
310 | def mergeone(self, repo, mergeq, head, patch, rev, wlock): | |
@@ -408,7 +413,7 b' class queue:' | |||||
408 | self.ui.warn("patch failed, unable to continue (try -v)\n") |
|
413 | self.ui.warn("patch failed, unable to continue (try -v)\n") | |
409 | return (False, [], False) |
|
414 | return (False, [], False) | |
410 |
|
415 | |||
411 |
return (True, files |
|
416 | return (True, files, fuzz) | |
412 |
|
417 | |||
413 | def apply(self, repo, series, list=False, update_status=True, |
|
418 | def apply(self, repo, series, list=False, update_status=True, | |
414 | strict=False, patchdir=None, merge=None, wlock=None): |
|
419 | strict=False, patchdir=None, merge=None, wlock=None): | |
@@ -421,42 +426,37 b' class queue:' | |||||
421 | lock = repo.lock() |
|
426 | lock = repo.lock() | |
422 | tr = repo.transaction() |
|
427 | tr = repo.transaction() | |
423 | n = None |
|
428 | n = None | |
424 | for patch in series: |
|
429 | for patchname in series: | |
425 | pushable, reason = self.pushable(patch) |
|
430 | pushable, reason = self.pushable(patchname) | |
426 | if not pushable: |
|
431 | if not pushable: | |
427 | self.explain_pushable(patch, all_patches=True) |
|
432 | self.explain_pushable(patchname, all_patches=True) | |
428 | continue |
|
433 | continue | |
429 | self.ui.warn("applying %s\n" % patch) |
|
434 | self.ui.warn("applying %s\n" % patchname) | |
430 | pf = os.path.join(patchdir, patch) |
|
435 | pf = os.path.join(patchdir, patchname) | |
431 |
|
436 | |||
432 | try: |
|
437 | try: | |
433 | message, comments, user, date, patchfound = self.readheaders(patch) |
|
438 | message, comments, user, date, patchfound = self.readheaders(patchname) | |
434 | except: |
|
439 | except: | |
435 |
self.ui.warn("Unable to read %s\n" % p |
|
440 | self.ui.warn("Unable to read %s\n" % patchname) | |
436 | err = 1 |
|
441 | err = 1 | |
437 | break |
|
442 | break | |
438 |
|
443 | |||
439 | if not message: |
|
444 | if not message: | |
440 | message = "imported patch %s\n" % patch |
|
445 | message = "imported patch %s\n" % patchname | |
441 | else: |
|
446 | else: | |
442 | if list: |
|
447 | if list: | |
443 | message.append("\nimported patch %s" % patch) |
|
448 | message.append("\nimported patch %s" % patchname) | |
444 | message = '\n'.join(message) |
|
449 | message = '\n'.join(message) | |
445 |
|
450 | |||
446 | (patcherr, files, fuzz) = self.patch(repo, pf) |
|
451 | (patcherr, files, fuzz) = self.patch(repo, pf) | |
447 | patcherr = not patcherr |
|
452 | patcherr = not patcherr | |
448 |
|
453 | |||
449 |
if merge and |
|
454 | if merge and files: | |
450 | # Mark as merged and update dirstate parent info |
|
455 | # Mark as merged and update dirstate parent info | |
451 | repo.dirstate.update(repo.dirstate.filterfiles(files), 'm') |
|
456 | repo.dirstate.update(repo.dirstate.filterfiles(files.keys()), 'm') | |
452 | p1, p2 = repo.dirstate.parents() |
|
457 | p1, p2 = repo.dirstate.parents() | |
453 | repo.dirstate.setparents(p1, merge) |
|
458 | repo.dirstate.setparents(p1, merge) | |
454 | if len(files) > 0: |
|
459 | files = patch.updatedir(self.ui, repo, files, wlock=wlock) | |
455 | cwd = repo.getcwd() |
|
|||
456 | cfiles = files |
|
|||
457 | if cwd: |
|
|||
458 | cfiles = [util.pathto(cwd, f) for f in files] |
|
|||
459 | cmdutil.addremove(repo, cfiles, wlock=wlock) |
|
|||
460 | n = repo.commit(files, message, user, date, force=1, lock=lock, |
|
460 | n = repo.commit(files, message, user, date, force=1, lock=lock, | |
461 | wlock=wlock) |
|
461 | wlock=wlock) | |
462 |
|
462 | |||
@@ -464,11 +464,11 b' class queue:' | |||||
464 | raise util.Abort(_("repo commit failed")) |
|
464 | raise util.Abort(_("repo commit failed")) | |
465 |
|
465 | |||
466 | if update_status: |
|
466 | if update_status: | |
467 | self.applied.append(statusentry(revlog.hex(n), patch)) |
|
467 | self.applied.append(statusentry(revlog.hex(n), patchname)) | |
468 |
|
468 | |||
469 | if patcherr: |
|
469 | if patcherr: | |
470 | if not patchfound: |
|
470 | if not patchfound: | |
471 | self.ui.warn("patch %s is empty\n" % patch) |
|
471 | self.ui.warn("patch %s is empty\n" % patchname) | |
472 | err = 0 |
|
472 | err = 0 | |
473 | else: |
|
473 | else: | |
474 | self.ui.warn("patch failed, rejects left in working dir\n") |
|
474 | self.ui.warn("patch failed, rejects left in working dir\n") | |
@@ -904,15 +904,15 b' class queue:' | |||||
904 | else: |
|
904 | else: | |
905 | self.ui.write("Patch queue now empty\n") |
|
905 | self.ui.write("Patch queue now empty\n") | |
906 |
|
906 | |||
907 |
def diff(self, repo, |
|
907 | def diff(self, repo, pats, opts): | |
908 | top = self.check_toppatch(repo) |
|
908 | top = self.check_toppatch(repo) | |
909 | if not top: |
|
909 | if not top: | |
910 | self.ui.write("No patches applied\n") |
|
910 | self.ui.write("No patches applied\n") | |
911 | return |
|
911 | return | |
912 | qp = self.qparents(repo, top) |
|
912 | qp = self.qparents(repo, top) | |
913 |
self.printdiff(repo, qp, files= |
|
913 | self.printdiff(repo, qp, files=pats, opts=opts) | |
914 |
|
914 | |||
915 |
def refresh(self, repo, |
|
915 | def refresh(self, repo, pats=None, **opts): | |
916 | if len(self.applied) == 0: |
|
916 | if len(self.applied) == 0: | |
917 | self.ui.write("No patches applied\n") |
|
917 | self.ui.write("No patches applied\n") | |
918 | return |
|
918 | return | |
@@ -925,7 +925,7 b' class queue:' | |||||
925 | message, comments, user, date, patchfound = self.readheaders(patch) |
|
925 | message, comments, user, date, patchfound = self.readheaders(patch) | |
926 |
|
926 | |||
927 | patchf = self.opener(patch, "w") |
|
927 | patchf = self.opener(patch, "w") | |
928 | msg = msg.rstrip() |
|
928 | msg = opts.get('msg', '').rstrip() | |
929 | if msg: |
|
929 | if msg: | |
930 | if comments: |
|
930 | if comments: | |
931 | # Remove existing message. |
|
931 | # Remove existing message. | |
@@ -939,6 +939,7 b' class queue:' | |||||
939 | comments = "\n".join(comments) + '\n\n' |
|
939 | comments = "\n".join(comments) + '\n\n' | |
940 | patchf.write(comments) |
|
940 | patchf.write(comments) | |
941 |
|
941 | |||
|
942 | fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) | |||
942 | tip = repo.changelog.tip() |
|
943 | tip = repo.changelog.tip() | |
943 | if top == tip: |
|
944 | if top == tip: | |
944 | # if the top of our patch queue is also the tip, there is an |
|
945 | # if the top of our patch queue is also the tip, there is an | |
@@ -956,7 +957,7 b' class queue:' | |||||
956 | # caching against the next repo.status call |
|
957 | # caching against the next repo.status call | |
957 | # |
|
958 | # | |
958 | mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5] |
|
959 | mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5] | |
959 | if short: |
|
960 | if opts.get('short'): | |
960 | filelist = mm + aa + dd |
|
961 | filelist = mm + aa + dd | |
961 | else: |
|
962 | else: | |
962 | filelist = None |
|
963 | filelist = None | |
@@ -992,16 +993,27 b' class queue:' | |||||
992 | m = list(util.unique(mm)) |
|
993 | m = list(util.unique(mm)) | |
993 | r = list(util.unique(dd)) |
|
994 | r = list(util.unique(dd)) | |
994 | a = list(util.unique(aa)) |
|
995 | a = list(util.unique(aa)) | |
995 |
filelist = |
|
996 | filelist = filter(matchfn, util.unique(m + r + a)) | |
996 | self.printdiff(repo, patchparent, files=filelist, |
|
997 | self.printdiff(repo, patchparent, files=filelist, | |
997 | changes=(m, a, r, [], u), fp=patchf) |
|
998 | changes=(m, a, r, [], u), fp=patchf) | |
998 | patchf.close() |
|
999 | patchf.close() | |
999 |
|
1000 | |||
1000 | changes = repo.changelog.read(tip) |
|
1001 | changes = repo.changelog.read(tip) | |
1001 | repo.dirstate.setparents(*cparents) |
|
1002 | repo.dirstate.setparents(*cparents) | |
|
1003 | copies = [(f, repo.dirstate.copied(f)) for f in a] | |||
1002 | repo.dirstate.update(a, 'a') |
|
1004 | repo.dirstate.update(a, 'a') | |
|
1005 | for dst, src in copies: | |||
|
1006 | repo.dirstate.copy(src, dst) | |||
1003 | repo.dirstate.update(r, 'r') |
|
1007 | repo.dirstate.update(r, 'r') | |
|
1008 | # if the patch excludes a modified file, mark that file with mtime=0 | |||
|
1009 | # so status can see it. | |||
|
1010 | mm = [] | |||
|
1011 | for i in range(len(m)-1, -1, -1): | |||
|
1012 | if not matchfn(m[i]): | |||
|
1013 | mm.append(m[i]) | |||
|
1014 | del m[i] | |||
1004 | repo.dirstate.update(m, 'n') |
|
1015 | repo.dirstate.update(m, 'n') | |
|
1016 | repo.dirstate.update(mm, 'n', st_mtime=0) | |||
1005 | repo.dirstate.forget(forget) |
|
1017 | repo.dirstate.forget(forget) | |
1006 |
|
1018 | |||
1007 | if not msg: |
|
1019 | if not msg: | |
@@ -1216,7 +1228,7 b' class queue:' | |||||
1216 | if not self.ui.verbose: |
|
1228 | if not self.ui.verbose: | |
1217 | p = pname |
|
1229 | p = pname | |
1218 | else: |
|
1230 | else: | |
1219 | p = str(self.series.index(pname)) + " " + p |
|
1231 | p = str(self.series.index(pname)) + " " + pname | |
1220 | return p |
|
1232 | return p | |
1221 |
|
1233 | |||
1222 | def top(self, repo): |
|
1234 | def top(self, repo): | |
@@ -1411,17 +1423,24 b' def new(ui, repo, patch, **opts):' | |||||
1411 | changes unless -f is specified, in which case the patch will |
|
1423 | changes unless -f is specified, in which case the patch will | |
1412 | be initialised with them. |
|
1424 | be initialised with them. | |
1413 |
|
1425 | |||
1414 | -m or -l set the patch header as well as the commit message. |
|
1426 | -e, -m or -l set the patch header as well as the commit message. | |
1415 |
If ne |
|
1427 | If none is specified, the patch header is empty and the | |
1416 | commit message is 'New patch: PATCH'""" |
|
1428 | commit message is 'New patch: PATCH'""" | |
1417 | q = repo.mq |
|
1429 | q = repo.mq | |
1418 | message = commands.logmessage(opts) |
|
1430 | message = commands.logmessage(opts) | |
|
1431 | if opts['edit']: | |||
|
1432 | message = ui.edit(message, ui.username()) | |||
1419 | q.new(repo, patch, msg=message, force=opts['force']) |
|
1433 | q.new(repo, patch, msg=message, force=opts['force']) | |
1420 | q.save_dirty() |
|
1434 | q.save_dirty() | |
1421 | return 0 |
|
1435 | return 0 | |
1422 |
|
1436 | |||
1423 | def refresh(ui, repo, **opts): |
|
1437 | def refresh(ui, repo, *pats, **opts): | |
1424 |
"""update the current patch |
|
1438 | """update the current patch | |
|
1439 | ||||
|
1440 | If any file patterns are provided, the refreshed patch will contain only | |||
|
1441 | the modifications that match those patterns; the remaining modifications | |||
|
1442 | will remain in the working directory. | |||
|
1443 | """ | |||
1425 | q = repo.mq |
|
1444 | q = repo.mq | |
1426 | message = commands.logmessage(opts) |
|
1445 | message = commands.logmessage(opts) | |
1427 | if opts['edit']: |
|
1446 | if opts['edit']: | |
@@ -1430,14 +1449,13 b' def refresh(ui, repo, **opts):' | |||||
1430 | patch = q.applied[-1].name |
|
1449 | patch = q.applied[-1].name | |
1431 | (message, comment, user, date, hasdiff) = q.readheaders(patch) |
|
1450 | (message, comment, user, date, hasdiff) = q.readheaders(patch) | |
1432 | message = ui.edit('\n'.join(message), user or ui.username()) |
|
1451 | message = ui.edit('\n'.join(message), user or ui.username()) | |
1433 |
q.refresh(repo, msg=message, |
|
1452 | q.refresh(repo, pats, msg=message, **opts) | |
1434 | q.save_dirty() |
|
1453 | q.save_dirty() | |
1435 | return 0 |
|
1454 | return 0 | |
1436 |
|
1455 | |||
1437 |
def diff(ui, repo, * |
|
1456 | def diff(ui, repo, *pats, **opts): | |
1438 | """diff of the current patch""" |
|
1457 | """diff of the current patch""" | |
1439 | # deep in the dirstate code, the walkhelper method wants a list, not a tuple |
|
1458 | repo.mq.diff(repo, pats, opts) | |
1440 | repo.mq.diff(repo, list(files)) |
|
|||
1441 | return 0 |
|
1459 | return 0 | |
1442 |
|
1460 | |||
1443 | def fold(ui, repo, *files, **opts): |
|
1461 | def fold(ui, repo, *files, **opts): | |
@@ -1469,20 +1487,21 b' def fold(ui, repo, *files, **opts):' | |||||
1469 | patches = [] |
|
1487 | patches = [] | |
1470 | messages = [] |
|
1488 | messages = [] | |
1471 | for f in files: |
|
1489 | for f in files: | |
1472 |
p |
|
1490 | p = q.lookup(f) | |
1473 |
if p |
|
1491 | if p in patches or p == parent: | |
1474 |
ui.warn(_('Skipping already folded patch %s') % p |
|
1492 | ui.warn(_('Skipping already folded patch %s') % p) | |
1475 |
if q.isapplied(p |
|
1493 | if q.isapplied(p): | |
1476 |
raise util.Abort(_('qfold cannot fold already applied patch %s') % p |
|
1494 | raise util.Abort(_('qfold cannot fold already applied patch %s') % p) | |
1477 |
patches.append(p |
|
1495 | patches.append(p) | |
1478 |
|
1496 | |||
1479 |
for p |
|
1497 | for p in patches: | |
1480 | if not message: |
|
1498 | if not message: | |
1481 |
messages.append(q.readheaders(p |
|
1499 | messages.append(q.readheaders(p)[0]) | |
1482 |
pf = q.join(p |
|
1500 | pf = q.join(p) | |
1483 | (patchsuccess, files, fuzz) = q.patch(repo, pf) |
|
1501 | (patchsuccess, files, fuzz) = q.patch(repo, pf) | |
1484 | if not patchsuccess: |
|
1502 | if not patchsuccess: | |
1485 |
raise util.Abort(_('Error folding patch %s') % p |
|
1503 | raise util.Abort(_('Error folding patch %s') % p) | |
|
1504 | patch.updatedir(ui, repo, files) | |||
1486 |
|
1505 | |||
1487 | if not message: |
|
1506 | if not message: | |
1488 | message, comments, user = q.readheaders(parent)[0:3] |
|
1507 | message, comments, user = q.readheaders(parent)[0:3] | |
@@ -1495,29 +1514,26 b' def fold(ui, repo, *files, **opts):' | |||||
1495 | message = ui.edit(message, user or ui.username()) |
|
1514 | message = ui.edit(message, user or ui.username()) | |
1496 |
|
1515 | |||
1497 | q.refresh(repo, msg=message) |
|
1516 | q.refresh(repo, msg=message) | |
1498 |
|
1517 | q.delete(repo, patches, keep=opts['keep']) | ||
1499 | for patch in patches: |
|
|||
1500 | q.delete(repo, patch, keep=opts['keep']) |
|
|||
1501 |
|
||||
1502 | q.save_dirty() |
|
1518 | q.save_dirty() | |
1503 |
|
1519 | |||
1504 | def guard(ui, repo, *args, **opts): |
|
1520 | def guard(ui, repo, *args, **opts): | |
1505 | '''set or print guards for a patch |
|
1521 | '''set or print guards for a patch | |
1506 |
|
1522 | |||
1507 |
|
|
1523 | Guards control whether a patch can be pushed. A patch with no | |
1508 |
guards is aways pushed. |
|
1524 | guards is always pushed. A patch with a positive guard ("+foo") is | |
1509 |
pushed only if qselect command |
|
1525 | pushed only if the qselect command has activated it. A patch with | |
1510 |
|
|
1526 | a negative guard ("-foo") is never pushed if the qselect command | |
1511 | guard "foo". |
|
1527 | has activated it. | |
1512 |
|
1528 | |||
1513 |
|
|
1529 | With no arguments, print the currently active guards. | |
1514 |
|
|
1530 | With arguments, set guards for the named patch. | |
1515 |
|
1531 | |||
1516 |
|
|
1532 | To set a negative guard "-foo" on topmost patch ("--" is needed so | |
1517 |
hg will not interpret "-foo" as a |
|
1533 | hg will not interpret "-foo" as an option): | |
1518 | hg qguard -- -foo |
|
1534 | hg qguard -- -foo | |
1519 |
|
1535 | |||
1520 |
|
|
1536 | To set guards on another patch: | |
1521 | hg qguard other.patch +2.6.17 -stable |
|
1537 | hg qguard other.patch +2.6.17 -stable | |
1522 | ''' |
|
1538 | ''' | |
1523 | def status(idx): |
|
1539 | def status(idx): | |
@@ -1723,32 +1739,34 b' def strip(ui, repo, rev, **opts):' | |||||
1723 | def select(ui, repo, *args, **opts): |
|
1739 | def select(ui, repo, *args, **opts): | |
1724 | '''set or print guarded patches to push |
|
1740 | '''set or print guarded patches to push | |
1725 |
|
1741 | |||
1726 |
|
|
1742 | Use the qguard command to set or print guards on patch, then use | |
1727 |
qselect to tell mq which guards to use. |
|
1743 | qselect to tell mq which guards to use. A patch will be pushed if it | |
|
1744 | has no guards or any positive guards match the currently selected guard, | |||
|
1745 | but will not be pushed if any negative guards match the current guard. | |||
|
1746 | For example: | |||
1728 |
|
1747 | |||
1729 |
qguard foo.patch -stable (n |
|
1748 | qguard foo.patch -stable (negative guard) | |
1730 |
qguard bar.patch +stable (pos |
|
1749 | qguard bar.patch +stable (positive guard) | |
1731 | qselect stable |
|
1750 | qselect stable | |
1732 |
|
1751 | |||
1733 |
|
|
1752 | This activates the "stable" guard. mq will skip foo.patch (because | |
1734 |
|
|
1753 | it has a negative match) but push bar.patch (because it | |
1735 | match). patch is pushed if any posative guards match and no |
|
1754 | has a positive match). | |
1736 | nagative guards match. |
|
|||
1737 |
|
1755 | |||
1738 |
|
|
1756 | With no arguments, prints the currently active guards. | |
1739 |
|
|
1757 | With one argument, sets the active guard. | |
1740 |
|
1758 | |||
1741 |
|
|
1759 | Use -n/--none to deactivate guards (no other arguments needed). | |
1742 |
|
|
1760 | When no guards are active, patches with positive guards are skipped | |
1743 |
patches with n |
|
1761 | and patches with negative guards are pushed. | |
1744 |
|
1762 | |||
1745 |
qselect can change guards o |
|
1763 | qselect can change the guards on applied patches. It does not pop | |
1746 |
guarded patches by default. |
|
1764 | guarded patches by default. Use --pop to pop back to the last applied | |
1747 |
patch that is not guarded. |
|
1765 | patch that is not guarded. Use --reapply (which implies --pop) to push | |
1748 | back to current patch afterwards, but skip guarded patches. |
|
1766 | back to the current patch afterwards, but skip guarded patches. | |
1749 |
|
1767 | |||
1750 |
|
|
1768 | Use -s/--series to print a list of all guards in the series file (no | |
1751 |
other arguments needed). |
|
1769 | other arguments needed). Use -v for more information.''' | |
1752 |
|
1770 | |||
1753 | q = repo.mq |
|
1771 | q = repo.mq | |
1754 | guards = q.active() |
|
1772 | guards = q.active() | |
@@ -1885,7 +1903,10 b' cmdtable = {' | |||||
1885 | (commit, |
|
1903 | (commit, | |
1886 | commands.table["^commit|ci"][1], |
|
1904 | commands.table["^commit|ci"][1], | |
1887 | 'hg qcommit [OPTION]... [FILE]...'), |
|
1905 | 'hg qcommit [OPTION]... [FILE]...'), | |
1888 | "^qdiff": (diff, [], 'hg qdiff [FILE]...'), |
|
1906 | "^qdiff": (diff, | |
|
1907 | [('I', 'include', [], _('include names matching the given patterns')), | |||
|
1908 | ('X', 'exclude', [], _('exclude names matching the given patterns'))], | |||
|
1909 | 'hg qdiff [-I] [-X] [FILE]...'), | |||
1889 | "qdelete|qremove|qrm": |
|
1910 | "qdelete|qremove|qrm": | |
1890 | (delete, |
|
1911 | (delete, | |
1891 | [('k', 'keep', None, _('keep patch file'))], |
|
1912 | [('k', 'keep', None, _('keep patch file'))], | |
@@ -1914,10 +1935,11 b' cmdtable = {' | |||||
1914 | 'hg qinit [-c]'), |
|
1935 | 'hg qinit [-c]'), | |
1915 | "qnew": |
|
1936 | "qnew": | |
1916 | (new, |
|
1937 | (new, | |
1917 |
[(' |
|
1938 | [('e', 'edit', None, _('edit commit message')), | |
|
1939 | ('m', 'message', '', _('use <text> as commit message')), | |||
1918 | ('l', 'logfile', '', _('read the commit message from <file>')), |
|
1940 | ('l', 'logfile', '', _('read the commit message from <file>')), | |
1919 | ('f', 'force', None, _('import uncommitted changes into patch'))], |
|
1941 | ('f', 'force', None, _('import uncommitted changes into patch'))], | |
1920 | 'hg qnew [-m TEXT] [-l FILE] [-f] PATCH'), |
|
1942 | 'hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH'), | |
1921 | "qnext": (next, [], 'hg qnext'), |
|
1943 | "qnext": (next, [], 'hg qnext'), | |
1922 | "qprev": (prev, [], 'hg qprev'), |
|
1944 | "qprev": (prev, [], 'hg qprev'), | |
1923 | "^qpop": |
|
1945 | "^qpop": | |
@@ -1939,8 +1961,10 b' cmdtable = {' | |||||
1939 | [('e', 'edit', None, _('edit commit message')), |
|
1961 | [('e', 'edit', None, _('edit commit message')), | |
1940 | ('m', 'message', '', _('change commit message with <text>')), |
|
1962 | ('m', 'message', '', _('change commit message with <text>')), | |
1941 | ('l', 'logfile', '', _('change commit message with <file> content')), |
|
1963 | ('l', 'logfile', '', _('change commit message with <file> content')), | |
1942 |
('s', 'short', None, 'short refresh') |
|
1964 | ('s', 'short', None, 'short refresh'), | |
1943 | 'hg qrefresh [-e] [-m TEXT] [-l FILE] [-s]'), |
|
1965 | ('I', 'include', [], _('include names matching the given patterns')), | |
|
1966 | ('X', 'exclude', [], _('exclude names matching the given patterns'))], | |||
|
1967 | 'hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] FILES...'), | |||
1944 | 'qrename|qmv': |
|
1968 | 'qrename|qmv': | |
1945 | (rename, [], 'hg qrename PATCH1 [PATCH2]'), |
|
1969 | (rename, [], 'hg qrename PATCH1 [PATCH2]'), | |
1946 | "qrestore": |
|
1970 | "qrestore": |
@@ -1526,7 +1526,6 b' def grep(ui, repo, pattern, *pats, **opt' | |||||
1526 | if st == 'window': |
|
1526 | if st == 'window': | |
1527 | incrementing = rev |
|
1527 | incrementing = rev | |
1528 | matches.clear() |
|
1528 | matches.clear() | |
1529 | copies.clear() |
|
|||
1530 | elif st == 'add': |
|
1529 | elif st == 'add': | |
1531 | change = repo.changelog.read(repo.lookup(str(rev))) |
|
1530 | change = repo.changelog.read(repo.lookup(str(rev))) | |
1532 | mf = repo.manifest.read(change[0]) |
|
1531 | mf = repo.manifest.read(change[0]) | |
@@ -1535,20 +1534,19 b' def grep(ui, repo, pattern, *pats, **opt' | |||||
1535 | if fn in skip: |
|
1534 | if fn in skip: | |
1536 | continue |
|
1535 | continue | |
1537 | fstate.setdefault(fn, {}) |
|
1536 | fstate.setdefault(fn, {}) | |
1538 | copies.setdefault(rev, {}) |
|
|||
1539 | try: |
|
1537 | try: | |
1540 | grepbody(fn, rev, getfile(fn).read(mf[fn])) |
|
1538 | grepbody(fn, rev, getfile(fn).read(mf[fn])) | |
1541 | if follow: |
|
1539 | if follow: | |
1542 | copied = getfile(fn).renamed(mf[fn]) |
|
1540 | copied = getfile(fn).renamed(mf[fn]) | |
1543 | if copied: |
|
1541 | if copied: | |
1544 |
copies |
|
1542 | copies.setdefault(rev, {})[fn] = copied[0] | |
1545 | except KeyError: |
|
1543 | except KeyError: | |
1546 | pass |
|
1544 | pass | |
1547 | elif st == 'iter': |
|
1545 | elif st == 'iter': | |
1548 | states = matches[rev].items() |
|
1546 | states = matches[rev].items() | |
1549 | states.sort() |
|
1547 | states.sort() | |
1550 | for fn, m in states: |
|
1548 | for fn, m in states: | |
1551 |
copy = copies |
|
1549 | copy = copies.get(rev, {}).get(fn) | |
1552 | if fn in skip: |
|
1550 | if fn in skip: | |
1553 | if copy: |
|
1551 | if copy: | |
1554 | skip[copy] = True |
|
1552 | skip[copy] = True | |
@@ -1571,7 +1569,7 b' def grep(ui, repo, pattern, *pats, **opt' | |||||
1571 | for fn, state in fstate: |
|
1569 | for fn, state in fstate: | |
1572 | if fn in skip: |
|
1570 | if fn in skip: | |
1573 | continue |
|
1571 | continue | |
1574 |
if fn not in copies |
|
1572 | if fn not in copies.get(prev[fn], {}): | |
1575 | display(fn, rev, {}, state) |
|
1573 | display(fn, rev, {}, state) | |
1576 | return (count == 0 and 1) or 0 |
|
1574 | return (count == 0 and 1) or 0 | |
1577 |
|
1575 | |||
@@ -1683,44 +1681,7 b' def import_(ui, repo, patch1, *patches, ' | |||||
1683 | ui.debug(_('message:\n%s\n') % message) |
|
1681 | ui.debug(_('message:\n%s\n') % message) | |
1684 |
|
1682 | |||
1685 | files, fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root) |
|
1683 | files, fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root) | |
1686 | removes = [] |
|
1684 | files = patch.updatedir(ui, repo, files, wlock=wlock) | |
1687 | if len(files) > 0: |
|
|||
1688 | cfiles = files.keys() |
|
|||
1689 | copies = [] |
|
|||
1690 | copts = {'after': False, 'force': False} |
|
|||
1691 | cwd = repo.getcwd() |
|
|||
1692 | if cwd: |
|
|||
1693 | cfiles = [util.pathto(cwd, f) for f in files.keys()] |
|
|||
1694 | for f in files: |
|
|||
1695 | ctype, gp = files[f] |
|
|||
1696 | if ctype == 'RENAME': |
|
|||
1697 | copies.append((gp.oldpath, gp.path, gp.copymod)) |
|
|||
1698 | removes.append(gp.oldpath) |
|
|||
1699 | elif ctype == 'COPY': |
|
|||
1700 | copies.append((gp.oldpath, gp.path, gp.copymod)) |
|
|||
1701 | elif ctype == 'DELETE': |
|
|||
1702 | removes.append(gp.path) |
|
|||
1703 | for src, dst, after in copies: |
|
|||
1704 | absdst = os.path.join(repo.root, dst) |
|
|||
1705 | if not after and os.path.exists(absdst): |
|
|||
1706 | raise util.Abort(_('patch creates existing file %s') % dst) |
|
|||
1707 | if cwd: |
|
|||
1708 | src, dst = [util.pathto(cwd, f) for f in (src, dst)] |
|
|||
1709 | copts['after'] = after |
|
|||
1710 | errs, copied = docopy(ui, repo, (src, dst), copts, wlock=wlock) |
|
|||
1711 | if errs: |
|
|||
1712 | raise util.Abort(errs) |
|
|||
1713 | if removes: |
|
|||
1714 | repo.remove(removes, True, wlock=wlock) |
|
|||
1715 | for f in files: |
|
|||
1716 | ctype, gp = files[f] |
|
|||
1717 | if gp and gp.mode: |
|
|||
1718 | x = gp.mode & 0100 != 0 |
|
|||
1719 | dst = os.path.join(repo.root, gp.path) |
|
|||
1720 | util.set_exec(dst, x) |
|
|||
1721 | cmdutil.addremove(repo, cfiles, wlock=wlock) |
|
|||
1722 | files = files.keys() |
|
|||
1723 | files.extend([r for r in removes if r not in files]) |
|
|||
1724 | repo.commit(files, message, user, date, wlock=wlock, lock=lock) |
|
1685 | repo.commit(files, message, user, date, wlock=wlock, lock=lock) | |
1725 | finally: |
|
1686 | finally: | |
1726 | os.unlink(tmpname) |
|
1687 | os.unlink(tmpname) | |
@@ -3281,18 +3242,11 b' def findext(name):' | |||||
3281 | return sys.modules[v] |
|
3242 | return sys.modules[v] | |
3282 | raise KeyError(name) |
|
3243 | raise KeyError(name) | |
3283 |
|
3244 | |||
3284 | def dispatch(args): |
|
3245 | def load_extensions(ui): | |
3285 | for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM': |
|
3246 | added = [] | |
3286 | num = getattr(signal, name, None) |
|
3247 | for ext_name, load_from_name in ui.extensions(): | |
3287 | if num: signal.signal(num, catchterm) |
|
3248 | if ext_name in external: | |
3288 |
|
3249 | continue | ||
3289 | try: |
|
|||
3290 | u = ui.ui(traceback='--traceback' in sys.argv[1:]) |
|
|||
3291 | except util.Abort, inst: |
|
|||
3292 | sys.stderr.write(_("abort: %s\n") % inst) |
|
|||
3293 | return -1 |
|
|||
3294 |
|
||||
3295 | for ext_name, load_from_name in u.extensions(): |
|
|||
3296 | try: |
|
3250 | try: | |
3297 | if load_from_name: |
|
3251 | if load_from_name: | |
3298 | # the module will be loaded in sys.modules |
|
3252 | # the module will be loaded in sys.modules | |
@@ -3312,24 +3266,37 b' def dispatch(args):' | |||||
3312 | except ImportError: |
|
3266 | except ImportError: | |
3313 | mod = importh(ext_name) |
|
3267 | mod = importh(ext_name) | |
3314 | external[ext_name] = mod.__name__ |
|
3268 | external[ext_name] = mod.__name__ | |
|
3269 | added.append((mod, ext_name)) | |||
3315 | except (util.SignalInterrupt, KeyboardInterrupt): |
|
3270 | except (util.SignalInterrupt, KeyboardInterrupt): | |
3316 | raise |
|
3271 | raise | |
3317 | except Exception, inst: |
|
3272 | except Exception, inst: | |
3318 |
u.warn(_("*** failed to import extension %s: %s\n") % |
|
3273 | ui.warn(_("*** failed to import extension %s: %s\n") % | |
3319 | if u.print_exc(): |
|
3274 | (ext_name, inst)) | |
|
3275 | if ui.print_exc(): | |||
3320 | return 1 |
|
3276 | return 1 | |
3321 |
|
3277 | |||
3322 | for name in external.itervalues(): |
|
3278 | for mod, name in added: | |
3323 | mod = sys.modules[name] |
|
|||
3324 | uisetup = getattr(mod, 'uisetup', None) |
|
3279 | uisetup = getattr(mod, 'uisetup', None) | |
3325 | if uisetup: |
|
3280 | if uisetup: | |
3326 | uisetup(u) |
|
3281 | uisetup(ui) | |
3327 | cmdtable = getattr(mod, 'cmdtable', {}) |
|
3282 | cmdtable = getattr(mod, 'cmdtable', {}) | |
3328 | for t in cmdtable: |
|
3283 | for t in cmdtable: | |
3329 | if t in table: |
|
3284 | if t in table: | |
3330 | u.warn(_("module %s overrides %s\n") % (name, t)) |
|
3285 | ui.warn(_("module %s overrides %s\n") % (name, t)) | |
3331 | table.update(cmdtable) |
|
3286 | table.update(cmdtable) | |
3332 |
|
3287 | |||
|
3288 | def dispatch(args): | |||
|
3289 | for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM': | |||
|
3290 | num = getattr(signal, name, None) | |||
|
3291 | if num: signal.signal(num, catchterm) | |||
|
3292 | ||||
|
3293 | try: | |||
|
3294 | u = ui.ui(traceback='--traceback' in sys.argv[1:], | |||
|
3295 | readhooks=[load_extensions]) | |||
|
3296 | except util.Abort, inst: | |||
|
3297 | sys.stderr.write(_("abort: %s\n") % inst) | |||
|
3298 | return -1 | |||
|
3299 | ||||
3333 | try: |
|
3300 | try: | |
3334 | cmd, func, args, options, cmdoptions = parse(u, args) |
|
3301 | cmd, func, args, options, cmdoptions = parse(u, args) | |
3335 | if options["time"]: |
|
3302 | if options["time"]: |
@@ -96,31 +96,59 b' class filelog(revlog):' | |||||
96 | return child |
|
96 | return child | |
97 |
|
97 | |||
98 | # find all ancestors |
|
98 | # find all ancestors | |
99 | needed = {node:1} |
|
99 | needed = {(self, node):1} | |
100 |
|
|
100 | files = [self] | |
|
101 | visit = [(self, node)] | |||
101 | while visit: |
|
102 | while visit: | |
102 | n = visit.pop(0) |
|
103 | f, n = visit.pop(0) | |
103 |
|
|
104 | rn = f.renamed(n) | |
104 |
|
|
105 | if rn: | |
105 |
|
|
106 | f, n = rn | |
106 | visit.append(p) |
|
107 | f = filelog(self.opener, f, self.defversion) | |
|
108 | files.insert(0, f) | |||
|
109 | if (f, n) not in needed: | |||
|
110 | needed[(f, n)] = 1 | |||
|
111 | else: | |||
|
112 | needed[(f, n)] += 1 | |||
|
113 | for p in f.parents(n): | |||
|
114 | if p == nullid: | |||
|
115 | continue | |||
|
116 | if (f, p) not in needed: | |||
|
117 | needed[(f, p)] = 1 | |||
|
118 | visit.append((f, p)) | |||
107 | else: |
|
119 | else: | |
108 | # count how many times we'll use this |
|
120 | # count how many times we'll use this | |
109 | needed[p] += 1 |
|
121 | needed[(f, p)] += 1 | |
110 |
|
122 | |||
111 | # sort by revision which is a topological order |
|
123 | # sort by revision (per file) which is a topological order | |
112 | visit = [ (self.rev(n), n) for n in needed.keys() ] |
|
124 | visit = [] | |
113 | visit.sort() |
|
125 | for f in files: | |
|
126 | fn = [(f.rev(n[1]), f, n[1]) for n in needed.keys() if n[0] == f] | |||
|
127 | fn.sort() | |||
|
128 | visit.extend(fn) | |||
114 | hist = {} |
|
129 | hist = {} | |
115 |
|
130 | |||
116 |
for |
|
131 | for i in range(len(visit)): | |
117 | curr = decorate(self.read(n), self.linkrev(n)) |
|
132 | r, f, n = visit[i] | |
118 | for p in self.parents(n): |
|
133 | curr = decorate(f.read(n), f.linkrev(n)) | |
|
134 | if r == -1: | |||
|
135 | continue | |||
|
136 | parents = f.parents(n) | |||
|
137 | # follow parents across renames | |||
|
138 | if r < 1 and i > 0: | |||
|
139 | j = i | |||
|
140 | while j > 0 and visit[j][1] == f: | |||
|
141 | j -= 1 | |||
|
142 | parents = (visit[j][2],) | |||
|
143 | f = visit[j][1] | |||
|
144 | else: | |||
|
145 | parents = f.parents(n) | |||
|
146 | for p in parents: | |||
119 | if p != nullid: |
|
147 | if p != nullid: | |
120 | curr = pair(hist[p], curr) |
|
148 | curr = pair(hist[p], curr) | |
121 | # trim the history of unneeded revs |
|
149 | # trim the history of unneeded revs | |
122 | needed[p] -= 1 |
|
150 | needed[(f, p)] -= 1 | |
123 | if not needed[p]: |
|
151 | if not needed[(f, p)]: | |
124 | del hist[p] |
|
152 | del hist[p] | |
125 | hist[n] = curr |
|
153 | hist[n] = curr | |
126 |
|
154 |
@@ -11,6 +11,28 b' from node import *' | |||||
11 | demandload(globals(), "cmdutil mdiff util") |
|
11 | demandload(globals(), "cmdutil mdiff util") | |
12 | demandload(globals(), "cStringIO email.Parser errno os re shutil sys tempfile") |
|
12 | demandload(globals(), "cStringIO email.Parser errno os re shutil sys tempfile") | |
13 |
|
13 | |||
|
14 | # helper functions | |||
|
15 | ||||
|
16 | def copyfile(src, dst, basedir=None): | |||
|
17 | if not basedir: | |||
|
18 | basedir = os.getcwd() | |||
|
19 | ||||
|
20 | abssrc, absdst = [os.path.join(basedir, n) for n in (src, dst)] | |||
|
21 | if os.path.exists(absdst): | |||
|
22 | raise util.Abort(_("cannot create %s: destination already exists") % | |||
|
23 | dst) | |||
|
24 | ||||
|
25 | targetdir = os.path.dirname(absdst) | |||
|
26 | if not os.path.isdir(targetdir): | |||
|
27 | os.makedirs(targetdir) | |||
|
28 | try: | |||
|
29 | shutil.copyfile(abssrc, absdst) | |||
|
30 | shutil.copymode(abssrc, absdst) | |||
|
31 | except shutil.Error, inst: | |||
|
32 | raise util.Abort(str(inst)) | |||
|
33 | ||||
|
34 | # public functions | |||
|
35 | ||||
14 | def extract(ui, fileobj): |
|
36 | def extract(ui, fileobj): | |
15 | '''extract patch from data read from fileobj. |
|
37 | '''extract patch from data read from fileobj. | |
16 |
|
38 | |||
@@ -174,21 +196,7 b' def dogitpatch(patchname, gitpatches):' | |||||
174 | if not p.copymod: |
|
196 | if not p.copymod: | |
175 | continue |
|
197 | continue | |
176 |
|
198 | |||
177 |
|
|
199 | copyfile(p.oldpath, p.path) | |
178 | raise util.Abort(_("cannot create %s: destination already exists") % |
|
|||
179 | p.path) |
|
|||
180 |
|
||||
181 | (src, dst) = [os.path.join(os.getcwd(), n) |
|
|||
182 | for n in (p.oldpath, p.path)] |
|
|||
183 |
|
||||
184 | targetdir = os.path.dirname(dst) |
|
|||
185 | if not os.path.isdir(targetdir): |
|
|||
186 | os.makedirs(targetdir) |
|
|||
187 | try: |
|
|||
188 | shutil.copyfile(src, dst) |
|
|||
189 | shutil.copymode(src, dst) |
|
|||
190 | except shutil.Error, inst: |
|
|||
191 | raise util.Abort(str(inst)) |
|
|||
192 |
|
200 | |||
193 | # rewrite patch hunk |
|
201 | # rewrite patch hunk | |
194 | while pfline < p.lineno: |
|
202 | while pfline < p.lineno: | |
@@ -281,6 +289,45 b' def diffopts(ui, opts={}):' | |||||
281 | ignoreblanklines=(opts.get('ignore_blank_lines') or |
|
289 | ignoreblanklines=(opts.get('ignore_blank_lines') or | |
282 | ui.configbool('diff', 'ignoreblanklines', None))) |
|
290 | ui.configbool('diff', 'ignoreblanklines', None))) | |
283 |
|
291 | |||
|
292 | def updatedir(ui, repo, patches, wlock=None): | |||
|
293 | '''Update dirstate after patch application according to metadata''' | |||
|
294 | if not patches: | |||
|
295 | return | |||
|
296 | copies = [] | |||
|
297 | removes = [] | |||
|
298 | cfiles = patches.keys() | |||
|
299 | copts = {'after': False, 'force': False} | |||
|
300 | cwd = repo.getcwd() | |||
|
301 | if cwd: | |||
|
302 | cfiles = [util.pathto(cwd, f) for f in patches.keys()] | |||
|
303 | for f in patches: | |||
|
304 | ctype, gp = patches[f] | |||
|
305 | if ctype == 'RENAME': | |||
|
306 | copies.append((gp.oldpath, gp.path, gp.copymod)) | |||
|
307 | removes.append(gp.oldpath) | |||
|
308 | elif ctype == 'COPY': | |||
|
309 | copies.append((gp.oldpath, gp.path, gp.copymod)) | |||
|
310 | elif ctype == 'DELETE': | |||
|
311 | removes.append(gp.path) | |||
|
312 | for src, dst, after in copies: | |||
|
313 | if not after: | |||
|
314 | copyfile(src, dst, repo.root) | |||
|
315 | repo.copy(src, dst, wlock=wlock) | |||
|
316 | if removes: | |||
|
317 | repo.remove(removes, True, wlock=wlock) | |||
|
318 | for f in patches: | |||
|
319 | ctype, gp = patches[f] | |||
|
320 | if gp and gp.mode: | |||
|
321 | x = gp.mode & 0100 != 0 | |||
|
322 | dst = os.path.join(repo.root, gp.path) | |||
|
323 | util.set_exec(dst, x) | |||
|
324 | cmdutil.addremove(repo, cfiles, wlock=wlock) | |||
|
325 | files = patches.keys() | |||
|
326 | files.extend([r for r in removes if r not in files]) | |||
|
327 | files.sort() | |||
|
328 | ||||
|
329 | return files | |||
|
330 | ||||
284 | def diff(repo, node1=None, node2=None, files=None, match=util.always, |
|
331 | def diff(repo, node1=None, node2=None, files=None, match=util.always, | |
285 | fp=None, changes=None, opts=None): |
|
332 | fp=None, changes=None, opts=None): | |
286 | '''print diff of changes to files between two nodes, or node and |
|
333 | '''print diff of changes to files between two nodes, or node and | |
@@ -296,10 +343,27 b' def diff(repo, node1=None, node2=None, f' | |||||
296 |
|
343 | |||
297 | if not node1: |
|
344 | if not node1: | |
298 | node1 = repo.dirstate.parents()[0] |
|
345 | node1 = repo.dirstate.parents()[0] | |
|
346 | ||||
|
347 | clcache = {} | |||
|
348 | def getchangelog(n): | |||
|
349 | if n not in clcache: | |||
|
350 | clcache[n] = repo.changelog.read(n) | |||
|
351 | return clcache[n] | |||
|
352 | mcache = {} | |||
|
353 | def getmanifest(n): | |||
|
354 | if n not in mcache: | |||
|
355 | mcache[n] = repo.manifest.read(n) | |||
|
356 | return mcache[n] | |||
|
357 | fcache = {} | |||
|
358 | def getfile(f): | |||
|
359 | if f not in fcache: | |||
|
360 | fcache[f] = repo.file(f) | |||
|
361 | return fcache[f] | |||
|
362 | ||||
299 | # reading the data for node1 early allows it to play nicely |
|
363 | # reading the data for node1 early allows it to play nicely | |
300 | # with repo.status and the revlog cache. |
|
364 | # with repo.status and the revlog cache. | |
301 |
change = |
|
365 | change = getchangelog(node1) | |
302 |
mmap = |
|
366 | mmap = getmanifest(change[0]) | |
303 | date1 = util.datestr(change[2]) |
|
367 | date1 = util.datestr(change[2]) | |
304 |
|
368 | |||
305 | if not changes: |
|
369 | if not changes: | |
@@ -320,17 +384,32 b' def diff(repo, node1=None, node2=None, f' | |||||
320 | if not modified and not added and not removed: |
|
384 | if not modified and not added and not removed: | |
321 | return |
|
385 | return | |
322 |
|
386 | |||
|
387 | def renamedbetween(f, n1, n2): | |||
|
388 | r1, r2 = map(repo.changelog.rev, (n1, n2)) | |||
|
389 | src = None | |||
|
390 | while r2 > r1: | |||
|
391 | cl = getchangelog(n2)[0] | |||
|
392 | m = getmanifest(cl) | |||
|
393 | try: | |||
|
394 | src = getfile(f).renamed(m[f]) | |||
|
395 | except KeyError: | |||
|
396 | return None | |||
|
397 | if src: | |||
|
398 | f = src[0] | |||
|
399 | n2 = repo.changelog.parents(n2)[0] | |||
|
400 | r2 = repo.changelog.rev(n2) | |||
|
401 | return src | |||
|
402 | ||||
323 | if node2: |
|
403 | if node2: | |
324 |
change = |
|
404 | change = getchangelog(node2) | |
325 |
mmap2 = |
|
405 | mmap2 = getmanifest(change[0]) | |
326 | _date2 = util.datestr(change[2]) |
|
406 | _date2 = util.datestr(change[2]) | |
327 | def date2(f): |
|
407 | def date2(f): | |
328 | return _date2 |
|
408 | return _date2 | |
329 | def read(f): |
|
409 | def read(f): | |
330 |
return |
|
410 | return getfile(f).read(mmap2[f]) | |
331 | def renamed(f): |
|
411 | def renamed(f): | |
332 | src = repo.file(f).renamed(mmap2[f]) |
|
412 | return renamedbetween(f, node1, node2) | |
333 | return src and src[0] or None |
|
|||
334 | else: |
|
413 | else: | |
335 | tz = util.makedate()[1] |
|
414 | tz = util.makedate()[1] | |
336 | _date2 = util.datestr() |
|
415 | _date2 = util.datestr() | |
@@ -343,7 +422,18 b' def diff(repo, node1=None, node2=None, f' | |||||
343 | def read(f): |
|
422 | def read(f): | |
344 | return repo.wread(f) |
|
423 | return repo.wread(f) | |
345 | def renamed(f): |
|
424 | def renamed(f): | |
346 |
|
|
425 | src = repo.dirstate.copies.get(f) | |
|
426 | parent = repo.dirstate.parents()[0] | |||
|
427 | if src: | |||
|
428 | f = src[0] | |||
|
429 | of = renamedbetween(f, node1, parent) | |||
|
430 | if of: | |||
|
431 | return of | |||
|
432 | elif src: | |||
|
433 | cl = getchangelog(parent)[0] | |||
|
434 | return (src, getmanifest(cl)[src]) | |||
|
435 | else: | |||
|
436 | return None | |||
347 |
|
437 | |||
348 | if repo.ui.quiet: |
|
438 | if repo.ui.quiet: | |
349 | r = None |
|
439 | r = None | |
@@ -357,7 +447,7 b' def diff(repo, node1=None, node2=None, f' | |||||
357 | src = renamed(f) |
|
447 | src = renamed(f) | |
358 | if src: |
|
448 | if src: | |
359 | copied[f] = src |
|
449 | copied[f] = src | |
360 | srcs = [x[1] for x in copied.items()] |
|
450 | srcs = [x[1][0] for x in copied.items()] | |
361 |
|
451 | |||
362 | all = modified + added + removed |
|
452 | all = modified + added + removed | |
363 | all.sort() |
|
453 | all.sort() | |
@@ -366,7 +456,7 b' def diff(repo, node1=None, node2=None, f' | |||||
366 | tn = None |
|
456 | tn = None | |
367 | dodiff = True |
|
457 | dodiff = True | |
368 | if f in mmap: |
|
458 | if f in mmap: | |
369 |
to = |
|
459 | to = getfile(f).read(mmap[f]) | |
370 | if f not in removed: |
|
460 | if f not in removed: | |
371 | tn = read(f) |
|
461 | tn = read(f) | |
372 | if opts.git: |
|
462 | if opts.git: | |
@@ -385,13 +475,13 b' def diff(repo, node1=None, node2=None, f' | |||||
385 | else: |
|
475 | else: | |
386 | mode = gitmode(util.is_exec(repo.wjoin(f), None)) |
|
476 | mode = gitmode(util.is_exec(repo.wjoin(f), None)) | |
387 | if f in copied: |
|
477 | if f in copied: | |
388 | a = copied[f] |
|
478 | a, arev = copied[f] | |
389 | omode = gitmode(mmap.execf(a)) |
|
479 | omode = gitmode(mmap.execf(a)) | |
390 | addmodehdr(header, omode, mode) |
|
480 | addmodehdr(header, omode, mode) | |
391 | op = a in removed and 'rename' or 'copy' |
|
481 | op = a in removed and 'rename' or 'copy' | |
392 | header.append('%s from %s\n' % (op, a)) |
|
482 | header.append('%s from %s\n' % (op, a)) | |
393 | header.append('%s to %s\n' % (op, f)) |
|
483 | header.append('%s to %s\n' % (op, f)) | |
394 |
to = |
|
484 | to = getfile(a).read(arev) | |
395 | else: |
|
485 | else: | |
396 | header.append('new file mode %s\n' % mode) |
|
486 | header.append('new file mode %s\n' % mode) | |
397 | elif f in removed: |
|
487 | elif f in removed: |
@@ -12,11 +12,13 b' demandload(globals(), "ConfigParser mdif' | |||||
12 |
|
12 | |||
13 | class ui(object): |
|
13 | class ui(object): | |
14 | def __init__(self, verbose=False, debug=False, quiet=False, |
|
14 | def __init__(self, verbose=False, debug=False, quiet=False, | |
15 |
interactive=True, traceback=False, parentui=None |
|
15 | interactive=True, traceback=False, parentui=None, | |
|
16 | readhooks=[]): | |||
16 | self.overlay = {} |
|
17 | self.overlay = {} | |
17 | if parentui is None: |
|
18 | if parentui is None: | |
18 | # this is the parent of all ui children |
|
19 | # this is the parent of all ui children | |
19 | self.parentui = None |
|
20 | self.parentui = None | |
|
21 | self.readhooks = list(readhooks) | |||
20 | self.cdata = ConfigParser.SafeConfigParser() |
|
22 | self.cdata = ConfigParser.SafeConfigParser() | |
21 | self.readconfig(util.rcpath()) |
|
23 | self.readconfig(util.rcpath()) | |
22 |
|
24 | |||
@@ -34,6 +36,7 b' class ui(object):' | |||||
34 | else: |
|
36 | else: | |
35 | # parentui may point to an ui object which is already a child |
|
37 | # parentui may point to an ui object which is already a child | |
36 | self.parentui = parentui.parentui or parentui |
|
38 | self.parentui = parentui.parentui or parentui | |
|
39 | self.readhooks = list(parentui.readhooks or readhooks) | |||
37 | parent_cdata = self.parentui.cdata |
|
40 | parent_cdata = self.parentui.cdata | |
38 | self.cdata = ConfigParser.SafeConfigParser(parent_cdata.defaults()) |
|
41 | self.cdata = ConfigParser.SafeConfigParser(parent_cdata.defaults()) | |
39 | # make interpolation work |
|
42 | # make interpolation work | |
@@ -78,6 +81,8 b' class ui(object):' | |||||
78 | for name, path in self.configitems("paths"): |
|
81 | for name, path in self.configitems("paths"): | |
79 | if path and "://" not in path and not os.path.isabs(path): |
|
82 | if path and "://" not in path and not os.path.isabs(path): | |
80 | self.cdata.set("paths", name, os.path.join(root, path)) |
|
83 | self.cdata.set("paths", name, os.path.join(root, path)) | |
|
84 | for hook in self.readhooks: | |||
|
85 | hook(self) | |||
81 |
|
86 | |||
82 | def setconfig(self, section, name, val): |
|
87 | def setconfig(self, section, name, val): | |
83 | self.overlay[(section, name)] = val |
|
88 | self.overlay[(section, name)] = val |
@@ -28,6 +28,6 b' writing tests:' | |||||
28 |
|
28 | |||
29 | - diff will show the current time |
|
29 | - diff will show the current time | |
30 |
|
30 | |||
31 |
use hg diff | sed "s/\( |
|
31 | use hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |
32 | dates |
|
32 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" | |
33 |
|
33 | to strip dates |
@@ -17,7 +17,7 b' while test $count -lt 32 ; do' | |||||
17 | test $count -eq 0 && hg add |
|
17 | test $count -eq 0 && hg add | |
18 | hg ci -m "msg $count" -d "$count 0" |
|
18 | hg ci -m "msg $count" -d "$count 0" | |
19 | echo % committed changeset $count |
|
19 | echo % committed changeset $count | |
20 |
count= |
|
20 | count=`expr $count + 1` | |
21 | done |
|
21 | done | |
22 |
|
22 | |||
23 | echo % log |
|
23 | echo % log |
@@ -8,7 +8,11 b' hg init a' | |||||
8 | cd a |
|
8 | cd a | |
9 | echo a > a |
|
9 | echo a > a | |
10 | hg add |
|
10 | hg add | |
11 | hg extdiff -o -Nr |
|
11 | diff -N /dev/null /dev/null 2> /dev/null | |
|
12 | if [ $? -ne 0 ]; then | |||
|
13 | opt="-p gdiff" | |||
|
14 | fi | |||
|
15 | hg extdiff -o -Nr $opt | |||
12 |
|
16 | |||
13 | echo "[extdiff]" >> $HGTMP/.hgrc |
|
17 | echo "[extdiff]" >> $HGTMP/.hgrc | |
14 | echo "cmd.falabala=echo" >> $HGTMP/.hgrc |
|
18 | echo "cmd.falabala=echo" >> $HGTMP/.hgrc |
@@ -8,22 +8,26 b" hg ci -Amstart -d '0 0'" | |||||
8 | echo new > new |
|
8 | echo new > new | |
9 | hg ci -Amnew -d '0 0' |
|
9 | hg ci -Amnew -d '0 0' | |
10 | echo '% new file' |
|
10 | echo '% new file' | |
11 |
hg diff --git -r 0 | sed "s/\( |
|
11 | hg diff --git -r 0 | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |
|
12 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" | |||
12 |
|
13 | |||
13 | hg cp new copy |
|
14 | hg cp new copy | |
14 | hg ci -mcopy -d '0 0' |
|
15 | hg ci -mcopy -d '0 0' | |
15 | echo '% copy' |
|
16 | echo '% copy' | |
16 |
hg diff --git -r 1:tip | sed "s/\( |
|
17 | hg diff --git -r 1:tip | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |
|
18 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" | |||
17 |
|
19 | |||
18 | hg mv copy rename |
|
20 | hg mv copy rename | |
19 | hg ci -mrename -d '0 0' |
|
21 | hg ci -mrename -d '0 0' | |
20 | echo '% rename' |
|
22 | echo '% rename' | |
21 |
hg diff --git -r 2:tip | sed "s/\( |
|
23 | hg diff --git -r 2:tip | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |
|
24 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" | |||
22 |
|
25 | |||
23 | hg rm rename |
|
26 | hg rm rename | |
24 | hg ci -mdelete -d '0 0' |
|
27 | hg ci -mdelete -d '0 0' | |
25 | echo '% delete' |
|
28 | echo '% delete' | |
26 |
hg diff --git -r 3:tip | sed "s/\( |
|
29 | hg diff --git -r 3:tip | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |
|
30 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" | |||
27 |
|
31 | |||
28 | cat > src <<EOF |
|
32 | cat > src <<EOF | |
29 | 1 |
|
33 | 1 | |
@@ -36,11 +40,13 b" hg ci -Amsrc -d '0 0'" | |||||
36 | chmod +x src |
|
40 | chmod +x src | |
37 | hg ci -munexec -d '0 0' |
|
41 | hg ci -munexec -d '0 0' | |
38 | echo '% chmod 644' |
|
42 | echo '% chmod 644' | |
39 |
hg diff --git -r 5:tip | sed "s/\( |
|
43 | hg diff --git -r 5:tip | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |
|
44 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" | |||
40 |
|
45 | |||
41 | hg mv src dst |
|
46 | hg mv src dst | |
42 | chmod -x dst |
|
47 | chmod -x dst | |
43 | echo a >> dst |
|
48 | echo a >> dst | |
44 | hg ci -mrenamemod -d '0 0' |
|
49 | hg ci -mrenamemod -d '0 0' | |
45 | echo '% rename+mod+chmod' |
|
50 | echo '% rename+mod+chmod' | |
46 |
hg diff --git -r 6:tip | sed "s/\( |
|
51 | hg diff --git -r 6:tip | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |
|
52 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" |
@@ -126,3 +126,30 b' echo x>x' | |||||
126 | hg ci -Ama |
|
126 | hg ci -Ama | |
127 | hg strip tip 2>&1 | sed 's/\(saving bundle to \).*/\1/' |
|
127 | hg strip tip 2>&1 | sed 's/\(saving bundle to \).*/\1/' | |
128 | hg unbundle .hg/strip-backup/* |
|
128 | hg unbundle .hg/strip-backup/* | |
|
129 | ||||
|
130 | cat >>$HGTMP/.hgrc <<EOF | |||
|
131 | [diff] | |||
|
132 | git = True | |||
|
133 | EOF | |||
|
134 | cd .. | |||
|
135 | hg init git | |||
|
136 | cd git | |||
|
137 | hg qinit | |||
|
138 | ||||
|
139 | hg qnew -m'new file' new | |||
|
140 | echo foo > new | |||
|
141 | chmod +x new | |||
|
142 | hg add new | |||
|
143 | hg qrefresh | |||
|
144 | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |||
|
145 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/new | |||
|
146 | ||||
|
147 | hg qnew -m'copy file' copy | |||
|
148 | hg cp new copy | |||
|
149 | hg qrefresh | |||
|
150 | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ | |||
|
151 | -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/copy | |||
|
152 | ||||
|
153 | hg qpop | |||
|
154 | hg qpush | |||
|
155 | hg qdiff |
@@ -127,3 +127,22 b' adding manifests' | |||||
127 | adding file changes |
|
127 | adding file changes | |
128 | added 1 changesets with 1 changes to 1 files |
|
128 | added 1 changesets with 1 changes to 1 files | |
129 | (run 'hg update' to get a working copy) |
|
129 | (run 'hg update' to get a working copy) | |
|
130 | new file | |||
|
131 | ||||
|
132 | diff --git a/new b/new | |||
|
133 | new file mode 100755 | |||
|
134 | --- /dev/null | |||
|
135 | +++ b/new | |||
|
136 | @@ -0,0 +1,1 @@ | |||
|
137 | +foo | |||
|
138 | copy file | |||
|
139 | ||||
|
140 | diff --git a/new b/copy | |||
|
141 | copy from new | |||
|
142 | copy to copy | |||
|
143 | Now at: new | |||
|
144 | applying copy | |||
|
145 | Now at: copy | |||
|
146 | diff --git a/new b/copy | |||
|
147 | copy from new | |||
|
148 | copy to copy |
General Comments 0
You need to be logged in to leave comments.
Login now