1# githelp.py - Try to map Git commands to Mercurial equivalents. 2# 3# Copyright 2013 Facebook, Inc. 4# 5# This software may be used and distributed according to the terms of the 6# GNU General Public License version 2 or any later version. 7"""try mapping git commands to Mercurial commands 8 9Tries to map a given git command to a Mercurial command: 10 11 $ hg githelp -- git checkout master 12 hg update master 13 14If an unknown command or parameter combination is detected, an error is 15produced. 16""" 17 18from __future__ import absolute_import 19 20import getopt 21import re 22 23from mercurial.i18n import _ 24from mercurial import ( 25 encoding, 26 error, 27 fancyopts, 28 pycompat, 29 registrar, 30 scmutil, 31) 32from mercurial.utils import procutil 33 34# Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for 35# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should 36# be specifying the version(s) of Mercurial they are tested with, or 37# leave the attribute unspecified. 38testedwith = b'ships-with-hg-core' 39 40cmdtable = {} 41command = registrar.command(cmdtable) 42 43 44def convert(s): 45 if s.startswith(b"origin/"): 46 return s[7:] 47 if b'HEAD' in s: 48 s = s.replace(b'HEAD', b'.') 49 # HEAD~ in git is .~1 in mercurial 50 s = re.sub(b'~$', b'~1', s) 51 return s 52 53 54@command( 55 b'githelp|git', 56 [], 57 _(b'hg githelp'), 58 helpcategory=command.CATEGORY_HELP, 59 helpbasic=True, 60) 61def githelp(ui, repo, *args, **kwargs): 62 """suggests the Mercurial equivalent of the given git command 63 64 Usage: hg githelp -- <git command> 65 """ 66 67 if len(args) == 0 or (len(args) == 1 and args[0] == b'git'): 68 raise error.Abort( 69 _(b'missing git command - usage: hg githelp -- <git command>') 70 ) 71 72 if args[0] == b'git': 73 args = args[1:] 74 75 cmd = args[0] 76 if not cmd in gitcommands: 77 raise error.Abort(_(b"error: unknown git command %s") % cmd) 78 79 ui.pager(b'githelp') 80 args = args[1:] 81 return gitcommands[cmd](ui, repo, *args, **kwargs) 82 83 84def parseoptions(ui, cmdoptions, args): 85 cmdoptions = list(cmdoptions) 86 opts = {} 87 args = list(args) 88 while True: 89 try: 90 args = fancyopts.fancyopts(list(args), cmdoptions, opts, True) 91 break 92 except getopt.GetoptError as ex: 93 if "requires argument" in ex.msg: 94 raise 95 if ('--' + ex.opt) in ex.msg: 96 flag = b'--' + pycompat.bytestr(ex.opt) 97 elif ('-' + ex.opt) in ex.msg: 98 flag = b'-' + pycompat.bytestr(ex.opt) 99 else: 100 raise error.Abort( 101 _(b"unknown option %s") % pycompat.bytestr(ex.opt) 102 ) 103 try: 104 args.remove(flag) 105 except Exception: 106 msg = _(b"unknown option '%s' packed with other options") 107 hint = _(b"please try passing the option as its own flag: -%s") 108 raise error.Abort( 109 msg % pycompat.bytestr(ex.opt), 110 hint=hint % pycompat.bytestr(ex.opt), 111 ) 112 113 ui.warn(_(b"ignoring unknown option %s\n") % flag) 114 115 args = list([convert(x) for x in args]) 116 opts = dict( 117 [ 118 (k, convert(v)) if isinstance(v, bytes) else (k, v) 119 for k, v in pycompat.iteritems(opts) 120 ] 121 ) 122 123 return args, opts 124 125 126class Command(object): 127 def __init__(self, name): 128 self.name = name 129 self.args = [] 130 self.opts = {} 131 132 def __bytes__(self): 133 cmd = b"hg " + self.name 134 if self.opts: 135 for k, values in sorted(pycompat.iteritems(self.opts)): 136 for v in values: 137 if v: 138 if isinstance(v, int): 139 fmt = b' %s %d' 140 else: 141 fmt = b' %s %s' 142 143 cmd += fmt % (k, v) 144 else: 145 cmd += b" %s" % (k,) 146 if self.args: 147 cmd += b" " 148 cmd += b" ".join(self.args) 149 return cmd 150 151 __str__ = encoding.strmethod(__bytes__) 152 153 def append(self, value): 154 self.args.append(value) 155 156 def extend(self, values): 157 self.args.extend(values) 158 159 def __setitem__(self, key, value): 160 values = self.opts.setdefault(key, []) 161 values.append(value) 162 163 def __and__(self, other): 164 return AndCommand(self, other) 165 166 167class AndCommand(object): 168 def __init__(self, left, right): 169 self.left = left 170 self.right = right 171 172 def __str__(self): 173 return b"%s && %s" % (self.left, self.right) 174 175 def __and__(self, other): 176 return AndCommand(self, other) 177 178 179def add(ui, repo, *args, **kwargs): 180 cmdoptions = [ 181 (b'A', b'all', None, b''), 182 (b'p', b'patch', None, b''), 183 ] 184 args, opts = parseoptions(ui, cmdoptions, args) 185 186 if opts.get(b'patch'): 187 ui.status( 188 _( 189 b"note: Mercurial will commit when complete, " 190 b"as there is no staging area in Mercurial\n\n" 191 ) 192 ) 193 cmd = Command(b'commit --interactive') 194 else: 195 cmd = Command(b"add") 196 197 if not opts.get(b'all'): 198 cmd.extend(args) 199 else: 200 ui.status( 201 _( 202 b"note: use hg addremove to remove files that have " 203 b"been deleted\n\n" 204 ) 205 ) 206 207 ui.status((bytes(cmd)), b"\n") 208 209 210def am(ui, repo, *args, **kwargs): 211 cmdoptions = [] 212 parseoptions(ui, cmdoptions, args) 213 cmd = Command(b'import') 214 ui.status(bytes(cmd), b"\n") 215 216 217def apply(ui, repo, *args, **kwargs): 218 cmdoptions = [ 219 (b'p', b'p', int, b''), 220 (b'', b'directory', b'', b''), 221 ] 222 args, opts = parseoptions(ui, cmdoptions, args) 223 224 cmd = Command(b'import --no-commit') 225 if opts.get(b'p'): 226 cmd[b'-p'] = opts.get(b'p') 227 if opts.get(b'directory'): 228 cmd[b'--prefix'] = opts.get(b'directory') 229 cmd.extend(args) 230 231 ui.status((bytes(cmd)), b"\n") 232 233 234def bisect(ui, repo, *args, **kwargs): 235 ui.status(_(b"see 'hg help bisect' for how to use bisect\n\n")) 236 237 238def blame(ui, repo, *args, **kwargs): 239 cmdoptions = [] 240 args, opts = parseoptions(ui, cmdoptions, args) 241 cmd = Command(b'annotate -udl') 242 cmd.extend([convert(v) for v in args]) 243 ui.status((bytes(cmd)), b"\n") 244 245 246def branch(ui, repo, *args, **kwargs): 247 cmdoptions = [ 248 (b'', b'set-upstream', None, b''), 249 (b'', b'set-upstream-to', b'', b''), 250 (b'd', b'delete', None, b''), 251 (b'D', b'delete', None, b''), 252 (b'm', b'move', None, b''), 253 (b'M', b'move', None, b''), 254 ] 255 args, opts = parseoptions(ui, cmdoptions, args) 256 257 cmd = Command(b"bookmark") 258 259 if opts.get(b'set_upstream') or opts.get(b'set_upstream_to'): 260 ui.status(_(b"Mercurial has no concept of upstream branches\n")) 261 return 262 elif opts.get(b'delete'): 263 cmd = Command(b"strip") 264 for branch in args: 265 cmd[b'-B'] = branch 266 else: 267 cmd[b'-B'] = None 268 elif opts.get(b'move'): 269 if len(args) > 0: 270 if len(args) > 1: 271 old = args.pop(0) 272 else: 273 # shell command to output the active bookmark for the active 274 # revision 275 old = b'`hg log -T"{activebookmark}" -r .`' 276 else: 277 raise error.Abort(_(b'missing newbranch argument')) 278 new = args[0] 279 cmd[b'-m'] = old 280 cmd.append(new) 281 else: 282 if len(args) > 1: 283 cmd[b'-r'] = args[1] 284 cmd.append(args[0]) 285 elif len(args) == 1: 286 cmd.append(args[0]) 287 ui.status((bytes(cmd)), b"\n") 288 289 290def ispath(repo, string): 291 """ 292 The first argument to git checkout can either be a revision or a path. Let's 293 generally assume it's a revision, unless it's obviously a path. There are 294 too many ways to spell revisions in git for us to reasonably catch all of 295 them, so let's be conservative. 296 """ 297 if scmutil.isrevsymbol(repo, string): 298 # if it's definitely a revision let's not even check if a file of the 299 # same name exists. 300 return False 301 302 cwd = repo.getcwd() 303 if cwd == b'': 304 repopath = string 305 else: 306 repopath = cwd + b'/' + string 307 308 exists = repo.wvfs.exists(repopath) 309 if exists: 310 return True 311 312 manifest = repo[b'.'].manifest() 313 314 didexist = (repopath in manifest) or manifest.hasdir(repopath) 315 316 return didexist 317 318 319def checkout(ui, repo, *args, **kwargs): 320 cmdoptions = [ 321 (b'b', b'branch', b'', b''), 322 (b'B', b'branch', b'', b''), 323 (b'f', b'force', None, b''), 324 (b'p', b'patch', None, b''), 325 ] 326 paths = [] 327 if b'--' in args: 328 sepindex = args.index(b'--') 329 paths.extend(args[sepindex + 1 :]) 330 args = args[:sepindex] 331 332 args, opts = parseoptions(ui, cmdoptions, args) 333 334 rev = None 335 if args and ispath(repo, args[0]): 336 paths = args + paths 337 elif args: 338 rev = args[0] 339 paths = args[1:] + paths 340 341 cmd = Command(b'update') 342 343 if opts.get(b'force'): 344 if paths or rev: 345 cmd[b'-C'] = None 346 347 if opts.get(b'patch'): 348 cmd = Command(b'revert') 349 cmd[b'-i'] = None 350 351 if opts.get(b'branch'): 352 if len(args) == 0: 353 cmd = Command(b'bookmark') 354 cmd.append(opts.get(b'branch')) 355 else: 356 cmd.append(args[0]) 357 bookcmd = Command(b'bookmark') 358 bookcmd.append(opts.get(b'branch')) 359 cmd = cmd & bookcmd 360 # if there is any path argument supplied, use revert instead of update 361 elif len(paths) > 0: 362 ui.status(_(b"note: use --no-backup to avoid creating .orig files\n\n")) 363 cmd = Command(b'revert') 364 if opts.get(b'patch'): 365 cmd[b'-i'] = None 366 if rev: 367 cmd[b'-r'] = rev 368 cmd.extend(paths) 369 elif rev: 370 if opts.get(b'patch'): 371 cmd[b'-r'] = rev 372 else: 373 cmd.append(rev) 374 elif opts.get(b'force'): 375 cmd = Command(b'revert') 376 cmd[b'--all'] = None 377 else: 378 raise error.Abort(_(b"a commit must be specified")) 379 380 ui.status((bytes(cmd)), b"\n") 381 382 383def cherrypick(ui, repo, *args, **kwargs): 384 cmdoptions = [ 385 (b'', b'continue', None, b''), 386 (b'', b'abort', None, b''), 387 (b'e', b'edit', None, b''), 388 ] 389 args, opts = parseoptions(ui, cmdoptions, args) 390 391 cmd = Command(b'graft') 392 393 if opts.get(b'edit'): 394 cmd[b'--edit'] = None 395 if opts.get(b'continue'): 396 cmd[b'--continue'] = None 397 elif opts.get(b'abort'): 398 ui.status(_(b"note: hg graft does not have --abort\n\n")) 399 return 400 else: 401 cmd.extend(args) 402 403 ui.status((bytes(cmd)), b"\n") 404 405 406def clean(ui, repo, *args, **kwargs): 407 cmdoptions = [ 408 (b'd', b'd', None, b''), 409 (b'f', b'force', None, b''), 410 (b'x', b'x', None, b''), 411 ] 412 args, opts = parseoptions(ui, cmdoptions, args) 413 414 cmd = Command(b'purge') 415 if opts.get(b'x'): 416 cmd[b'--all'] = None 417 cmd.extend(args) 418 419 ui.status((bytes(cmd)), b"\n") 420 421 422def clone(ui, repo, *args, **kwargs): 423 cmdoptions = [ 424 (b'', b'bare', None, b''), 425 (b'n', b'no-checkout', None, b''), 426 (b'b', b'branch', b'', b''), 427 ] 428 args, opts = parseoptions(ui, cmdoptions, args) 429 430 if len(args) == 0: 431 raise error.Abort(_(b"a repository to clone must be specified")) 432 433 cmd = Command(b'clone') 434 cmd.append(args[0]) 435 if len(args) > 1: 436 cmd.append(args[1]) 437 438 if opts.get(b'bare'): 439 cmd[b'-U'] = None 440 ui.status( 441 _( 442 b"note: Mercurial does not have bare clones. " 443 b"-U will clone the repo without checking out a commit\n\n" 444 ) 445 ) 446 elif opts.get(b'no_checkout'): 447 cmd[b'-U'] = None 448 449 if opts.get(b'branch'): 450 cocmd = Command(b"update") 451 cocmd.append(opts.get(b'branch')) 452 cmd = cmd & cocmd 453 454 ui.status((bytes(cmd)), b"\n") 455 456 457def commit(ui, repo, *args, **kwargs): 458 cmdoptions = [ 459 (b'a', b'all', None, b''), 460 (b'm', b'message', b'', b''), 461 (b'p', b'patch', None, b''), 462 (b'C', b'reuse-message', b'', b''), 463 (b'F', b'file', b'', b''), 464 (b'', b'author', b'', b''), 465 (b'', b'date', b'', b''), 466 (b'', b'amend', None, b''), 467 (b'', b'no-edit', None, b''), 468 ] 469 args, opts = parseoptions(ui, cmdoptions, args) 470 471 cmd = Command(b'commit') 472 if opts.get(b'patch'): 473 cmd = Command(b'commit --interactive') 474 475 if opts.get(b'amend'): 476 if opts.get(b'no_edit'): 477 cmd = Command(b'amend') 478 else: 479 cmd[b'--amend'] = None 480 481 if opts.get(b'reuse_message'): 482 cmd[b'-M'] = opts.get(b'reuse_message') 483 484 if opts.get(b'message'): 485 cmd[b'-m'] = b"'%s'" % (opts.get(b'message'),) 486 487 if opts.get(b'all'): 488 ui.status( 489 _( 490 b"note: Mercurial doesn't have a staging area, " 491 b"so there is no --all. -A will add and remove files " 492 b"for you though.\n\n" 493 ) 494 ) 495 496 if opts.get(b'file'): 497 cmd[b'-l'] = opts.get(b'file') 498 499 if opts.get(b'author'): 500 cmd[b'-u'] = opts.get(b'author') 501 502 if opts.get(b'date'): 503 cmd[b'-d'] = opts.get(b'date') 504 505 cmd.extend(args) 506 507 ui.status((bytes(cmd)), b"\n") 508 509 510def deprecated(ui, repo, *args, **kwargs): 511 ui.warn( 512 _( 513 b'this command has been deprecated in the git project, ' 514 b'thus isn\'t supported by this tool\n\n' 515 ) 516 ) 517 518 519def diff(ui, repo, *args, **kwargs): 520 cmdoptions = [ 521 (b'a', b'all', None, b''), 522 (b'', b'cached', None, b''), 523 (b'R', b'reverse', None, b''), 524 ] 525 args, opts = parseoptions(ui, cmdoptions, args) 526 527 cmd = Command(b'diff') 528 529 if opts.get(b'cached'): 530 ui.status( 531 _( 532 b'note: Mercurial has no concept of a staging area, ' 533 b'so --cached does nothing\n\n' 534 ) 535 ) 536 537 if opts.get(b'reverse'): 538 cmd[b'--reverse'] = None 539 540 for a in list(args): 541 args.remove(a) 542 try: 543 repo.revs(a) 544 cmd[b'-r'] = a 545 except Exception: 546 cmd.append(a) 547 548 ui.status((bytes(cmd)), b"\n") 549 550 551def difftool(ui, repo, *args, **kwargs): 552 ui.status( 553 _( 554 b'Mercurial does not enable external difftool by default. You ' 555 b'need to enable the extdiff extension in your .hgrc file by adding\n' 556 b'extdiff =\n' 557 b'to the [extensions] section and then running\n\n' 558 b'hg extdiff -p <program>\n\n' 559 b'See \'hg help extdiff\' and \'hg help -e extdiff\' for more ' 560 b'information.\n' 561 ) 562 ) 563 564 565def fetch(ui, repo, *args, **kwargs): 566 cmdoptions = [ 567 (b'', b'all', None, b''), 568 (b'f', b'force', None, b''), 569 ] 570 args, opts = parseoptions(ui, cmdoptions, args) 571 572 cmd = Command(b'pull') 573 574 if len(args) > 0: 575 cmd.append(args[0]) 576 if len(args) > 1: 577 ui.status( 578 _( 579 b"note: Mercurial doesn't have refspecs. " 580 b"-r can be used to specify which commits you want to " 581 b"pull. -B can be used to specify which bookmark you " 582 b"want to pull.\n\n" 583 ) 584 ) 585 for v in args[1:]: 586 if v in repo._bookmarks: 587 cmd[b'-B'] = v 588 else: 589 cmd[b'-r'] = v 590 591 ui.status((bytes(cmd)), b"\n") 592 593 594def grep(ui, repo, *args, **kwargs): 595 cmdoptions = [] 596 args, opts = parseoptions(ui, cmdoptions, args) 597 598 cmd = Command(b'grep') 599 600 # For basic usage, git grep and hg grep are the same. They both have the 601 # pattern first, followed by paths. 602 cmd.extend(args) 603 604 ui.status((bytes(cmd)), b"\n") 605 606 607def init(ui, repo, *args, **kwargs): 608 cmdoptions = [] 609 args, opts = parseoptions(ui, cmdoptions, args) 610 611 cmd = Command(b'init') 612 613 if len(args) > 0: 614 cmd.append(args[0]) 615 616 ui.status((bytes(cmd)), b"\n") 617 618 619def log(ui, repo, *args, **kwargs): 620 cmdoptions = [ 621 (b'', b'follow', None, b''), 622 (b'', b'decorate', None, b''), 623 (b'n', b'number', b'', b''), 624 (b'1', b'1', None, b''), 625 (b'', b'pretty', b'', b''), 626 (b'', b'format', b'', b''), 627 (b'', b'oneline', None, b''), 628 (b'', b'stat', None, b''), 629 (b'', b'graph', None, b''), 630 (b'p', b'patch', None, b''), 631 (b'G', b'grep-diff', b'', b''), 632 (b'S', b'pickaxe-regex', b'', b''), 633 ] 634 args, opts = parseoptions(ui, cmdoptions, args) 635 grep_pat = opts.get(b'grep_diff') or opts.get(b'pickaxe_regex') 636 if grep_pat: 637 cmd = Command(b'grep') 638 cmd[b'--diff'] = grep_pat 639 ui.status(b'%s\n' % bytes(cmd)) 640 return 641 642 ui.status( 643 _( 644 b'note: -v prints the entire commit message like Git does. To ' 645 b'print just the first line, drop the -v.\n\n' 646 ) 647 ) 648 ui.status( 649 _( 650 b"note: see hg help revset for information on how to filter " 651 b"log output\n\n" 652 ) 653 ) 654 655 cmd = Command(b'log') 656 cmd[b'-v'] = None 657 658 if opts.get(b'number'): 659 cmd[b'-l'] = opts.get(b'number') 660 if opts.get(b'1'): 661 cmd[b'-l'] = b'1' 662 if opts.get(b'stat'): 663 cmd[b'--stat'] = None 664 if opts.get(b'graph'): 665 cmd[b'-G'] = None 666 if opts.get(b'patch'): 667 cmd[b'-p'] = None 668 669 if opts.get(b'pretty') or opts.get(b'format') or opts.get(b'oneline'): 670 format = opts.get(b'format', b'') 671 if b'format:' in format: 672 ui.status( 673 _( 674 b"note: --format format:??? equates to Mercurial's " 675 b"--template. See hg help templates for more info.\n\n" 676 ) 677 ) 678 cmd[b'--template'] = b'???' 679 else: 680 ui.status( 681 _( 682 b"note: --pretty/format/oneline equate to Mercurial's " 683 b"--style or --template. See hg help templates for " 684 b"more info.\n\n" 685 ) 686 ) 687 cmd[b'--style'] = b'???' 688 689 if len(args) > 0: 690 if b'..' in args[0]: 691 since, until = args[0].split(b'..') 692 cmd[b'-r'] = b"'%s::%s'" % (since, until) 693 del args[0] 694 cmd.extend(args) 695 696 ui.status((bytes(cmd)), b"\n") 697 698 699def lsfiles(ui, repo, *args, **kwargs): 700 cmdoptions = [ 701 (b'c', b'cached', None, b''), 702 (b'd', b'deleted', None, b''), 703 (b'm', b'modified', None, b''), 704 (b'o', b'others', None, b''), 705 (b'i', b'ignored', None, b''), 706 (b's', b'stage', None, b''), 707 (b'z', b'_zero', None, b''), 708 ] 709 args, opts = parseoptions(ui, cmdoptions, args) 710 711 if ( 712 opts.get(b'modified') 713 or opts.get(b'deleted') 714 or opts.get(b'others') 715 or opts.get(b'ignored') 716 ): 717 cmd = Command(b'status') 718 if opts.get(b'deleted'): 719 cmd[b'-d'] = None 720 if opts.get(b'modified'): 721 cmd[b'-m'] = None 722 if opts.get(b'others'): 723 cmd[b'-o'] = None 724 if opts.get(b'ignored'): 725 cmd[b'-i'] = None 726 else: 727 cmd = Command(b'files') 728 if opts.get(b'stage'): 729 ui.status( 730 _( 731 b"note: Mercurial doesn't have a staging area, ignoring " 732 b"--stage\n" 733 ) 734 ) 735 if opts.get(b'_zero'): 736 cmd[b'-0'] = None 737 cmd.append(b'.') 738 for include in args: 739 cmd[b'-I'] = procutil.shellquote(include) 740 741 ui.status((bytes(cmd)), b"\n") 742 743 744def merge(ui, repo, *args, **kwargs): 745 cmdoptions = [] 746 args, opts = parseoptions(ui, cmdoptions, args) 747 748 cmd = Command(b'merge') 749 750 if len(args) > 0: 751 cmd.append(args[len(args) - 1]) 752 753 ui.status((bytes(cmd)), b"\n") 754 755 756def mergebase(ui, repo, *args, **kwargs): 757 cmdoptions = [] 758 args, opts = parseoptions(ui, cmdoptions, args) 759 760 if len(args) != 2: 761 args = [b'A', b'B'] 762 763 cmd = Command( 764 b"log -T '{node}\\n' -r 'ancestor(%s,%s)'" % (args[0], args[1]) 765 ) 766 767 ui.status( 768 _(b'note: ancestors() is part of the revset language\n'), 769 _(b"(learn more about revsets with 'hg help revsets')\n\n"), 770 ) 771 ui.status((bytes(cmd)), b"\n") 772 773 774def mergetool(ui, repo, *args, **kwargs): 775 cmdoptions = [] 776 args, opts = parseoptions(ui, cmdoptions, args) 777 778 cmd = Command(b"resolve") 779 780 if len(args) == 0: 781 cmd[b'--all'] = None 782 cmd.extend(args) 783 ui.status((bytes(cmd)), b"\n") 784 785 786def mv(ui, repo, *args, **kwargs): 787 cmdoptions = [ 788 (b'f', b'force', None, b''), 789 (b'n', b'dry-run', None, b''), 790 ] 791 args, opts = parseoptions(ui, cmdoptions, args) 792 793 cmd = Command(b'mv') 794 cmd.extend(args) 795 796 if opts.get(b'force'): 797 cmd[b'-f'] = None 798 if opts.get(b'dry_run'): 799 cmd[b'-n'] = None 800 801 ui.status((bytes(cmd)), b"\n") 802 803 804def pull(ui, repo, *args, **kwargs): 805 cmdoptions = [ 806 (b'', b'all', None, b''), 807 (b'f', b'force', None, b''), 808 (b'r', b'rebase', None, b''), 809 ] 810 args, opts = parseoptions(ui, cmdoptions, args) 811 812 cmd = Command(b'pull') 813 cmd[b'--rebase'] = None 814 815 if len(args) > 0: 816 cmd.append(args[0]) 817 if len(args) > 1: 818 ui.status( 819 _( 820 b"note: Mercurial doesn't have refspecs. " 821 b"-r can be used to specify which commits you want to " 822 b"pull. -B can be used to specify which bookmark you " 823 b"want to pull.\n\n" 824 ) 825 ) 826 for v in args[1:]: 827 if v in repo._bookmarks: 828 cmd[b'-B'] = v 829 else: 830 cmd[b'-r'] = v 831 832 ui.status((bytes(cmd)), b"\n") 833 834 835def push(ui, repo, *args, **kwargs): 836 cmdoptions = [ 837 (b'', b'all', None, b''), 838 (b'f', b'force', None, b''), 839 ] 840 args, opts = parseoptions(ui, cmdoptions, args) 841 842 cmd = Command(b'push') 843 844 if len(args) > 0: 845 cmd.append(args[0]) 846 if len(args) > 1: 847 ui.status( 848 _( 849 b"note: Mercurial doesn't have refspecs. " 850 b"-r can be used to specify which commits you want " 851 b"to push. -B can be used to specify which bookmark " 852 b"you want to push.\n\n" 853 ) 854 ) 855 for v in args[1:]: 856 if v in repo._bookmarks: 857 cmd[b'-B'] = v 858 else: 859 cmd[b'-r'] = v 860 861 if opts.get(b'force'): 862 cmd[b'-f'] = None 863 864 ui.status((bytes(cmd)), b"\n") 865 866 867def rebase(ui, repo, *args, **kwargs): 868 cmdoptions = [ 869 (b'', b'all', None, b''), 870 (b'i', b'interactive', None, b''), 871 (b'', b'onto', b'', b''), 872 (b'', b'abort', None, b''), 873 (b'', b'continue', None, b''), 874 (b'', b'skip', None, b''), 875 ] 876 args, opts = parseoptions(ui, cmdoptions, args) 877 878 if opts.get(b'interactive'): 879 ui.status( 880 _( 881 b"note: hg histedit does not perform a rebase. " 882 b"It just edits history.\n\n" 883 ) 884 ) 885 cmd = Command(b'histedit') 886 if len(args) > 0: 887 ui.status( 888 _( 889 b"also note: 'hg histedit' will automatically detect" 890 b" your stack, so no second argument is necessary\n\n" 891 ) 892 ) 893 ui.status((bytes(cmd)), b"\n") 894 return 895 896 if opts.get(b'skip'): 897 cmd = Command(b'revert --all -r .') 898 ui.status((bytes(cmd)), b"\n") 899 900 cmd = Command(b'rebase') 901 902 if opts.get(b'continue') or opts.get(b'skip'): 903 cmd[b'--continue'] = None 904 if opts.get(b'abort'): 905 cmd[b'--abort'] = None 906 907 if opts.get(b'onto'): 908 ui.status( 909 _( 910 b"note: if you're trying to lift a commit off one branch, " 911 b"try hg rebase -d <destination commit> -s <commit to be " 912 b"lifted>\n\n" 913 ) 914 ) 915 cmd[b'-d'] = convert(opts.get(b'onto')) 916 if len(args) < 2: 917 raise error.Abort(_(b"expected format: git rebase --onto X Y Z")) 918 cmd[b'-s'] = b"'::%s - ::%s'" % (convert(args[1]), convert(args[0])) 919 else: 920 if len(args) == 1: 921 cmd[b'-d'] = convert(args[0]) 922 elif len(args) == 2: 923 cmd[b'-d'] = convert(args[0]) 924 cmd[b'-b'] = convert(args[1]) 925 926 ui.status((bytes(cmd)), b"\n") 927 928 929def reflog(ui, repo, *args, **kwargs): 930 cmdoptions = [ 931 (b'', b'all', None, b''), 932 ] 933 args, opts = parseoptions(ui, cmdoptions, args) 934 935 cmd = Command(b'journal') 936 if opts.get(b'all'): 937 cmd[b'--all'] = None 938 if len(args) > 0: 939 cmd.append(args[0]) 940 941 ui.status(bytes(cmd), b"\n\n") 942 ui.status( 943 _( 944 b"note: in hg commits can be deleted from repo but we always" 945 b" have backups\n" 946 ) 947 ) 948 949 950def reset(ui, repo, *args, **kwargs): 951 cmdoptions = [ 952 (b'', b'soft', None, b''), 953 (b'', b'hard', None, b''), 954 (b'', b'mixed', None, b''), 955 ] 956 args, opts = parseoptions(ui, cmdoptions, args) 957 958 commit = convert(args[0] if len(args) > 0 else b'.') 959 hard = opts.get(b'hard') 960 961 if opts.get(b'mixed'): 962 ui.status( 963 _( 964 b'note: --mixed has no meaning since Mercurial has no ' 965 b'staging area\n\n' 966 ) 967 ) 968 if opts.get(b'soft'): 969 ui.status( 970 _( 971 b'note: --soft has no meaning since Mercurial has no ' 972 b'staging area\n\n' 973 ) 974 ) 975 976 cmd = Command(b'update') 977 if hard: 978 cmd.append(b'--clean') 979 980 cmd.append(commit) 981 982 ui.status((bytes(cmd)), b"\n") 983 984 985def revert(ui, repo, *args, **kwargs): 986 cmdoptions = [] 987 args, opts = parseoptions(ui, cmdoptions, args) 988 989 if len(args) > 1: 990 ui.status( 991 _( 992 b"note: hg backout doesn't support multiple commits at " 993 b"once\n\n" 994 ) 995 ) 996 997 cmd = Command(b'backout') 998 if args: 999 cmd.append(args[0]) 1000 1001 ui.status((bytes(cmd)), b"\n") 1002 1003 1004def revparse(ui, repo, *args, **kwargs): 1005 cmdoptions = [ 1006 (b'', b'show-cdup', None, b''), 1007 (b'', b'show-toplevel', None, b''), 1008 ] 1009 args, opts = parseoptions(ui, cmdoptions, args) 1010 1011 if opts.get(b'show_cdup') or opts.get(b'show_toplevel'): 1012 cmd = Command(b'root') 1013 if opts.get(b'show_cdup'): 1014 ui.status(_(b"note: hg root prints the root of the repository\n\n")) 1015 ui.status((bytes(cmd)), b"\n") 1016 else: 1017 ui.status(_(b"note: see hg help revset for how to refer to commits\n")) 1018 1019 1020def rm(ui, repo, *args, **kwargs): 1021 cmdoptions = [ 1022 (b'f', b'force', None, b''), 1023 (b'n', b'dry-run', None, b''), 1024 ] 1025 args, opts = parseoptions(ui, cmdoptions, args) 1026 1027 cmd = Command(b'rm') 1028 cmd.extend(args) 1029 1030 if opts.get(b'force'): 1031 cmd[b'-f'] = None 1032 if opts.get(b'dry_run'): 1033 cmd[b'-n'] = None 1034 1035 ui.status((bytes(cmd)), b"\n") 1036 1037 1038def show(ui, repo, *args, **kwargs): 1039 cmdoptions = [ 1040 (b'', b'name-status', None, b''), 1041 (b'', b'pretty', b'', b''), 1042 (b'U', b'unified', int, b''), 1043 ] 1044 args, opts = parseoptions(ui, cmdoptions, args) 1045 1046 if opts.get(b'name_status'): 1047 if opts.get(b'pretty') == b'format:': 1048 cmd = Command(b'status') 1049 cmd[b'--change'] = b'.' 1050 else: 1051 cmd = Command(b'log') 1052 cmd.append(b'--style status') 1053 cmd.append(b'-r .') 1054 elif len(args) > 0: 1055 if ispath(repo, args[0]): 1056 cmd = Command(b'cat') 1057 else: 1058 cmd = Command(b'export') 1059 cmd.extend(args) 1060 if opts.get(b'unified'): 1061 cmd.append(b'--config diff.unified=%d' % (opts[b'unified'],)) 1062 elif opts.get(b'unified'): 1063 cmd = Command(b'export') 1064 cmd.append(b'--config diff.unified=%d' % (opts[b'unified'],)) 1065 else: 1066 cmd = Command(b'export') 1067 1068 ui.status((bytes(cmd)), b"\n") 1069 1070 1071def stash(ui, repo, *args, **kwargs): 1072 cmdoptions = [ 1073 (b'p', b'patch', None, b''), 1074 ] 1075 args, opts = parseoptions(ui, cmdoptions, args) 1076 1077 cmd = Command(b'shelve') 1078 action = args[0] if len(args) > 0 else None 1079 1080 if action == b'list': 1081 cmd[b'-l'] = None 1082 if opts.get(b'patch'): 1083 cmd[b'-p'] = None 1084 elif action == b'show': 1085 if opts.get(b'patch'): 1086 cmd[b'-p'] = None 1087 else: 1088 cmd[b'--stat'] = None 1089 if len(args) > 1: 1090 cmd.append(args[1]) 1091 elif action == b'clear': 1092 cmd[b'--cleanup'] = None 1093 elif action == b'drop': 1094 cmd[b'-d'] = None 1095 if len(args) > 1: 1096 cmd.append(args[1]) 1097 else: 1098 cmd.append(b'<shelve name>') 1099 elif action == b'pop' or action == b'apply': 1100 cmd = Command(b'unshelve') 1101 if len(args) > 1: 1102 cmd.append(args[1]) 1103 if action == b'apply': 1104 cmd[b'--keep'] = None 1105 elif action == b'branch' or action == b'create': 1106 ui.status( 1107 _( 1108 b"note: Mercurial doesn't have equivalents to the " 1109 b"git stash branch or create actions\n\n" 1110 ) 1111 ) 1112 return 1113 else: 1114 if len(args) > 0: 1115 if args[0] != b'save': 1116 cmd[b'--name'] = args[0] 1117 elif len(args) > 1: 1118 cmd[b'--name'] = args[1] 1119 1120 ui.status((bytes(cmd)), b"\n") 1121 1122 1123def status(ui, repo, *args, **kwargs): 1124 cmdoptions = [ 1125 (b'', b'ignored', None, b''), 1126 ] 1127 args, opts = parseoptions(ui, cmdoptions, args) 1128 1129 cmd = Command(b'status') 1130 cmd.extend(args) 1131 1132 if opts.get(b'ignored'): 1133 cmd[b'-i'] = None 1134 1135 ui.status((bytes(cmd)), b"\n") 1136 1137 1138def svn(ui, repo, *args, **kwargs): 1139 if not args: 1140 raise error.Abort(_(b'missing svn command')) 1141 svncmd = args[0] 1142 if svncmd not in gitsvncommands: 1143 raise error.Abort(_(b'unknown git svn command "%s"') % svncmd) 1144 1145 args = args[1:] 1146 return gitsvncommands[svncmd](ui, repo, *args, **kwargs) 1147 1148 1149def svndcommit(ui, repo, *args, **kwargs): 1150 cmdoptions = [] 1151 parseoptions(ui, cmdoptions, args) 1152 1153 cmd = Command(b'push') 1154 1155 ui.status((bytes(cmd)), b"\n") 1156 1157 1158def svnfetch(ui, repo, *args, **kwargs): 1159 cmdoptions = [] 1160 parseoptions(ui, cmdoptions, args) 1161 1162 cmd = Command(b'pull') 1163 cmd.append(b'default-push') 1164 1165 ui.status((bytes(cmd)), b"\n") 1166 1167 1168def svnfindrev(ui, repo, *args, **kwargs): 1169 cmdoptions = [] 1170 args, opts = parseoptions(ui, cmdoptions, args) 1171 1172 if not args: 1173 raise error.Abort(_(b'missing find-rev argument')) 1174 1175 cmd = Command(b'log') 1176 cmd[b'-r'] = args[0] 1177 1178 ui.status((bytes(cmd)), b"\n") 1179 1180 1181def svnrebase(ui, repo, *args, **kwargs): 1182 cmdoptions = [ 1183 (b'l', b'local', None, b''), 1184 ] 1185 parseoptions(ui, cmdoptions, args) 1186 1187 pullcmd = Command(b'pull') 1188 pullcmd.append(b'default-push') 1189 rebasecmd = Command(b'rebase') 1190 rebasecmd.append(b'tip') 1191 1192 cmd = pullcmd & rebasecmd 1193 1194 ui.status((bytes(cmd)), b"\n") 1195 1196 1197def tag(ui, repo, *args, **kwargs): 1198 cmdoptions = [ 1199 (b'f', b'force', None, b''), 1200 (b'l', b'list', None, b''), 1201 (b'd', b'delete', None, b''), 1202 ] 1203 args, opts = parseoptions(ui, cmdoptions, args) 1204 1205 if opts.get(b'list'): 1206 cmd = Command(b'tags') 1207 else: 1208 cmd = Command(b'tag') 1209 1210 if not args: 1211 raise error.Abort(_(b'missing tag argument')) 1212 1213 cmd.append(args[0]) 1214 if len(args) > 1: 1215 cmd[b'-r'] = args[1] 1216 1217 if opts.get(b'delete'): 1218 cmd[b'--remove'] = None 1219 1220 if opts.get(b'force'): 1221 cmd[b'-f'] = None 1222 1223 ui.status((bytes(cmd)), b"\n") 1224 1225 1226gitcommands = { 1227 b'add': add, 1228 b'am': am, 1229 b'apply': apply, 1230 b'bisect': bisect, 1231 b'blame': blame, 1232 b'branch': branch, 1233 b'checkout': checkout, 1234 b'cherry-pick': cherrypick, 1235 b'clean': clean, 1236 b'clone': clone, 1237 b'commit': commit, 1238 b'diff': diff, 1239 b'difftool': difftool, 1240 b'fetch': fetch, 1241 b'grep': grep, 1242 b'init': init, 1243 b'log': log, 1244 b'ls-files': lsfiles, 1245 b'merge': merge, 1246 b'merge-base': mergebase, 1247 b'mergetool': mergetool, 1248 b'mv': mv, 1249 b'pull': pull, 1250 b'push': push, 1251 b'rebase': rebase, 1252 b'reflog': reflog, 1253 b'reset': reset, 1254 b'revert': revert, 1255 b'rev-parse': revparse, 1256 b'rm': rm, 1257 b'show': show, 1258 b'stash': stash, 1259 b'status': status, 1260 b'svn': svn, 1261 b'tag': tag, 1262 b'whatchanged': deprecated, 1263} 1264 1265gitsvncommands = { 1266 b'dcommit': svndcommit, 1267 b'fetch': svnfetch, 1268 b'find-rev': svnfindrev, 1269 b'rebase': svnrebase, 1270} 1271