gitbetter.gitbetter
1import os 2from datetime import datetime 3 4from argshell import ArgShell, Namespace, with_parser 5from noiftimer import Timer 6from pathier import Pathier 7 8from gitbetter import Git, parsers 9 10 11class GitArgShell(ArgShell): 12 git_header = "Built in Git commands (type '{command} -h' or '{command} --help'):" 13 convenience_header = "Convenience commands (type 'help {command}'):" 14 15 def do_help(self, arg): 16 """List available commands with "help" or detailed help with "help cmd". 17 If using 'help cmd' and the cmd is decorated with a parser, the parser help will also be printed. 18 """ 19 if arg: 20 # XXX check arg syntax 21 try: 22 func = getattr(self, "help_" + arg) 23 except AttributeError: 24 try: 25 func = getattr(self, "do_" + arg) 26 doc = func.__doc__ 27 if doc: 28 self.stdout.write("%s\n" % str(doc)) 29 # =========================Modification start========================= 30 # Check for decorator and call decorated function with "--help" 31 if hasattr(func, "__wrapped__"): 32 self.stdout.write( 33 f"Parser help for {func.__name__.replace('do_','')}:\n" 34 ) 35 func("--help") 36 if doc or hasattr(func, "__wrapped__"): 37 return 38 # |=========================Modification stop=========================| 39 except AttributeError: 40 pass 41 self.stdout.write("%s\n" % str(self.nohelp % (arg,))) 42 return 43 func() 44 else: 45 names = self.get_names() 46 cmds_doc = [] 47 cmds_undoc = [] 48 topics = set() 49 for name in names: 50 if name[:5] == "help_": 51 topics.add(name[5:]) 52 names.sort() 53 # There can be duplicates if routines overridden 54 prevname = "" 55 for name in names: 56 if name[:3] == "do_": 57 if name == prevname: 58 continue 59 prevname = name 60 cmd = name[3:] 61 if cmd in topics: 62 cmds_doc.append(cmd) 63 topics.remove(cmd) 64 elif getattr(self, name).__doc__: 65 cmds_doc.append(cmd) 66 else: 67 cmds_undoc.append(cmd) 68 # |========================Modification Start========================| 69 content = Pathier(__file__).read_text() 70 convenience_index = content.rfind("=Convenience=") 71 git_commands = [] 72 convenience_commands = [] 73 for cmd in cmds_doc: 74 if content.find(f"do_{cmd}") < convenience_index: 75 git_commands.append(cmd) 76 else: 77 convenience_commands.append(cmd) 78 self.stdout.write("%s\n" % str(self.doc_leader)) 79 self.print_topics(self.git_header, git_commands, 15, 80) 80 self.print_topics(self.convenience_header, convenience_commands, 15, 80) 81 # |========================Modification Stop========================| 82 self.print_topics(self.misc_header, sorted(topics), 15, 80) 83 self.print_topics(self.undoc_header, cmds_undoc, 15, 80) 84 85 86class GitBetter(GitArgShell): 87 """GitBetter Shell.""" 88 89 execute_in_terminal_if_unrecognized = True 90 git = Git() 91 intro = "Starting gitbetter...\nEnter 'help' or '?' for command help." 92 prompt = f"gitbetter::{Pathier.cwd()}>" 93 94 @property 95 def unrecognized_command_behavior_status(self): 96 return f"Unrecognized command behavior: {('Execute in shell with os.system()' if self.execute_in_terminal_if_unrecognized else 'Print unknown syntax error')}" 97 98 def default(self, line: str): 99 if self.execute_in_terminal_if_unrecognized: 100 os.system(line) 101 else: 102 super().default(line) 103 104 def do_cd(self, path: str): 105 """Change current working directory to `path`.""" 106 os.chdir(path) 107 self.prompt = f"gitbetter::{Pathier.cwd()}>" 108 109 def do_help(self, arg: str): 110 """List available commands with "help" or detailed help with "help cmd".""" 111 super().do_help(arg) 112 if not arg: 113 print(self.unrecognized_command_behavior_status) 114 if self.execute_in_terminal_if_unrecognized: 115 print( 116 "^Essentially makes this shell function as a super-shell of whatever shell you launched gitbetter from.^" 117 ) 118 print() 119 120 def do_toggle_unrecognized_command_behavior(self, arg: str): 121 """Toggle whether the shell will attempt to execute unrecognized commands as system commands in the terminal. 122 When on (the default), `GitBetter` will treat unrecognized commands as if you added the `sys` command in front of the input, i.e. `os.system(your_input)`. 123 When off, an `unknown syntax` message will be printed and no commands will be executed. 124 """ 125 self.execute_in_terminal_if_unrecognized = ( 126 not self.execute_in_terminal_if_unrecognized 127 ) 128 print(self.unrecognized_command_behavior_status) 129 130 # Seat |================================================Core================================================| 131 132 def do_git(self, args: str): 133 """Directly execute `git {args}`. 134 135 i.e. You can still do everything directly invoking git can do.""" 136 self.git.git(args) 137 138 # Seat 139 140 def do_add(self, args: str): 141 """>>> git add {args}""" 142 self.git.add(args) 143 144 def do_am(self, args: str): 145 """>>> git am {args}""" 146 self.git.am(args) 147 148 def do_annotate(self, args: str): 149 """>>> git annotate {args}""" 150 self.git.annotate(args) 151 152 def do_archive(self, args: str): 153 """>>> git archive {args}""" 154 self.git.archive(args) 155 156 def do_bisect(self, args: str): 157 """>>> git bisect {args}""" 158 self.git.bisect(args) 159 160 def do_blame(self, args: str): 161 """>>> git blame {args}""" 162 self.git.blame(args) 163 164 def do_branch(self, args: str): 165 """>>> git branch {args}""" 166 self.git.branch(args) 167 168 def do_bugreport(self, args: str): 169 """>>> git bugreport {args}""" 170 self.git.bugreport(args) 171 172 def do_bundle(self, args: str): 173 """>>> git bundle {args}""" 174 self.git.bundle(args) 175 176 def do_checkout(self, args: str): 177 """>>> git checkout {args}""" 178 self.git.checkout(args) 179 180 def do_cherry_pick(self, args: str): 181 """>>> git cherry_pick {args}""" 182 self.git.cherry_pick(args) 183 184 def do_citool(self, args: str): 185 """>>> git citool {args}""" 186 self.git.citool(args) 187 188 def do_clean(self, args: str): 189 """>>> git clean {args}""" 190 self.git.clean(args) 191 192 def do_clone(self, args: str): 193 """>>> git clone {args}""" 194 self.git.clone(args) 195 196 def do_commit(self, args: str): 197 """>>> git commit {args}""" 198 self.git.commit(args) 199 200 def do_config(self, args: str): 201 """>>> git config {args}""" 202 self.git.config(args) 203 204 def do_count_objects(self, args: str): 205 """>>> git count_objects {args}""" 206 self.git.count_objects(args) 207 208 def do_describe(self, args: str): 209 """>>> git describe {args}""" 210 self.git.describe(args) 211 212 def do_diagnose(self, args: str): 213 """>>> git diagnose {args}""" 214 self.git.diagnose(args) 215 216 def do_diff(self, args: str): 217 """>>> git diff {args}""" 218 self.git.diff(args) 219 220 def do_difftool(self, args: str): 221 """>>> git difftool {args}""" 222 self.git.difftool(args) 223 224 def do_fast_export(self, args: str): 225 """>>> git fast_export {args}""" 226 self.git.fast_export(args) 227 228 def do_fast_import(self, args: str): 229 """>>> git fast_import {args}""" 230 self.git.fast_import(args) 231 232 def do_fetch(self, args: str): 233 """>>> git fetch {args}""" 234 self.git.fetch(args) 235 236 def do_filter_branch(self, args: str): 237 """>>> git filter_branch {args}""" 238 self.git.filter_branch(args) 239 240 def do_format_patch(self, args: str): 241 """>>> git format_patch {args}""" 242 self.git.format_patch(args) 243 244 def do_fsck(self, args: str): 245 """>>> git fsck {args}""" 246 self.git.fsck(args) 247 248 def do_gc(self, args: str): 249 """>>> git gc {args}""" 250 self.git.gc(args) 251 252 def do_gitk(self, args: str): 253 """>>> git gitk {args}""" 254 self.git.gitk(args) 255 256 def do_gitweb(self, args: str): 257 """>>> git gitweb {args}""" 258 self.git.gitweb(args) 259 260 def do_grep(self, args: str): 261 """>>> git grep {args}""" 262 self.git.grep(args) 263 264 def do_gui(self, args: str): 265 """>>> git gui {args}""" 266 self.git.gui(args) 267 268 def do_init(self, args: str): 269 """>>> git init {args}""" 270 self.git.init(args) 271 272 def do_instaweb(self, args: str): 273 """>>> git instaweb {args}""" 274 self.git.instaweb(args) 275 276 def do_log(self, args: str): 277 """>>> git log {args}""" 278 self.git.log(args) 279 280 def do_maintenance(self, args: str): 281 """>>> git maintenance {args}""" 282 self.git.maintenance(args) 283 284 def do_merge(self, args: str): 285 """>>> git merge {args}""" 286 self.git.merge(args) 287 288 def do_merge_tree(self, args: str): 289 """>>> git merge_tree {args}""" 290 self.git.merge_tree(args) 291 292 def do_mergetool(self, args: str): 293 """>>> git mergetool {args}""" 294 self.git.mergetool(args) 295 296 def do_mv(self, args: str): 297 """>>> git mv {args}""" 298 self.git.mv(args) 299 300 def do_notes(self, args: str): 301 """>>> git notes {args}""" 302 self.git.notes(args) 303 304 def do_pack_refs(self, args: str): 305 """>>> git pack_refs {args}""" 306 self.git.pack_refs(args) 307 308 def do_prune(self, args: str): 309 """>>> git prune {args}""" 310 self.git.prune(args) 311 312 def do_pull(self, args: str): 313 """>>> git pull {args}""" 314 self.git.pull(args) 315 316 def do_push(self, args: str): 317 """>>> git push {args}""" 318 self.git.push(args) 319 320 def do_range_diff(self, args: str): 321 """>>> git range_diff {args}""" 322 self.git.range_diff(args) 323 324 def do_rebase(self, args: str): 325 """>>> git rebase {args}""" 326 self.git.rebase(args) 327 328 def do_reflog(self, args: str): 329 """>>> git reflog {args}""" 330 self.git.reflog(args) 331 332 def do_remote(self, args: str): 333 """>>> git remote {args}""" 334 self.git.remote(args) 335 336 def do_repack(self, args: str): 337 """>>> git repack {args}""" 338 self.git.repack(args) 339 340 def do_replace(self, args: str): 341 """>>> git replace {args}""" 342 self.git.replace(args) 343 344 def do_request_pull(self, args: str): 345 """>>> git request_pull {args}""" 346 self.git.request_pull(args) 347 348 def do_rerere(self, args: str): 349 """>>> git rerere {args}""" 350 self.git.rerere(args) 351 352 def do_reset(self, args: str): 353 """>>> git reset {args}""" 354 self.git.reset(args) 355 356 def do_restore(self, args: str): 357 """>>> git restore {args}""" 358 self.git.restore(args) 359 360 def do_revert(self, args: str): 361 """>>> git revert {args}""" 362 self.git.revert(args) 363 364 def do_rm(self, args: str): 365 """>>> git rm {args}""" 366 self.git.rm(args) 367 368 def do_scalar(self, args: str): 369 """>>> git scalar {args}""" 370 self.git.scalar(args) 371 372 def do_shortlog(self, args: str): 373 """>>> git shortlog {args}""" 374 self.git.shortlog(args) 375 376 def do_show(self, args: str): 377 """>>> git show {args}""" 378 self.git.show(args) 379 380 def do_show_branch(self, args: str): 381 """>>> git show_branch {args}""" 382 self.git.show_branch(args) 383 384 def do_sparse_checkout(self, args: str): 385 """>>> git sparse_checkout {args}""" 386 self.git.sparse_checkout(args) 387 388 def do_stash(self, args: str): 389 """>>> git stash {args}""" 390 self.git.stash(args) 391 392 def do_status(self, args: str): 393 """>>> git status {args}""" 394 self.git.status(args) 395 396 def do_submodule(self, args: str): 397 """>>> git submodule {args}""" 398 self.git.submodule(args) 399 400 def do_switch(self, args: str): 401 """>>> git switch {args}""" 402 self.git.switch(args) 403 404 def do_tag(self, args: str): 405 """>>> git tag {args}""" 406 self.git.tag(args) 407 408 def do_verify_commit(self, args: str): 409 """>>> git verify_commit {args}""" 410 self.git.verify_commit(args) 411 412 def do_verify_tag(self, args: str): 413 """>>> git verify_tag {args}""" 414 self.git.verify_tag(args) 415 416 def do_version(self, args: str): 417 """>>> git version {args}""" 418 self.git.version(args) 419 420 def do_whatchanged(self, args: str): 421 """>>> git whatchanged {args}""" 422 self.git.whatchanged(args) 423 424 def do_worktree(self, args: str): 425 """>>> git worktree {args}""" 426 self.git.worktree(args) 427 428 # Seat |==================================Convenience==================================| 429 430 def do_add_url(self, url: str): 431 """Add remote origin url for repo and push repo. 432 >>> git remote add origin {url} 433 >>> git push -u origin main""" 434 self.git.add_remote_url(url) 435 self.git.push("-u origin main") 436 437 @with_parser(parsers.add_files_parser) 438 def do_amend(self, args: Namespace): 439 """Stage files and add to previous commit.""" 440 self.git.amend(args.files) 441 442 def do_branches(self, _: str): 443 """Show local and remote branches. 444 >>> git branch -vva""" 445 self.git.list_branches() 446 447 def do_commitall(self, message: str): 448 """Stage and commit all modified and untracked files with this message. 449 >>> git add . 450 >>> git commit -m \"{message}\" """ 451 message = message.strip('"').replace('"', "'") 452 self.git.add_all() 453 self.git.commit(f'-m "{message}"') 454 455 @with_parser(parsers.delete_branch_parser) 456 def do_delete_branch(self, args: Namespace): 457 """Delete branch.""" 458 self.git.delete_branch(args.branch, not args.remote) 459 460 def do_delete_gh_repo(self, _: str): 461 """Delete this repo from GitHub. 462 463 GitHub CLI must be installed and configured. 464 465 May require you to reauthorize and rerun command.""" 466 self.git.delete_remote() 467 468 def do_dob(self, _: str): 469 """Date of this repo's first commit.""" 470 dob = self.git.dob 471 elapsed = Timer.format_time((datetime.now() - dob).total_seconds()) 472 print(f"{dob:%m/%d/%Y}|{elapsed} ago") 473 474 def do_ignore(self, patterns: str): 475 """Add the list of patterns/file names to `.gitignore` and commit with the message `chore: add to gitignore`.""" 476 self.git.ignore(patterns.split()) 477 self.git.commit_files([".gitignore"], "chore: add to gitignore") 478 479 @with_parser(parsers.add_files_parser) 480 def do_initcommit(self, args: Namespace): 481 """Stage and commit all files with message "Initial Commit".""" 482 self.git.initcommit(args.files) 483 484 def do_loggy(self, _: str): 485 """>>> git --oneline --name-only --abbrev-commit --graph""" 486 self.git.loggy() 487 488 def do_make_private(self, _: str): 489 """Make the GitHub remote for this repo private. 490 491 This repo must exist and GitHub CLI must be installed and configured.""" 492 self.git.make_private() 493 494 def do_make_public(self, _: str): 495 """Make the GitHub remote for this repo public. 496 497 This repo must exist and GitHub CLI must be installed and configured.""" 498 self.git.make_public() 499 500 def do_new_branch(self, name: str): 501 """Create and switch to a new branch with this `name`.""" 502 self.git.create_new_branch(name) 503 504 @with_parser(parsers.new_remote_parser) 505 def do_new_gh_remote(self, args: Namespace): 506 """Create a remote GitHub repository for this repo. 507 508 GitHub CLI must be installed and configured for this to work.""" 509 self.git.create_remote_from_cwd(args.public) 510 511 def do_new_repo(self, _: str): 512 """Create a new git repo in this directory.""" 513 self.git.new_repo() 514 515 def do_push_new(self, _: str): 516 """Push current branch to origin with `-u` flag. 517 >>> git push -u origin {this_branch}""" 518 self.git.push_new_branch(self.git.current_branch) 519 520 def do_undo(self, _: str): 521 """Undo all uncommitted changes. 522 >>> git checkout .""" 523 self.git.undo() 524 525 @with_parser(parsers.add_files_parser) 526 def do_untrack(self, args: Namespace): 527 """Untrack files matching provided path/pattern list. 528 529 For each path/pattern, equivalent to: 530 >>> git rm --cached {path}""" 531 self.git.untrack(*args.files) 532 533 @with_parser(parsers.rename_file_parser) 534 def do_rename_file(self, args: Namespace): 535 """Renames a file. 536 After renaming the file, the renaming change is staged for commit.""" 537 self.git.rename_file(args.file, args.new_name) 538 539 540def main(): 541 GitBetter().cmdloop() 542 543 544if __name__ == "__main__": 545 main()
12class GitArgShell(ArgShell): 13 git_header = "Built in Git commands (type '{command} -h' or '{command} --help'):" 14 convenience_header = "Convenience commands (type 'help {command}'):" 15 16 def do_help(self, arg): 17 """List available commands with "help" or detailed help with "help cmd". 18 If using 'help cmd' and the cmd is decorated with a parser, the parser help will also be printed. 19 """ 20 if arg: 21 # XXX check arg syntax 22 try: 23 func = getattr(self, "help_" + arg) 24 except AttributeError: 25 try: 26 func = getattr(self, "do_" + arg) 27 doc = func.__doc__ 28 if doc: 29 self.stdout.write("%s\n" % str(doc)) 30 # =========================Modification start========================= 31 # Check for decorator and call decorated function with "--help" 32 if hasattr(func, "__wrapped__"): 33 self.stdout.write( 34 f"Parser help for {func.__name__.replace('do_','')}:\n" 35 ) 36 func("--help") 37 if doc or hasattr(func, "__wrapped__"): 38 return 39 # |=========================Modification stop=========================| 40 except AttributeError: 41 pass 42 self.stdout.write("%s\n" % str(self.nohelp % (arg,))) 43 return 44 func() 45 else: 46 names = self.get_names() 47 cmds_doc = [] 48 cmds_undoc = [] 49 topics = set() 50 for name in names: 51 if name[:5] == "help_": 52 topics.add(name[5:]) 53 names.sort() 54 # There can be duplicates if routines overridden 55 prevname = "" 56 for name in names: 57 if name[:3] == "do_": 58 if name == prevname: 59 continue 60 prevname = name 61 cmd = name[3:] 62 if cmd in topics: 63 cmds_doc.append(cmd) 64 topics.remove(cmd) 65 elif getattr(self, name).__doc__: 66 cmds_doc.append(cmd) 67 else: 68 cmds_undoc.append(cmd) 69 # |========================Modification Start========================| 70 content = Pathier(__file__).read_text() 71 convenience_index = content.rfind("=Convenience=") 72 git_commands = [] 73 convenience_commands = [] 74 for cmd in cmds_doc: 75 if content.find(f"do_{cmd}") < convenience_index: 76 git_commands.append(cmd) 77 else: 78 convenience_commands.append(cmd) 79 self.stdout.write("%s\n" % str(self.doc_leader)) 80 self.print_topics(self.git_header, git_commands, 15, 80) 81 self.print_topics(self.convenience_header, convenience_commands, 15, 80) 82 # |========================Modification Stop========================| 83 self.print_topics(self.misc_header, sorted(topics), 15, 80) 84 self.print_topics(self.undoc_header, cmds_undoc, 15, 80)
Subclass this to create custom ArgShells.
16 def do_help(self, arg): 17 """List available commands with "help" or detailed help with "help cmd". 18 If using 'help cmd' and the cmd is decorated with a parser, the parser help will also be printed. 19 """ 20 if arg: 21 # XXX check arg syntax 22 try: 23 func = getattr(self, "help_" + arg) 24 except AttributeError: 25 try: 26 func = getattr(self, "do_" + arg) 27 doc = func.__doc__ 28 if doc: 29 self.stdout.write("%s\n" % str(doc)) 30 # =========================Modification start========================= 31 # Check for decorator and call decorated function with "--help" 32 if hasattr(func, "__wrapped__"): 33 self.stdout.write( 34 f"Parser help for {func.__name__.replace('do_','')}:\n" 35 ) 36 func("--help") 37 if doc or hasattr(func, "__wrapped__"): 38 return 39 # |=========================Modification stop=========================| 40 except AttributeError: 41 pass 42 self.stdout.write("%s\n" % str(self.nohelp % (arg,))) 43 return 44 func() 45 else: 46 names = self.get_names() 47 cmds_doc = [] 48 cmds_undoc = [] 49 topics = set() 50 for name in names: 51 if name[:5] == "help_": 52 topics.add(name[5:]) 53 names.sort() 54 # There can be duplicates if routines overridden 55 prevname = "" 56 for name in names: 57 if name[:3] == "do_": 58 if name == prevname: 59 continue 60 prevname = name 61 cmd = name[3:] 62 if cmd in topics: 63 cmds_doc.append(cmd) 64 topics.remove(cmd) 65 elif getattr(self, name).__doc__: 66 cmds_doc.append(cmd) 67 else: 68 cmds_undoc.append(cmd) 69 # |========================Modification Start========================| 70 content = Pathier(__file__).read_text() 71 convenience_index = content.rfind("=Convenience=") 72 git_commands = [] 73 convenience_commands = [] 74 for cmd in cmds_doc: 75 if content.find(f"do_{cmd}") < convenience_index: 76 git_commands.append(cmd) 77 else: 78 convenience_commands.append(cmd) 79 self.stdout.write("%s\n" % str(self.doc_leader)) 80 self.print_topics(self.git_header, git_commands, 15, 80) 81 self.print_topics(self.convenience_header, convenience_commands, 15, 80) 82 # |========================Modification Stop========================| 83 self.print_topics(self.misc_header, sorted(topics), 15, 80) 84 self.print_topics(self.undoc_header, cmds_undoc, 15, 80)
List available commands with "help" or detailed help with "help cmd". If using 'help cmd' and the cmd is decorated with a parser, the parser help will also be printed.
Inherited Members
- cmd.Cmd
- Cmd
- precmd
- postcmd
- preloop
- postloop
- parseline
- onecmd
- default
- completedefault
- completenames
- complete
- get_names
- complete_help
- print_topics
- columnize
- argshell.argshell.ArgShell
- do_quit
- do_sys
- cmdloop
- emptyline
87class GitBetter(GitArgShell): 88 """GitBetter Shell.""" 89 90 execute_in_terminal_if_unrecognized = True 91 git = Git() 92 intro = "Starting gitbetter...\nEnter 'help' or '?' for command help." 93 prompt = f"gitbetter::{Pathier.cwd()}>" 94 95 @property 96 def unrecognized_command_behavior_status(self): 97 return f"Unrecognized command behavior: {('Execute in shell with os.system()' if self.execute_in_terminal_if_unrecognized else 'Print unknown syntax error')}" 98 99 def default(self, line: str): 100 if self.execute_in_terminal_if_unrecognized: 101 os.system(line) 102 else: 103 super().default(line) 104 105 def do_cd(self, path: str): 106 """Change current working directory to `path`.""" 107 os.chdir(path) 108 self.prompt = f"gitbetter::{Pathier.cwd()}>" 109 110 def do_help(self, arg: str): 111 """List available commands with "help" or detailed help with "help cmd".""" 112 super().do_help(arg) 113 if not arg: 114 print(self.unrecognized_command_behavior_status) 115 if self.execute_in_terminal_if_unrecognized: 116 print( 117 "^Essentially makes this shell function as a super-shell of whatever shell you launched gitbetter from.^" 118 ) 119 print() 120 121 def do_toggle_unrecognized_command_behavior(self, arg: str): 122 """Toggle whether the shell will attempt to execute unrecognized commands as system commands in the terminal. 123 When on (the default), `GitBetter` will treat unrecognized commands as if you added the `sys` command in front of the input, i.e. `os.system(your_input)`. 124 When off, an `unknown syntax` message will be printed and no commands will be executed. 125 """ 126 self.execute_in_terminal_if_unrecognized = ( 127 not self.execute_in_terminal_if_unrecognized 128 ) 129 print(self.unrecognized_command_behavior_status) 130 131 # Seat |================================================Core================================================| 132 133 def do_git(self, args: str): 134 """Directly execute `git {args}`. 135 136 i.e. You can still do everything directly invoking git can do.""" 137 self.git.git(args) 138 139 # Seat 140 141 def do_add(self, args: str): 142 """>>> git add {args}""" 143 self.git.add(args) 144 145 def do_am(self, args: str): 146 """>>> git am {args}""" 147 self.git.am(args) 148 149 def do_annotate(self, args: str): 150 """>>> git annotate {args}""" 151 self.git.annotate(args) 152 153 def do_archive(self, args: str): 154 """>>> git archive {args}""" 155 self.git.archive(args) 156 157 def do_bisect(self, args: str): 158 """>>> git bisect {args}""" 159 self.git.bisect(args) 160 161 def do_blame(self, args: str): 162 """>>> git blame {args}""" 163 self.git.blame(args) 164 165 def do_branch(self, args: str): 166 """>>> git branch {args}""" 167 self.git.branch(args) 168 169 def do_bugreport(self, args: str): 170 """>>> git bugreport {args}""" 171 self.git.bugreport(args) 172 173 def do_bundle(self, args: str): 174 """>>> git bundle {args}""" 175 self.git.bundle(args) 176 177 def do_checkout(self, args: str): 178 """>>> git checkout {args}""" 179 self.git.checkout(args) 180 181 def do_cherry_pick(self, args: str): 182 """>>> git cherry_pick {args}""" 183 self.git.cherry_pick(args) 184 185 def do_citool(self, args: str): 186 """>>> git citool {args}""" 187 self.git.citool(args) 188 189 def do_clean(self, args: str): 190 """>>> git clean {args}""" 191 self.git.clean(args) 192 193 def do_clone(self, args: str): 194 """>>> git clone {args}""" 195 self.git.clone(args) 196 197 def do_commit(self, args: str): 198 """>>> git commit {args}""" 199 self.git.commit(args) 200 201 def do_config(self, args: str): 202 """>>> git config {args}""" 203 self.git.config(args) 204 205 def do_count_objects(self, args: str): 206 """>>> git count_objects {args}""" 207 self.git.count_objects(args) 208 209 def do_describe(self, args: str): 210 """>>> git describe {args}""" 211 self.git.describe(args) 212 213 def do_diagnose(self, args: str): 214 """>>> git diagnose {args}""" 215 self.git.diagnose(args) 216 217 def do_diff(self, args: str): 218 """>>> git diff {args}""" 219 self.git.diff(args) 220 221 def do_difftool(self, args: str): 222 """>>> git difftool {args}""" 223 self.git.difftool(args) 224 225 def do_fast_export(self, args: str): 226 """>>> git fast_export {args}""" 227 self.git.fast_export(args) 228 229 def do_fast_import(self, args: str): 230 """>>> git fast_import {args}""" 231 self.git.fast_import(args) 232 233 def do_fetch(self, args: str): 234 """>>> git fetch {args}""" 235 self.git.fetch(args) 236 237 def do_filter_branch(self, args: str): 238 """>>> git filter_branch {args}""" 239 self.git.filter_branch(args) 240 241 def do_format_patch(self, args: str): 242 """>>> git format_patch {args}""" 243 self.git.format_patch(args) 244 245 def do_fsck(self, args: str): 246 """>>> git fsck {args}""" 247 self.git.fsck(args) 248 249 def do_gc(self, args: str): 250 """>>> git gc {args}""" 251 self.git.gc(args) 252 253 def do_gitk(self, args: str): 254 """>>> git gitk {args}""" 255 self.git.gitk(args) 256 257 def do_gitweb(self, args: str): 258 """>>> git gitweb {args}""" 259 self.git.gitweb(args) 260 261 def do_grep(self, args: str): 262 """>>> git grep {args}""" 263 self.git.grep(args) 264 265 def do_gui(self, args: str): 266 """>>> git gui {args}""" 267 self.git.gui(args) 268 269 def do_init(self, args: str): 270 """>>> git init {args}""" 271 self.git.init(args) 272 273 def do_instaweb(self, args: str): 274 """>>> git instaweb {args}""" 275 self.git.instaweb(args) 276 277 def do_log(self, args: str): 278 """>>> git log {args}""" 279 self.git.log(args) 280 281 def do_maintenance(self, args: str): 282 """>>> git maintenance {args}""" 283 self.git.maintenance(args) 284 285 def do_merge(self, args: str): 286 """>>> git merge {args}""" 287 self.git.merge(args) 288 289 def do_merge_tree(self, args: str): 290 """>>> git merge_tree {args}""" 291 self.git.merge_tree(args) 292 293 def do_mergetool(self, args: str): 294 """>>> git mergetool {args}""" 295 self.git.mergetool(args) 296 297 def do_mv(self, args: str): 298 """>>> git mv {args}""" 299 self.git.mv(args) 300 301 def do_notes(self, args: str): 302 """>>> git notes {args}""" 303 self.git.notes(args) 304 305 def do_pack_refs(self, args: str): 306 """>>> git pack_refs {args}""" 307 self.git.pack_refs(args) 308 309 def do_prune(self, args: str): 310 """>>> git prune {args}""" 311 self.git.prune(args) 312 313 def do_pull(self, args: str): 314 """>>> git pull {args}""" 315 self.git.pull(args) 316 317 def do_push(self, args: str): 318 """>>> git push {args}""" 319 self.git.push(args) 320 321 def do_range_diff(self, args: str): 322 """>>> git range_diff {args}""" 323 self.git.range_diff(args) 324 325 def do_rebase(self, args: str): 326 """>>> git rebase {args}""" 327 self.git.rebase(args) 328 329 def do_reflog(self, args: str): 330 """>>> git reflog {args}""" 331 self.git.reflog(args) 332 333 def do_remote(self, args: str): 334 """>>> git remote {args}""" 335 self.git.remote(args) 336 337 def do_repack(self, args: str): 338 """>>> git repack {args}""" 339 self.git.repack(args) 340 341 def do_replace(self, args: str): 342 """>>> git replace {args}""" 343 self.git.replace(args) 344 345 def do_request_pull(self, args: str): 346 """>>> git request_pull {args}""" 347 self.git.request_pull(args) 348 349 def do_rerere(self, args: str): 350 """>>> git rerere {args}""" 351 self.git.rerere(args) 352 353 def do_reset(self, args: str): 354 """>>> git reset {args}""" 355 self.git.reset(args) 356 357 def do_restore(self, args: str): 358 """>>> git restore {args}""" 359 self.git.restore(args) 360 361 def do_revert(self, args: str): 362 """>>> git revert {args}""" 363 self.git.revert(args) 364 365 def do_rm(self, args: str): 366 """>>> git rm {args}""" 367 self.git.rm(args) 368 369 def do_scalar(self, args: str): 370 """>>> git scalar {args}""" 371 self.git.scalar(args) 372 373 def do_shortlog(self, args: str): 374 """>>> git shortlog {args}""" 375 self.git.shortlog(args) 376 377 def do_show(self, args: str): 378 """>>> git show {args}""" 379 self.git.show(args) 380 381 def do_show_branch(self, args: str): 382 """>>> git show_branch {args}""" 383 self.git.show_branch(args) 384 385 def do_sparse_checkout(self, args: str): 386 """>>> git sparse_checkout {args}""" 387 self.git.sparse_checkout(args) 388 389 def do_stash(self, args: str): 390 """>>> git stash {args}""" 391 self.git.stash(args) 392 393 def do_status(self, args: str): 394 """>>> git status {args}""" 395 self.git.status(args) 396 397 def do_submodule(self, args: str): 398 """>>> git submodule {args}""" 399 self.git.submodule(args) 400 401 def do_switch(self, args: str): 402 """>>> git switch {args}""" 403 self.git.switch(args) 404 405 def do_tag(self, args: str): 406 """>>> git tag {args}""" 407 self.git.tag(args) 408 409 def do_verify_commit(self, args: str): 410 """>>> git verify_commit {args}""" 411 self.git.verify_commit(args) 412 413 def do_verify_tag(self, args: str): 414 """>>> git verify_tag {args}""" 415 self.git.verify_tag(args) 416 417 def do_version(self, args: str): 418 """>>> git version {args}""" 419 self.git.version(args) 420 421 def do_whatchanged(self, args: str): 422 """>>> git whatchanged {args}""" 423 self.git.whatchanged(args) 424 425 def do_worktree(self, args: str): 426 """>>> git worktree {args}""" 427 self.git.worktree(args) 428 429 # Seat |==================================Convenience==================================| 430 431 def do_add_url(self, url: str): 432 """Add remote origin url for repo and push repo. 433 >>> git remote add origin {url} 434 >>> git push -u origin main""" 435 self.git.add_remote_url(url) 436 self.git.push("-u origin main") 437 438 @with_parser(parsers.add_files_parser) 439 def do_amend(self, args: Namespace): 440 """Stage files and add to previous commit.""" 441 self.git.amend(args.files) 442 443 def do_branches(self, _: str): 444 """Show local and remote branches. 445 >>> git branch -vva""" 446 self.git.list_branches() 447 448 def do_commitall(self, message: str): 449 """Stage and commit all modified and untracked files with this message. 450 >>> git add . 451 >>> git commit -m \"{message}\" """ 452 message = message.strip('"').replace('"', "'") 453 self.git.add_all() 454 self.git.commit(f'-m "{message}"') 455 456 @with_parser(parsers.delete_branch_parser) 457 def do_delete_branch(self, args: Namespace): 458 """Delete branch.""" 459 self.git.delete_branch(args.branch, not args.remote) 460 461 def do_delete_gh_repo(self, _: str): 462 """Delete this repo from GitHub. 463 464 GitHub CLI must be installed and configured. 465 466 May require you to reauthorize and rerun command.""" 467 self.git.delete_remote() 468 469 def do_dob(self, _: str): 470 """Date of this repo's first commit.""" 471 dob = self.git.dob 472 elapsed = Timer.format_time((datetime.now() - dob).total_seconds()) 473 print(f"{dob:%m/%d/%Y}|{elapsed} ago") 474 475 def do_ignore(self, patterns: str): 476 """Add the list of patterns/file names to `.gitignore` and commit with the message `chore: add to gitignore`.""" 477 self.git.ignore(patterns.split()) 478 self.git.commit_files([".gitignore"], "chore: add to gitignore") 479 480 @with_parser(parsers.add_files_parser) 481 def do_initcommit(self, args: Namespace): 482 """Stage and commit all files with message "Initial Commit".""" 483 self.git.initcommit(args.files) 484 485 def do_loggy(self, _: str): 486 """>>> git --oneline --name-only --abbrev-commit --graph""" 487 self.git.loggy() 488 489 def do_make_private(self, _: str): 490 """Make the GitHub remote for this repo private. 491 492 This repo must exist and GitHub CLI must be installed and configured.""" 493 self.git.make_private() 494 495 def do_make_public(self, _: str): 496 """Make the GitHub remote for this repo public. 497 498 This repo must exist and GitHub CLI must be installed and configured.""" 499 self.git.make_public() 500 501 def do_new_branch(self, name: str): 502 """Create and switch to a new branch with this `name`.""" 503 self.git.create_new_branch(name) 504 505 @with_parser(parsers.new_remote_parser) 506 def do_new_gh_remote(self, args: Namespace): 507 """Create a remote GitHub repository for this repo. 508 509 GitHub CLI must be installed and configured for this to work.""" 510 self.git.create_remote_from_cwd(args.public) 511 512 def do_new_repo(self, _: str): 513 """Create a new git repo in this directory.""" 514 self.git.new_repo() 515 516 def do_push_new(self, _: str): 517 """Push current branch to origin with `-u` flag. 518 >>> git push -u origin {this_branch}""" 519 self.git.push_new_branch(self.git.current_branch) 520 521 def do_undo(self, _: str): 522 """Undo all uncommitted changes. 523 >>> git checkout .""" 524 self.git.undo() 525 526 @with_parser(parsers.add_files_parser) 527 def do_untrack(self, args: Namespace): 528 """Untrack files matching provided path/pattern list. 529 530 For each path/pattern, equivalent to: 531 >>> git rm --cached {path}""" 532 self.git.untrack(*args.files) 533 534 @with_parser(parsers.rename_file_parser) 535 def do_rename_file(self, args: Namespace): 536 """Renames a file. 537 After renaming the file, the renaming change is staged for commit.""" 538 self.git.rename_file(args.file, args.new_name)
GitBetter Shell.
99 def default(self, line: str): 100 if self.execute_in_terminal_if_unrecognized: 101 os.system(line) 102 else: 103 super().default(line)
Called on an input line when the command prefix is not recognized.
If this method is not overridden, it prints an error message and returns.
105 def do_cd(self, path: str): 106 """Change current working directory to `path`.""" 107 os.chdir(path) 108 self.prompt = f"gitbetter::{Pathier.cwd()}>"
Change current working directory to path
.
110 def do_help(self, arg: str): 111 """List available commands with "help" or detailed help with "help cmd".""" 112 super().do_help(arg) 113 if not arg: 114 print(self.unrecognized_command_behavior_status) 115 if self.execute_in_terminal_if_unrecognized: 116 print( 117 "^Essentially makes this shell function as a super-shell of whatever shell you launched gitbetter from.^" 118 ) 119 print()
List available commands with "help" or detailed help with "help cmd".
121 def do_toggle_unrecognized_command_behavior(self, arg: str): 122 """Toggle whether the shell will attempt to execute unrecognized commands as system commands in the terminal. 123 When on (the default), `GitBetter` will treat unrecognized commands as if you added the `sys` command in front of the input, i.e. `os.system(your_input)`. 124 When off, an `unknown syntax` message will be printed and no commands will be executed. 125 """ 126 self.execute_in_terminal_if_unrecognized = ( 127 not self.execute_in_terminal_if_unrecognized 128 ) 129 print(self.unrecognized_command_behavior_status)
Toggle whether the shell will attempt to execute unrecognized commands as system commands in the terminal.
When on (the default), GitBetter
will treat unrecognized commands as if you added the sys
command in front of the input, i.e. os.system(your_input)
.
When off, an unknown syntax
message will be printed and no commands will be executed.
133 def do_git(self, args: str): 134 """Directly execute `git {args}`. 135 136 i.e. You can still do everything directly invoking git can do.""" 137 self.git.git(args)
Directly execute git {args}
.
i.e. You can still do everything directly invoking git can do.
169 def do_bugreport(self, args: str): 170 """>>> git bugreport {args}""" 171 self.git.bugreport(args)
>>> git bugreport {args}
181 def do_cherry_pick(self, args: str): 182 """>>> git cherry_pick {args}""" 183 self.git.cherry_pick(args)
>>> git cherry_pick {args}
205 def do_count_objects(self, args: str): 206 """>>> git count_objects {args}""" 207 self.git.count_objects(args)
>>> git count_objects {args}
225 def do_fast_export(self, args: str): 226 """>>> git fast_export {args}""" 227 self.git.fast_export(args)
>>> git fast_export {args}
229 def do_fast_import(self, args: str): 230 """>>> git fast_import {args}""" 231 self.git.fast_import(args)
>>> git fast_import {args}
237 def do_filter_branch(self, args: str): 238 """>>> git filter_branch {args}""" 239 self.git.filter_branch(args)
>>> git filter_branch {args}
241 def do_format_patch(self, args: str): 242 """>>> git format_patch {args}""" 243 self.git.format_patch(args)
>>> git format_patch {args}
281 def do_maintenance(self, args: str): 282 """>>> git maintenance {args}""" 283 self.git.maintenance(args)
>>> git maintenance {args}
289 def do_merge_tree(self, args: str): 290 """>>> git merge_tree {args}""" 291 self.git.merge_tree(args)
>>> git merge_tree {args}
293 def do_mergetool(self, args: str): 294 """>>> git mergetool {args}""" 295 self.git.mergetool(args)
>>> git mergetool {args}
305 def do_pack_refs(self, args: str): 306 """>>> git pack_refs {args}""" 307 self.git.pack_refs(args)
>>> git pack_refs {args}
321 def do_range_diff(self, args: str): 322 """>>> git range_diff {args}""" 323 self.git.range_diff(args)
>>> git range_diff {args}
345 def do_request_pull(self, args: str): 346 """>>> git request_pull {args}""" 347 self.git.request_pull(args)
>>> git request_pull {args}
381 def do_show_branch(self, args: str): 382 """>>> git show_branch {args}""" 383 self.git.show_branch(args)
>>> git show_branch {args}
385 def do_sparse_checkout(self, args: str): 386 """>>> git sparse_checkout {args}""" 387 self.git.sparse_checkout(args)
>>> git sparse_checkout {args}
397 def do_submodule(self, args: str): 398 """>>> git submodule {args}""" 399 self.git.submodule(args)
>>> git submodule {args}
409 def do_verify_commit(self, args: str): 410 """>>> git verify_commit {args}""" 411 self.git.verify_commit(args)
>>> git verify_commit {args}
413 def do_verify_tag(self, args: str): 414 """>>> git verify_tag {args}""" 415 self.git.verify_tag(args)
>>> git verify_tag {args}
421 def do_whatchanged(self, args: str): 422 """>>> git whatchanged {args}""" 423 self.git.whatchanged(args)
>>> git whatchanged {args}
431 def do_add_url(self, url: str): 432 """Add remote origin url for repo and push repo. 433 >>> git remote add origin {url} 434 >>> git push -u origin main""" 435 self.git.add_remote_url(url) 436 self.git.push("-u origin main")
Add remote origin url for repo and push repo.
>>> git remote add origin {url}
>>> git push -u origin main
438 @with_parser(parsers.add_files_parser) 439 def do_amend(self, args: Namespace): 440 """Stage files and add to previous commit.""" 441 self.git.amend(args.files)
Stage files and add to previous commit.
443 def do_branches(self, _: str): 444 """Show local and remote branches. 445 >>> git branch -vva""" 446 self.git.list_branches()
Show local and remote branches.
>>> git branch -vva
448 def do_commitall(self, message: str): 449 """Stage and commit all modified and untracked files with this message. 450 >>> git add . 451 >>> git commit -m \"{message}\" """ 452 message = message.strip('"').replace('"', "'") 453 self.git.add_all() 454 self.git.commit(f'-m "{message}"')
Stage and commit all modified and untracked files with this message.
>>> git add .
>>> git commit -m "{message}"
456 @with_parser(parsers.delete_branch_parser) 457 def do_delete_branch(self, args: Namespace): 458 """Delete branch.""" 459 self.git.delete_branch(args.branch, not args.remote)
Delete branch.
461 def do_delete_gh_repo(self, _: str): 462 """Delete this repo from GitHub. 463 464 GitHub CLI must be installed and configured. 465 466 May require you to reauthorize and rerun command.""" 467 self.git.delete_remote()
Delete this repo from GitHub.
GitHub CLI must be installed and configured.
May require you to reauthorize and rerun command.
469 def do_dob(self, _: str): 470 """Date of this repo's first commit.""" 471 dob = self.git.dob 472 elapsed = Timer.format_time((datetime.now() - dob).total_seconds()) 473 print(f"{dob:%m/%d/%Y}|{elapsed} ago")
Date of this repo's first commit.
475 def do_ignore(self, patterns: str): 476 """Add the list of patterns/file names to `.gitignore` and commit with the message `chore: add to gitignore`.""" 477 self.git.ignore(patterns.split()) 478 self.git.commit_files([".gitignore"], "chore: add to gitignore")
Add the list of patterns/file names to .gitignore
and commit with the message chore: add to gitignore
.
480 @with_parser(parsers.add_files_parser) 481 def do_initcommit(self, args: Namespace): 482 """Stage and commit all files with message "Initial Commit".""" 483 self.git.initcommit(args.files)
Stage and commit all files with message "Initial Commit".
485 def do_loggy(self, _: str): 486 """>>> git --oneline --name-only --abbrev-commit --graph""" 487 self.git.loggy()
>>> git --oneline --name-only --abbrev-commit --graph
489 def do_make_private(self, _: str): 490 """Make the GitHub remote for this repo private. 491 492 This repo must exist and GitHub CLI must be installed and configured.""" 493 self.git.make_private()
Make the GitHub remote for this repo private.
This repo must exist and GitHub CLI must be installed and configured.
495 def do_make_public(self, _: str): 496 """Make the GitHub remote for this repo public. 497 498 This repo must exist and GitHub CLI must be installed and configured.""" 499 self.git.make_public()
Make the GitHub remote for this repo public.
This repo must exist and GitHub CLI must be installed and configured.
501 def do_new_branch(self, name: str): 502 """Create and switch to a new branch with this `name`.""" 503 self.git.create_new_branch(name)
Create and switch to a new branch with this name
.
505 @with_parser(parsers.new_remote_parser) 506 def do_new_gh_remote(self, args: Namespace): 507 """Create a remote GitHub repository for this repo. 508 509 GitHub CLI must be installed and configured for this to work.""" 510 self.git.create_remote_from_cwd(args.public)
Create a remote GitHub repository for this repo.
GitHub CLI must be installed and configured for this to work.
512 def do_new_repo(self, _: str): 513 """Create a new git repo in this directory.""" 514 self.git.new_repo()
Create a new git repo in this directory.
516 def do_push_new(self, _: str): 517 """Push current branch to origin with `-u` flag. 518 >>> git push -u origin {this_branch}""" 519 self.git.push_new_branch(self.git.current_branch)
Push current branch to origin with -u
flag.
>>> git push -u origin {this_branch}
521 def do_undo(self, _: str): 522 """Undo all uncommitted changes. 523 >>> git checkout .""" 524 self.git.undo()
Undo all uncommitted changes.
>>> git checkout .
526 @with_parser(parsers.add_files_parser) 527 def do_untrack(self, args: Namespace): 528 """Untrack files matching provided path/pattern list. 529 530 For each path/pattern, equivalent to: 531 >>> git rm --cached {path}""" 532 self.git.untrack(*args.files)
Untrack files matching provided path/pattern list.
For each path/pattern, equivalent to:
>>> git rm --cached {path}
534 @with_parser(parsers.rename_file_parser) 535 def do_rename_file(self, args: Namespace): 536 """Renames a file. 537 After renaming the file, the renaming change is staged for commit.""" 538 self.git.rename_file(args.file, args.new_name)
Renames a file. After renaming the file, the renaming change is staged for commit.
Inherited Members
- cmd.Cmd
- Cmd
- precmd
- postcmd
- preloop
- postloop
- parseline
- onecmd
- completedefault
- completenames
- complete
- get_names
- complete_help
- print_topics
- columnize
- argshell.argshell.ArgShell
- do_quit
- do_sys
- cmdloop
- emptyline