Mercurial > public > mercurial-scm > hg
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 } |