1 """Launcher and command line interface to git-cola"""
2 from __future__
import absolute_import
, division
, unicode_literals
14 # we're using argparse with subparser, but argparse
15 # does not allow us to assign a default subparser
16 # when none has been specified. We fake it by injecting
17 # 'cola' into the command-line so that parse_args()
18 # routes them to the 'cola' parser by default.
19 help_commands
= core
.encode('--help-commands')
20 args
= [core
.encode(arg
) for arg
in argv
]
22 argv
[0].startswith('-') and help_commands
not in args
):
23 argv
.insert(0, 'cola')
24 elif help_commands
in argv
:
26 args
= parse_args(argv
)
27 return args
.func(args
)
31 return app
.winmain(main
)
35 parser
= argparse
.ArgumentParser()
36 subparser
= parser
.add_subparsers(title
='valid commands')
38 add_cola_command(subparser
)
39 add_about_command(subparser
)
40 add_am_command(subparser
)
41 add_archive_command(subparser
)
42 add_branch_command(subparser
)
43 add_browse_command(subparser
)
44 add_clone_command(subparser
)
45 add_config_command(subparser
)
46 add_dag_command(subparser
)
47 add_diff_command(subparser
)
48 add_fetch_command(subparser
)
49 add_find_command(subparser
)
50 add_grep_command(subparser
)
51 add_merge_command(subparser
)
52 add_pull_command(subparser
)
53 add_push_command(subparser
)
54 add_rebase_command(subparser
)
55 add_recent_command(subparser
)
56 add_remote_command(subparser
)
57 add_search_command(subparser
)
58 add_stash_command(subparser
)
59 add_tag_command(subparser
)
60 add_version_command(subparser
)
62 return parser
.parse_args(argv
)
65 def add_command(parent
, name
, description
, func
):
66 parser
= parent
.add_parser(str(name
), help=description
)
67 parser
.set_defaults(func
=func
)
68 app
.add_common_arguments(parser
)
72 def add_cola_command(subparser
):
73 parser
= add_command(subparser
, 'cola', 'start git-cola', cmd_cola
)
74 parser
.add_argument('--amend', default
=False, action
='store_true',
75 help='start in amend mode')
76 parser
.add_argument('--help-commands', default
=False, action
='store_true',
77 help='show available sub-commands')
78 parser
.add_argument('--status-filter', '-s', metavar
='<path>',
79 default
='', help='status path filter')
82 def add_about_command(parent
):
83 add_command(parent
, 'about', 'about git-cola', cmd_about
)
86 def add_am_command(parent
):
87 parser
= add_command(parent
, 'am', 'apply patches using "git am"', cmd_am
)
88 parser
.add_argument('patches', metavar
='<patches>', nargs
='*',
89 help='patches to apply')
92 def add_archive_command(parent
):
93 parser
= add_command(parent
, 'archive', 'save an archive', cmd_archive
)
94 parser
.add_argument('ref', metavar
='<ref>', nargs
='?', default
=None,
95 help='commit to archive')
98 def add_branch_command(subparser
):
99 add_command(subparser
, 'branch', 'create a branch', cmd_branch
)
102 def add_browse_command(subparser
):
103 add_command(subparser
, 'browse', 'browse repository', cmd_browse
)
106 def add_clone_command(subparser
):
107 add_command(subparser
, 'clone', 'clone repository', cmd_clone
)
110 def add_config_command(subparser
):
111 add_command(subparser
, 'config', 'edit configuration', cmd_config
)
114 def add_dag_command(subparser
):
115 parser
= add_command(subparser
, 'dag', 'start git-dag', cmd_dag
)
116 parser
.add_argument('-c', '--count', metavar
='<count>',
117 type=int, default
=1000,
118 help='number of commits to display')
119 parser
.add_argument('--all', action
='store_true', dest
='show_all',
120 help='visualize all branches', default
=False)
121 parser
.add_argument('args', nargs
='*', metavar
='<args>',
122 help='git log arguments')
125 def add_diff_command(subparser
):
126 parser
= add_command(subparser
, 'diff', 'view diffs', cmd_diff
)
127 parser
.add_argument('args', nargs
='*', metavar
='<args>',
128 help='git diff arguments')
131 def add_fetch_command(subparser
):
132 add_command(subparser
, 'fetch', 'fetch remotes', cmd_fetch
)
135 def add_find_command(subparser
):
136 parser
= add_command(subparser
, 'find', 'find files', cmd_find
)
137 parser
.add_argument('paths', nargs
='*', metavar
='<path>',
138 help='filter by path')
141 def add_grep_command(subparser
):
142 parser
= add_command(subparser
, 'grep', 'grep source', cmd_grep
)
143 parser
.add_argument('args', nargs
='*', metavar
='<args>',
144 help='git grep arguments')
147 def add_merge_command(subparser
):
148 parser
= add_command(subparser
, 'merge', 'merge branches', cmd_merge
)
149 parser
.add_argument('ref', nargs
='?', metavar
='<ref>',
150 help='branch, tag, or commit to merge')
153 def add_pull_command(subparser
):
154 parser
= add_command(subparser
, 'pull', 'pull remote branches', cmd_pull
)
155 parser
.add_argument('--rebase', default
=False, action
='store_true',
156 help='rebase local branch when pulling')
159 def add_push_command(subparser
):
160 add_command(subparser
, 'push', 'push remote branches', cmd_push
)
163 def add_rebase_command(subparser
):
164 parser
= add_command(subparser
, 'rebase', 'interactive rebase', cmd_rebase
)
165 parser
.add_argument('-v', '--verbose', default
=False, action
='store_true',
166 help='display a diffstat of what changed upstream')
167 parser
.add_argument('-q', '--quiet', default
=False, action
='store_true',
168 help='be quiet. implies --no-stat')
169 parser
.add_argument('-i', '--interactive', default
=True,
170 action
='store_true', help=argparse
.SUPPRESS
)
171 parser
.add_argument('--autostash', default
=False, action
='store_true',
172 help='automatically stash/stash pop before and after')
173 parser
.add_argument('--fork-point', default
=False, action
='store_true',
174 help="use 'merge-base --fork-point' to refine upstream")
175 parser
.add_argument('--onto', default
=None, metavar
='<newbase>',
176 help='rebase onto given branch instead of upstream')
177 parser
.add_argument('-p', '--preserve-merges',
178 default
=False, action
='store_true',
179 help='try to recreate merges instead of ignoring them')
180 parser
.add_argument('-s', '--strategy', default
=None, metavar
='<strategy>',
181 help='use the given merge strategy')
182 parser
.add_argument('--no-ff', default
=False, action
='store_true',
183 help='cherry-pick all commits, even if unchanged')
184 parser
.add_argument('-m', '--merge', default
=False, action
='store_true',
185 help='use merging strategies to rebase')
186 parser
.add_argument('-x', '--exec', default
=None,
187 help='add exec lines after each commit of '
189 parser
.add_argument('-k', '--keep-empty', default
=False,
191 help='preserve empty commits during rebase')
192 parser
.add_argument('-f', '--force-rebase', default
=False,
194 help='force rebase even if branch is up to date')
195 parser
.add_argument('-X', '--strategy-option', default
=None,
197 help='pass the argument through to the merge strategy')
198 parser
.add_argument('--stat', default
=False, action
='store_true',
199 help='display a diffstat of what changed upstream')
200 parser
.add_argument('-n', '--no-stat', default
=False, action
='store_true',
201 help='do not show diffstat of what changed upstream')
202 parser
.add_argument('--verify', default
=False, action
='store_true',
203 help='allow pre-rebase hook to run')
204 parser
.add_argument('--rerere-autoupdate',
205 default
=False, action
='store_true',
206 help='allow rerere to update index with '
207 'resolved conflicts')
208 parser
.add_argument('--root', default
=False, action
='store_true',
209 help='rebase all reachable commits up to the root(s)')
210 parser
.add_argument('--autosquash', default
=True, action
='store_true',
211 help='move commits that begin with '
212 'squash!/fixup! under -i')
213 parser
.add_argument('--no-autosquash', default
=True, action
='store_false',
215 help='do not move commits that begin with '
216 'squash!/fixup! under -i')
217 parser
.add_argument('--committer-date-is-author-date',
218 default
=False, action
='store_true',
219 help="passed to 'git am' by 'git rebase'")
220 parser
.add_argument('--ignore-date', default
=False, action
='store_true',
221 help="passed to 'git am' by 'git rebase'")
222 parser
.add_argument('--whitespace', default
=False, action
='store_true',
223 help="passed to 'git apply' by 'git rebase'")
224 parser
.add_argument('--ignore-whitespace', default
=False,
226 help="passed to 'git apply' by 'git rebase'")
227 parser
.add_argument('-C', dest
='context_lines', default
=None, metavar
='<n>',
228 help="passed to 'git apply' by 'git rebase'")
230 actions
= parser
.add_argument_group('actions')
231 actions
.add_argument('--continue', default
=False, action
='store_true',
233 actions
.add_argument('--abort', default
=False, action
='store_true',
234 help='abort and check out the original branch')
235 actions
.add_argument('--skip', default
=False, action
='store_true',
236 help='skip current patch and continue')
237 actions
.add_argument('--edit-todo', default
=False, action
='store_true',
238 help='edit the todo list during an interactive rebase')
240 parser
.add_argument('upstream', nargs
='?', default
=None,
241 metavar
='<upstream>',
242 help='the upstream configured in branch.<name>.remote '
243 'and branch.<name>.merge options will be used '
244 'when <upstream> is omitted; see git-rebase(1) '
245 'for details. If you are currently not on any '
246 'branch or if the current branch does not have '
247 'a configured upstream, the rebase will abort')
248 parser
.add_argument('branch', nargs
='?', default
=None, metavar
='<branch>',
249 help='git rebase will perform an automatic '
250 '"git checkout <branch>" before doing anything '
251 'else when <branch> is specified')
254 def add_recent_command(subparser
):
255 add_command(subparser
, 'recent', 'edit recent files', cmd_recent
)
258 def add_remote_command(subparser
):
259 add_command(subparser
, 'remote', 'edit remotes', cmd_remote
)
262 def add_search_command(subparser
):
263 add_command(subparser
, 'search', 'search commits', cmd_search
)
266 def add_stash_command(subparser
):
267 add_command(subparser
, 'stash', 'stash and unstash changes', cmd_stash
)
270 def add_tag_command(subparser
):
271 parser
= add_command(subparser
, 'tag', 'create tags', cmd_tag
)
272 parser
.add_argument('name', metavar
='<name>', nargs
='?', default
=None,
274 parser
.add_argument('ref', metavar
='<ref>', nargs
='?', default
=None,
275 help='commit to tag')
276 parser
.add_argument('-s', '--sign', default
=False, action
='store_true',
277 help='annotated and GPG-signed tag')
280 def add_version_command(subparser
):
281 parser
= add_command(
282 subparser
, 'version', 'print the version', cmd_version
)
283 parser
.add_argument('--brief', action
='store_true', default
=False,
284 help='print the version number only')
285 parser
.add_argument('--build', action
='store_true', default
=False,
286 help='print the build version')
291 from .widgets
.main
import MainView
292 status_filter
= args
.status_filter
294 status_filter
= core
.abspath(status_filter
)
296 context
= app
.application_init(args
)
298 context
.timer
.start('view')
299 view
= MainView(context
, settings
=args
.settings
)
301 cmds
.do(cmds
.AmendMode
, context
, amend
=True)
304 view
.set_filter(core
.relpath(status_filter
))
306 context
.timer
.stop('view')
308 context
.timer
.display('view')
310 return app
.application_run(
311 context
, view
, start
=start_cola
, stop
=app
.default_stop
)
314 def start_cola(context
, view
):
315 app
.default_start(context
, view
)
320 from .widgets
import about
321 context
= app
.application_init(args
)
322 view
= about
.about_dialog(context
)
323 return app
.application_start(context
, view
)
327 from .widgets
.patch
import new_apply_patches
328 context
= app
.application_init(args
)
329 view
= new_apply_patches(context
, patches
=args
.patches
)
330 return app
.application_start(context
, view
)
333 def cmd_archive(args
):
334 from .widgets
import archive
335 context
= app
.application_init(args
, update
=True)
337 args
.ref
= context
.model
.currentbranch
338 view
= archive
.Archive(context
, args
.ref
)
339 return app
.application_start(context
, view
)
342 def cmd_branch(args
):
343 from .widgets
.createbranch
import create_new_branch
344 context
= app
.application_init(args
, update
=True)
345 view
= create_new_branch(context
, settings
=args
.settings
)
346 return app
.application_start(context
, view
)
349 def cmd_browse(args
):
350 from .widgets
.browse
import worktree_browser
351 context
= app
.application_init(args
)
352 view
= worktree_browser(
353 context
, show
=False, update
=False, settings
=args
.settings
)
354 return app
.application_start(context
, view
)
358 from .widgets
import clone
359 context
= app
.application_init(args
)
360 view
= clone
.clone(context
, settings
=args
.settings
)
361 context
.set_view(view
)
362 result
= 0 if view
.exec_() == view
.Accepted
else 1
363 app
.default_stop(context
, view
)
367 def cmd_config(args
):
368 from .widgets
.prefs
import preferences
369 context
= app
.application_init(args
)
370 view
= preferences(context
)
371 return app
.application_start(context
, view
)
375 from .widgets
import dag
376 context
= app
.application_init(args
)
377 # cola.main() uses parse_args(), unlike dag.main() which uses
378 # parse_known_args(), thus we aren't able to automatically forward
379 # all unknown arguments. Special-case support for "--all" since it's
380 # used by the history viewer command on Windows.
382 args
.args
.insert(0, '--all')
383 view
= dag
.git_dag(context
, args
=args
, settings
=args
.settings
, show
=False)
384 return app
.application_start(context
, view
)
388 from .difftool
import diff_expression
389 context
= app
.application_init(args
)
390 expr
= core
.list2cmdline(args
.args
)
391 view
= diff_expression(context
, None, expr
, create_widget
=True)
392 return app
.application_start(context
, view
)
396 # TODO: the calls to update_status() can be done asynchronously
397 # by hooking into the message_updated notification.
398 from .widgets
import remote
399 context
= app
.application_init(args
)
400 context
.model
.update_status()
401 view
= remote
.fetch(context
)
402 return app
.application_start(context
, view
)
406 from .widgets
import finder
407 context
= app
.application_init(args
)
408 paths
= core
.list2cmdline(args
.paths
)
409 view
= finder
.finder(context
, paths
=paths
)
410 return app
.application_start(context
, view
)
414 from .widgets
import grep
415 context
= app
.application_init(args
)
416 text
= core
.list2cmdline(args
.args
)
417 view
= grep
.new_grep(context
, text
=text
, parent
=None)
418 return app
.application_start(context
, view
)
422 from .widgets
.merge
import Merge
423 context
= app
.application_init(args
, update
=True)
424 view
= Merge(context
, parent
=None, ref
=args
.ref
)
425 return app
.application_start(context
, view
)
428 def cmd_version(args
):
429 from . import version
430 version
.print_version(brief
=args
.brief
, build
=args
.build
)
435 from .widgets
import remote
436 context
= app
.application_init(args
, update
=True)
437 view
= remote
.pull(context
)
439 view
.set_rebase(True)
440 return app
.application_start(context
, view
)
444 from .widgets
import remote
445 context
= app
.application_init(args
, update
=True)
446 view
= remote
.push(context
)
447 return app
.application_start(context
, view
)
450 def cmd_rebase(args
):
452 'verbose': args
.verbose
,
454 'autostash': args
.autostash
,
455 'fork_point': args
.fork_point
,
457 'preserve_merges': args
.preserve_merges
,
458 'strategy': args
.strategy
,
461 'exec': getattr(args
, 'exec', None), # python keyword
462 'keep_empty': args
.keep_empty
,
463 'force_rebase': args
.force_rebase
,
464 'strategy_option': args
.strategy_option
,
466 'no_stat': args
.no_stat
,
467 'verify': args
.verify
,
468 'rerere_autoupdate': args
.rerere_autoupdate
,
470 'autosquash': args
.autosquash
,
471 'committer_date_is_author_date': args
.committer_date_is_author_date
,
472 'ignore_date': args
.ignore_date
,
473 'whitespace': args
.whitespace
,
474 'ignore_whitespace': args
.ignore_whitespace
,
475 'C': args
.context_lines
,
476 'continue': getattr(args
, 'continue', False), # python keyword
479 'edit_todo': args
.edit_todo
,
480 'upstream': args
.upstream
,
481 'branch': args
.branch
,
483 context
= app
.application_init(args
)
484 status
, _
, _
= cmds
.do(cmds
.Rebase
, context
, **kwargs
)
488 def cmd_recent(args
):
489 from .widgets
import recent
490 context
= app
.application_init(args
)
491 view
= recent
.browse_recent_files(context
)
492 return app
.application_start(context
, view
)
495 def cmd_remote(args
):
496 from .widgets
import editremotes
497 context
= app
.application_init(args
)
498 view
= editremotes
.editor(context
, run
=False)
499 return app
.application_start(context
, view
)
502 def cmd_search(args
):
503 from .widgets
.search
import search
504 context
= app
.application_init(args
)
505 view
= search(context
)
506 return app
.application_start(context
, view
)
510 from .widgets
import stash
511 context
= app
.application_init(args
)
512 view
= stash
.view(context
, show
=False)
513 return app
.application_start(context
, view
)
517 from .widgets
.createtag
import new_create_tag
518 context
= app
.application_init(args
)
519 view
= new_create_tag(
520 context
, name
=args
.name
, ref
=args
.ref
, sign
=args
.sign
,
521 settings
=args
.settings
)
522 return app
.application_start(context
, view
)
525 # Windows shortcut launch features:
526 def shortcut_launch():
527 """Launch from a shortcut
529 Prompt for the repository by default.
534 argv
= ['cola', '--prompt']
535 return app
.winmain(main
, argv
)