comparison hgext/githelp.py @ 35714:113281667205

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