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, GitHub, 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.run(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        GitHub().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        GitHub().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        GitHub().make_public()
499
500    def do_merge_to(self, branch: str):
501        """Merge the current branch into the provided branch after switching to the provided branch.
502
503        If no branch name is given, "main" will be used."""
504        self.git.merge_to(branch or "main")
505
506    def do_new_branch(self, name: str):
507        """Create and switch to a new branch with this `name`."""
508        self.git.create_new_branch(name)
509
510    @with_parser(parsers.new_remote_parser)
511    def do_new_gh_remote(self, args: Namespace):
512        """Create a remote GitHub repository for this repo.
513
514        GitHub CLI must be installed and configured for this to work."""
515        GitHub().create_remote_from_cwd(args.public)
516
517    def do_new_repo(self, _: str):
518        """Create a new git repo in this directory."""
519        self.git.new_repo()
520
521    def do_push_new(self, _: str):
522        """Push current branch to origin with `-u` flag.
523        >>> git push -u origin {this_branch}"""
524        self.git.push_new_branch(self.git.current_branch)
525
526    def do_undo(self, _: str):
527        """Undo all uncommitted changes.
528        >>> git checkout ."""
529        self.git.undo()
530
531    @with_parser(parsers.add_files_parser)
532    def do_untrack(self, args: Namespace):
533        """Untrack files matching provided path/pattern list.
534
535        For each path/pattern, equivalent to:
536        >>> git rm --cached {path}"""
537        self.git.untrack(*args.files)
538
539    @with_parser(parsers.rename_file_parser)
540    def do_rename_file(self, args: Namespace):
541        """Renames a file.
542        After renaming the file, the renaming change is staged for commit."""
543        self.git.rename_file(args.file, args.new_name)
544
545
546def main():
547    GitBetter().cmdloop()
548
549
550if __name__ == "__main__":
551    main()
class GitArgShell(argshell.argshell.ArgShell):
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.

def do_help(self, arg):
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
do_reload
cmdloop
emptyline
class GitBetter(GitArgShell):
 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.run(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        GitHub().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        GitHub().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        GitHub().make_public()
500
501    def do_merge_to(self, branch: str):
502        """Merge the current branch into the provided branch after switching to the provided branch.
503
504        If no branch name is given, "main" will be used."""
505        self.git.merge_to(branch or "main")
506
507    def do_new_branch(self, name: str):
508        """Create and switch to a new branch with this `name`."""
509        self.git.create_new_branch(name)
510
511    @with_parser(parsers.new_remote_parser)
512    def do_new_gh_remote(self, args: Namespace):
513        """Create a remote GitHub repository for this repo.
514
515        GitHub CLI must be installed and configured for this to work."""
516        GitHub().create_remote_from_cwd(args.public)
517
518    def do_new_repo(self, _: str):
519        """Create a new git repo in this directory."""
520        self.git.new_repo()
521
522    def do_push_new(self, _: str):
523        """Push current branch to origin with `-u` flag.
524        >>> git push -u origin {this_branch}"""
525        self.git.push_new_branch(self.git.current_branch)
526
527    def do_undo(self, _: str):
528        """Undo all uncommitted changes.
529        >>> git checkout ."""
530        self.git.undo()
531
532    @with_parser(parsers.add_files_parser)
533    def do_untrack(self, args: Namespace):
534        """Untrack files matching provided path/pattern list.
535
536        For each path/pattern, equivalent to:
537        >>> git rm --cached {path}"""
538        self.git.untrack(*args.files)
539
540    @with_parser(parsers.rename_file_parser)
541    def do_rename_file(self, args: Namespace):
542        """Renames a file.
543        After renaming the file, the renaming change is staged for commit."""
544        self.git.rename_file(args.file, args.new_name)

GitBetter Shell.

def default(self, line: str):
 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.

def do_cd(self, path: str):
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.

def do_help(self, arg: str):
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".

def do_toggle_unrecognized_command_behavior(self, arg: str):
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.

def do_git(self, args: str):
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.run(args)

Directly execute git {args}.

i.e. You can still do everything directly invoking git can do.

def do_add(self, args: str):
141    def do_add(self, args: str):
142        """>>> git add {args}"""
143        self.git.add(args)
>>> git add {args}
def do_am(self, args: str):
145    def do_am(self, args: str):
146        """>>> git am {args}"""
147        self.git.am(args)
>>> git am {args}
def do_annotate(self, args: str):
149    def do_annotate(self, args: str):
150        """>>> git annotate {args}"""
151        self.git.annotate(args)
>>> git annotate {args}
def do_archive(self, args: str):
153    def do_archive(self, args: str):
154        """>>> git archive {args}"""
155        self.git.archive(args)
>>> git archive {args}
def do_bisect(self, args: str):
157    def do_bisect(self, args: str):
158        """>>> git bisect {args}"""
159        self.git.bisect(args)
>>> git bisect {args}
def do_blame(self, args: str):
161    def do_blame(self, args: str):
162        """>>> git blame {args}"""
163        self.git.blame(args)
>>> git blame {args}
def do_branch(self, args: str):
165    def do_branch(self, args: str):
166        """>>> git branch {args}"""
167        self.git.branch(args)
>>> git branch {args}
def do_bugreport(self, args: str):
169    def do_bugreport(self, args: str):
170        """>>> git bugreport {args}"""
171        self.git.bugreport(args)
>>> git bugreport {args}
def do_bundle(self, args: str):
173    def do_bundle(self, args: str):
174        """>>> git bundle {args}"""
175        self.git.bundle(args)
>>> git bundle {args}
def do_checkout(self, args: str):
177    def do_checkout(self, args: str):
178        """>>> git checkout {args}"""
179        self.git.checkout(args)
>>> git checkout {args}
def do_cherry_pick(self, args: str):
181    def do_cherry_pick(self, args: str):
182        """>>> git cherry_pick {args}"""
183        self.git.cherry_pick(args)
>>> git cherry_pick {args}
def do_citool(self, args: str):
185    def do_citool(self, args: str):
186        """>>> git citool {args}"""
187        self.git.citool(args)
>>> git citool {args}
def do_clean(self, args: str):
189    def do_clean(self, args: str):
190        """>>> git clean {args}"""
191        self.git.clean(args)
>>> git clean {args}
def do_clone(self, args: str):
193    def do_clone(self, args: str):
194        """>>> git clone {args}"""
195        self.git.clone(args)
>>> git clone {args}
def do_commit(self, args: str):
197    def do_commit(self, args: str):
198        """>>> git commit {args}"""
199        self.git.commit(args)
>>> git commit {args}
def do_config(self, args: str):
201    def do_config(self, args: str):
202        """>>> git config {args}"""
203        self.git.config(args)
>>> git config {args}
def do_count_objects(self, args: str):
205    def do_count_objects(self, args: str):
206        """>>> git count_objects {args}"""
207        self.git.count_objects(args)
>>> git count_objects {args}
def do_describe(self, args: str):
209    def do_describe(self, args: str):
210        """>>> git describe {args}"""
211        self.git.describe(args)
>>> git describe {args}
def do_diagnose(self, args: str):
213    def do_diagnose(self, args: str):
214        """>>> git diagnose {args}"""
215        self.git.diagnose(args)
>>> git diagnose {args}
def do_diff(self, args: str):
217    def do_diff(self, args: str):
218        """>>> git diff {args}"""
219        self.git.diff(args)
>>> git diff {args}
def do_difftool(self, args: str):
221    def do_difftool(self, args: str):
222        """>>> git difftool {args}"""
223        self.git.difftool(args)
>>> git difftool {args}
def do_fast_export(self, args: str):
225    def do_fast_export(self, args: str):
226        """>>> git fast_export {args}"""
227        self.git.fast_export(args)
>>> git fast_export {args}
def do_fast_import(self, args: str):
229    def do_fast_import(self, args: str):
230        """>>> git fast_import {args}"""
231        self.git.fast_import(args)
>>> git fast_import {args}
def do_fetch(self, args: str):
233    def do_fetch(self, args: str):
234        """>>> git fetch {args}"""
235        self.git.fetch(args)
>>> git fetch {args}
def do_filter_branch(self, args: str):
237    def do_filter_branch(self, args: str):
238        """>>> git filter_branch {args}"""
239        self.git.filter_branch(args)
>>> git filter_branch {args}
def do_format_patch(self, args: str):
241    def do_format_patch(self, args: str):
242        """>>> git format_patch {args}"""
243        self.git.format_patch(args)
>>> git format_patch {args}
def do_fsck(self, args: str):
245    def do_fsck(self, args: str):
246        """>>> git fsck {args}"""
247        self.git.fsck(args)
>>> git fsck {args}
def do_gc(self, args: str):
249    def do_gc(self, args: str):
250        """>>> git gc {args}"""
251        self.git.gc(args)
>>> git gc {args}
def do_gitk(self, args: str):
253    def do_gitk(self, args: str):
254        """>>> git gitk {args}"""
255        self.git.gitk(args)
>>> git gitk {args}
def do_gitweb(self, args: str):
257    def do_gitweb(self, args: str):
258        """>>> git gitweb {args}"""
259        self.git.gitweb(args)
>>> git gitweb {args}
def do_grep(self, args: str):
261    def do_grep(self, args: str):
262        """>>> git grep {args}"""
263        self.git.grep(args)
>>> git grep {args}
def do_gui(self, args: str):
265    def do_gui(self, args: str):
266        """>>> git gui {args}"""
267        self.git.gui(args)
>>> git gui {args}
def do_init(self, args: str):
269    def do_init(self, args: str):
270        """>>> git init {args}"""
271        self.git.init(args)
>>> git init {args}
def do_instaweb(self, args: str):
273    def do_instaweb(self, args: str):
274        """>>> git instaweb {args}"""
275        self.git.instaweb(args)
>>> git instaweb {args}
def do_log(self, args: str):
277    def do_log(self, args: str):
278        """>>> git log {args}"""
279        self.git.log(args)
>>> git log {args}
def do_maintenance(self, args: str):
281    def do_maintenance(self, args: str):
282        """>>> git maintenance {args}"""
283        self.git.maintenance(args)
>>> git maintenance {args}
def do_merge(self, args: str):
285    def do_merge(self, args: str):
286        """>>> git merge {args}"""
287        self.git.merge(args)
>>> git merge {args}
def do_merge_tree(self, args: str):
289    def do_merge_tree(self, args: str):
290        """>>> git merge_tree {args}"""
291        self.git.merge_tree(args)
>>> git merge_tree {args}
def do_mergetool(self, args: str):
293    def do_mergetool(self, args: str):
294        """>>> git mergetool {args}"""
295        self.git.mergetool(args)
>>> git mergetool {args}
def do_mv(self, args: str):
297    def do_mv(self, args: str):
298        """>>> git mv {args}"""
299        self.git.mv(args)
>>> git mv {args}
def do_notes(self, args: str):
301    def do_notes(self, args: str):
302        """>>> git notes {args}"""
303        self.git.notes(args)
>>> git notes {args}
def do_pack_refs(self, args: str):
305    def do_pack_refs(self, args: str):
306        """>>> git pack_refs {args}"""
307        self.git.pack_refs(args)
>>> git pack_refs {args}
def do_prune(self, args: str):
309    def do_prune(self, args: str):
310        """>>> git prune {args}"""
311        self.git.prune(args)
>>> git prune {args}
def do_pull(self, args: str):
313    def do_pull(self, args: str):
314        """>>> git pull {args}"""
315        self.git.pull(args)
>>> git pull {args}
def do_push(self, args: str):
317    def do_push(self, args: str):
318        """>>> git push {args}"""
319        self.git.push(args)
>>> git push {args}
def do_range_diff(self, args: str):
321    def do_range_diff(self, args: str):
322        """>>> git range_diff {args}"""
323        self.git.range_diff(args)
>>> git range_diff {args}
def do_rebase(self, args: str):
325    def do_rebase(self, args: str):
326        """>>> git rebase {args}"""
327        self.git.rebase(args)
>>> git rebase {args}
def do_reflog(self, args: str):
329    def do_reflog(self, args: str):
330        """>>> git reflog {args}"""
331        self.git.reflog(args)
>>> git reflog {args}
def do_remote(self, args: str):
333    def do_remote(self, args: str):
334        """>>> git remote {args}"""
335        self.git.remote(args)
>>> git remote {args}
def do_repack(self, args: str):
337    def do_repack(self, args: str):
338        """>>> git repack {args}"""
339        self.git.repack(args)
>>> git repack {args}
def do_replace(self, args: str):
341    def do_replace(self, args: str):
342        """>>> git replace {args}"""
343        self.git.replace(args)
>>> git replace {args}
def do_request_pull(self, args: str):
345    def do_request_pull(self, args: str):
346        """>>> git request_pull {args}"""
347        self.git.request_pull(args)
>>> git request_pull {args}
def do_rerere(self, args: str):
349    def do_rerere(self, args: str):
350        """>>> git rerere {args}"""
351        self.git.rerere(args)
>>> git rerere {args}
def do_reset(self, args: str):
353    def do_reset(self, args: str):
354        """>>> git reset {args}"""
355        self.git.reset(args)
>>> git reset {args}
def do_restore(self, args: str):
357    def do_restore(self, args: str):
358        """>>> git restore {args}"""
359        self.git.restore(args)
>>> git restore {args}
def do_revert(self, args: str):
361    def do_revert(self, args: str):
362        """>>> git revert {args}"""
363        self.git.revert(args)
>>> git revert {args}
def do_rm(self, args: str):
365    def do_rm(self, args: str):
366        """>>> git rm {args}"""
367        self.git.rm(args)
>>> git rm {args}
def do_scalar(self, args: str):
369    def do_scalar(self, args: str):
370        """>>> git scalar {args}"""
371        self.git.scalar(args)
>>> git scalar {args}
def do_shortlog(self, args: str):
373    def do_shortlog(self, args: str):
374        """>>> git shortlog {args}"""
375        self.git.shortlog(args)
>>> git shortlog {args}
def do_show(self, args: str):
377    def do_show(self, args: str):
378        """>>> git show {args}"""
379        self.git.show(args)
>>> git show {args}
def do_show_branch(self, args: str):
381    def do_show_branch(self, args: str):
382        """>>> git show_branch {args}"""
383        self.git.show_branch(args)
>>> git show_branch {args}
def do_sparse_checkout(self, args: str):
385    def do_sparse_checkout(self, args: str):
386        """>>> git sparse_checkout {args}"""
387        self.git.sparse_checkout(args)
>>> git sparse_checkout {args}
def do_stash(self, args: str):
389    def do_stash(self, args: str):
390        """>>> git stash {args}"""
391        self.git.stash(args)
>>> git stash {args}
def do_status(self, args: str):
393    def do_status(self, args: str):
394        """>>> git status {args}"""
395        self.git.status(args)
>>> git status {args}
def do_submodule(self, args: str):
397    def do_submodule(self, args: str):
398        """>>> git submodule {args}"""
399        self.git.submodule(args)
>>> git submodule {args}
def do_switch(self, args: str):
401    def do_switch(self, args: str):
402        """>>> git switch {args}"""
403        self.git.switch(args)
>>> git switch {args}
def do_tag(self, args: str):
405    def do_tag(self, args: str):
406        """>>> git tag {args}"""
407        self.git.tag(args)
>>> git tag {args}
def do_verify_commit(self, args: str):
409    def do_verify_commit(self, args: str):
410        """>>> git verify_commit {args}"""
411        self.git.verify_commit(args)
>>> git verify_commit {args}
def do_verify_tag(self, args: str):
413    def do_verify_tag(self, args: str):
414        """>>> git verify_tag {args}"""
415        self.git.verify_tag(args)
>>> git verify_tag {args}
def do_version(self, args: str):
417    def do_version(self, args: str):
418        """>>> git version {args}"""
419        self.git.version(args)
>>> git version {args}
def do_whatchanged(self, args: str):
421    def do_whatchanged(self, args: str):
422        """>>> git whatchanged {args}"""
423        self.git.whatchanged(args)
>>> git whatchanged {args}
def do_worktree(self, args: str):
425    def do_worktree(self, args: str):
426        """>>> git worktree {args}"""
427        self.git.worktree(args)
>>> git worktree {args}
def do_add_url(self, url: str):
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
@with_parser(parsers.add_files_parser)
def do_amend(self, args: argshell.argshell.Namespace):
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.

def do_branches(self, _: str):
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
def do_commitall(self, message: str):
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}"
@with_parser(parsers.delete_branch_parser)
def do_delete_branch(self, args: argshell.argshell.Namespace):
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.

def do_delete_gh_repo(self, _: str):
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        GitHub().delete_remote()

Delete this repo from GitHub.

GitHub CLI must be installed and configured.

May require you to reauthorize and rerun command.

def do_dob(self, _: str):
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.

def do_ignore(self, patterns: str):
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.

@with_parser(parsers.add_files_parser)
def do_initcommit(self, args: argshell.argshell.Namespace):
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".

def do_loggy(self, _: str):
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
def do_make_private(self, _: str):
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        GitHub().make_private()

Make the GitHub remote for this repo private.

This repo must exist and GitHub CLI must be installed and configured.

def do_make_public(self, _: str):
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        GitHub().make_public()

Make the GitHub remote for this repo public.

This repo must exist and GitHub CLI must be installed and configured.

def do_merge_to(self, branch: str):
501    def do_merge_to(self, branch: str):
502        """Merge the current branch into the provided branch after switching to the provided branch.
503
504        If no branch name is given, "main" will be used."""
505        self.git.merge_to(branch or "main")

Merge the current branch into the provided branch after switching to the provided branch.

If no branch name is given, "main" will be used.

def do_new_branch(self, name: str):
507    def do_new_branch(self, name: str):
508        """Create and switch to a new branch with this `name`."""
509        self.git.create_new_branch(name)

Create and switch to a new branch with this name.

@with_parser(parsers.new_remote_parser)
def do_new_gh_remote(self, args: argshell.argshell.Namespace):
511    @with_parser(parsers.new_remote_parser)
512    def do_new_gh_remote(self, args: Namespace):
513        """Create a remote GitHub repository for this repo.
514
515        GitHub CLI must be installed and configured for this to work."""
516        GitHub().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.

def do_new_repo(self, _: str):
518    def do_new_repo(self, _: str):
519        """Create a new git repo in this directory."""
520        self.git.new_repo()

Create a new git repo in this directory.

def do_push_new(self, _: str):
522    def do_push_new(self, _: str):
523        """Push current branch to origin with `-u` flag.
524        >>> git push -u origin {this_branch}"""
525        self.git.push_new_branch(self.git.current_branch)

Push current branch to origin with -u flag.

>>> git push -u origin {this_branch}
def do_undo(self, _: str):
527    def do_undo(self, _: str):
528        """Undo all uncommitted changes.
529        >>> git checkout ."""
530        self.git.undo()

Undo all uncommitted changes.

>>> git checkout .
@with_parser(parsers.add_files_parser)
def do_untrack(self, args: argshell.argshell.Namespace):
532    @with_parser(parsers.add_files_parser)
533    def do_untrack(self, args: Namespace):
534        """Untrack files matching provided path/pattern list.
535
536        For each path/pattern, equivalent to:
537        >>> git rm --cached {path}"""
538        self.git.untrack(*args.files)

Untrack files matching provided path/pattern list.

For each path/pattern, equivalent to:

>>> git rm --cached {path}
@with_parser(parsers.rename_file_parser)
def do_rename_file(self, args: argshell.argshell.Namespace):
540    @with_parser(parsers.rename_file_parser)
541    def do_rename_file(self, args: Namespace):
542        """Renames a file.
543        After renaming the file, the renaming change is staged for commit."""
544        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
do_reload
cmdloop
emptyline
def main():
547def main():
548    GitBetter().cmdloop()