skilleter-thingy 0.0.22__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of skilleter-thingy might be problematic. Click here for more details.

Files changed (67) hide show
  1. skilleter_thingy/__init__.py +0 -0
  2. skilleter_thingy/addpath.py +107 -0
  3. skilleter_thingy/aws.py +548 -0
  4. skilleter_thingy/borger.py +269 -0
  5. skilleter_thingy/colour.py +213 -0
  6. skilleter_thingy/console_colours.py +63 -0
  7. skilleter_thingy/dc_curses.py +278 -0
  8. skilleter_thingy/dc_defaults.py +221 -0
  9. skilleter_thingy/dc_util.py +50 -0
  10. skilleter_thingy/dircolors.py +308 -0
  11. skilleter_thingy/diskspacecheck.py +67 -0
  12. skilleter_thingy/docker.py +95 -0
  13. skilleter_thingy/docker_purge.py +113 -0
  14. skilleter_thingy/ffind.py +536 -0
  15. skilleter_thingy/files.py +142 -0
  16. skilleter_thingy/ggit.py +90 -0
  17. skilleter_thingy/ggrep.py +154 -0
  18. skilleter_thingy/git.py +1368 -0
  19. skilleter_thingy/git2.py +1307 -0
  20. skilleter_thingy/git_br.py +180 -0
  21. skilleter_thingy/git_ca.py +142 -0
  22. skilleter_thingy/git_cleanup.py +287 -0
  23. skilleter_thingy/git_co.py +220 -0
  24. skilleter_thingy/git_common.py +61 -0
  25. skilleter_thingy/git_hold.py +154 -0
  26. skilleter_thingy/git_mr.py +92 -0
  27. skilleter_thingy/git_parent.py +77 -0
  28. skilleter_thingy/git_review.py +1416 -0
  29. skilleter_thingy/git_update.py +385 -0
  30. skilleter_thingy/git_wt.py +96 -0
  31. skilleter_thingy/gitcmp_helper.py +322 -0
  32. skilleter_thingy/gitlab.py +193 -0
  33. skilleter_thingy/gitprompt.py +274 -0
  34. skilleter_thingy/gl.py +174 -0
  35. skilleter_thingy/gphotosync.py +610 -0
  36. skilleter_thingy/linecount.py +155 -0
  37. skilleter_thingy/logger.py +112 -0
  38. skilleter_thingy/moviemover.py +133 -0
  39. skilleter_thingy/path.py +156 -0
  40. skilleter_thingy/photodupe.py +110 -0
  41. skilleter_thingy/phototidier.py +248 -0
  42. skilleter_thingy/popup.py +87 -0
  43. skilleter_thingy/process.py +112 -0
  44. skilleter_thingy/py_audit.py +131 -0
  45. skilleter_thingy/readable.py +270 -0
  46. skilleter_thingy/remdir.py +126 -0
  47. skilleter_thingy/rmdupe.py +550 -0
  48. skilleter_thingy/rpylint.py +91 -0
  49. skilleter_thingy/run.py +334 -0
  50. skilleter_thingy/s3_sync.py +383 -0
  51. skilleter_thingy/splitpics.py +99 -0
  52. skilleter_thingy/strreplace.py +82 -0
  53. skilleter_thingy/sysmon.py +435 -0
  54. skilleter_thingy/tfm.py +920 -0
  55. skilleter_thingy/tfm_pane.py +595 -0
  56. skilleter_thingy/tfparse.py +101 -0
  57. skilleter_thingy/tidy.py +160 -0
  58. skilleter_thingy/trimpath.py +84 -0
  59. skilleter_thingy/window_rename.py +92 -0
  60. skilleter_thingy/xchmod.py +125 -0
  61. skilleter_thingy/yamlcheck.py +89 -0
  62. skilleter_thingy-0.0.22.dist-info/LICENSE +619 -0
  63. skilleter_thingy-0.0.22.dist-info/METADATA +22 -0
  64. skilleter_thingy-0.0.22.dist-info/RECORD +67 -0
  65. skilleter_thingy-0.0.22.dist-info/WHEEL +5 -0
  66. skilleter_thingy-0.0.22.dist-info/entry_points.txt +43 -0
  67. skilleter_thingy-0.0.22.dist-info/top_level.txt +1 -0
@@ -0,0 +1,220 @@
1
+ #! /usr/bin/env python3
2
+
3
+ ################################################################################
4
+ """ Enhanced version of 'git checkout'
5
+
6
+ Currently only supports the '-b' option in addition to the default
7
+ behaviour (may be extended to other options later, but otherwise, just
8
+ use the 'git checkout' command as normal.
9
+
10
+ Differs from standard checkout in that if the branch name specified is not
11
+ an exact match for an existing local or remote branch it will look for
12
+ branches where the specified name is a substring (e.g. '12345' will match
13
+ 'feature/fix-1234567') and, if there is a unique match, it will check that
14
+ out. If there are multiple matches it will just list them.
15
+
16
+ Note - partial matching ONLY works for branch names - tag names only
17
+ do full matching and commits only match against the start of the SHA1
18
+
19
+ TODO: Should prioritise branch names over SHA1 - for instance git co 69772
20
+ """
21
+ ################################################################################
22
+
23
+ import logging
24
+ import sys
25
+ import argparse
26
+
27
+ from skilleter_thingy import git
28
+ from skilleter_thingy import colour
29
+
30
+ assert sys.version_info.major >= 3 and sys.version_info.minor >= 6
31
+
32
+ ################################################################################
33
+
34
+ DESCRIPTION = \
35
+ """
36
+ Enhanced version of 'git checkout'
37
+
38
+ Differs from standard checkout in that if the branch name specified is
39
+ not an exact match for an existing branch it will look for branches
40
+ where the specified name is a substring (e.g. '12345' will match
41
+ 'feature/fix-1234567')
42
+
43
+ If there is a single match, it will check that out.
44
+
45
+ If there are multiple matches it will just list them.
46
+
47
+ If no local branches match, it will match against remote branches.
48
+
49
+ If no matching branches exist will will try commit IDs or tags.
50
+
51
+ Currently only supports the '-b' option in addition to the default
52
+ behaviour (may be extended to other options later, but otherwise, just
53
+ use the 'git checkout' command as normal).
54
+ """
55
+
56
+ ################################################################################
57
+
58
+ def parse_arguments():
59
+ """ Parse and return command line arguments """
60
+
61
+ parser = argparse.ArgumentParser(description=DESCRIPTION, formatter_class=argparse.RawTextHelpFormatter)
62
+ parser.add_argument('-b', '--branch', action='store_true', help='Create the specified branch')
63
+ parser.add_argument('-u', '--update', action='store_true', help='If a remote branch exists, delete any local branch and check out the remote version')
64
+ parser.add_argument('-r', '--rebase', action='store_true', help='Rebase the branch onto its parent after checking it out')
65
+ parser.add_argument('-f', '--force', action='store_true',
66
+ help='When using the update option, recreate the local branch even if it is owned by the current user (based on the author of the most recent commit)')
67
+ parser.add_argument('-e', '--exact', action='store_true', help='Do not use branch name matching - check out the branch as specified (if it exists)')
68
+ parser.add_argument('--debug', action='store_true', help='Enable debug output')
69
+ parser.add_argument('branchname', nargs=1, type=str,
70
+ help='The branch name (or a partial name that matches uniquely against a local branch, remote branch, commit ID or tag)')
71
+
72
+ args = parser.parse_args()
73
+
74
+ # Enable logging if requested
75
+
76
+ if args.debug:
77
+ logging.basicConfig(level=logging.INFO)
78
+
79
+ return args
80
+
81
+ ################################################################################
82
+
83
+ def checkout_matching_branch(args, branchname):
84
+ """ Look for a commit matching the specified name and check it out if it is
85
+ an exact match or there is only one partial match.
86
+ If there are multiple branches that match, just list them """
87
+
88
+ # If we are doing an update, then make sure we have all the remote info up-to-date
89
+
90
+ if args.update:
91
+ colour.write('Fetching updates from remote server(s)')
92
+ git.fetch(all=True)
93
+
94
+ # Get the list of matching commits.
95
+ # * If --exact specified, use the specified commit if it exists
96
+ # * Otherwise, if an exact match (branch, tag or SHA) exists, use that
97
+ # * Otherwise, look for a partial match
98
+
99
+ if args.exact:
100
+ commits = [branchname] if git.iscommit(branchname, remote=True) else []
101
+
102
+ logging.info(f'Exact match required: {commits}')
103
+ elif git.iscommit(branchname, remote=True):
104
+ commits = [branchname]
105
+
106
+ logging.info(f'Exact match found for {branchname}')
107
+ else:
108
+ commits = git.matching_branch(branchname)
109
+
110
+ if not commits:
111
+ commits = git.matching_commit(branchname)
112
+
113
+ logging.info('Commits matching %s = %s', branchname, commits)
114
+
115
+ # If we have one match, then we can do stuff
116
+
117
+ if len(commits) == 1:
118
+ logging.info('Only one matching commit')
119
+
120
+ commit = commits[0]
121
+
122
+ if args.update:
123
+ # TODO: Should check all remotes if more than one
124
+
125
+ remote = git.remote_names()[0]
126
+
127
+ if commit.startswith(f'{remote}/'):
128
+ remote_branch = commit
129
+ else:
130
+ remote_branch = f'remotes/{remote}/{commit}'
131
+
132
+ logging.info('Remote branch: %s', remote_branch)
133
+
134
+ # If the remote branch exists, then update, delete the local branch and re-create it
135
+
136
+ if git.isbranch(remote_branch):
137
+ logging.info('Remote branch exists')
138
+
139
+ default_branch = git.default_branch()
140
+
141
+ colour.write(f'Updating the [BLUE:{default_branch}] branch')
142
+
143
+ git.checkout(default_branch)
144
+ git.merge(f'{remote}/{default_branch}')
145
+
146
+ # If the local branch exists, delete it
147
+
148
+ # TODO: Should prompt rather than using force
149
+
150
+ if git.isbranch(commit):
151
+ logging.info('Local branch %s exists', commit)
152
+
153
+ # Don't overwrite our own branches, just to be on the safe side
154
+
155
+ if not args.force:
156
+ author = git.author(commit)
157
+ if author == git.config_get('user', 'name'):
158
+ colour.write(f'ERROR: Most recent commit on {commit} is {author} - Use the --force option to force-update your own branch!')
159
+ sys.exit(1)
160
+
161
+ colour.write('Removing existing [BLUE:%s] branch' % commit)
162
+ git.delete_branch(commit, force=True)
163
+ else:
164
+ colour.write(f'No corresponding remote branch [BLUE:{remote_branch}] exists')
165
+ return
166
+
167
+ # Check out the commit and report the name (branch, tag, or if nowt else, commit ID)
168
+
169
+ logging.info('Checking out %s', commit)
170
+
171
+ git.checkout(commit)
172
+ colour.write('[BOLD]Checked out [NORMAL][BLUE]%s[NORMAL]' % (git.branch() or git.tag() or git.current_commit()))
173
+
174
+ if args.rebase:
175
+ colour.write('Rebasing branch against its parent')
176
+
177
+ output = git.update()
178
+
179
+ for text in output:
180
+ print(text)
181
+
182
+ elif not commits:
183
+ colour.write('[BOLD]No branches or commits matching [NORMAL][BLUE]%s[NORMAL]' % branchname)
184
+ else:
185
+ colour.write('[BOLD]Multiple matches for [NORMAL][BLUE]%s[NORMAL]: %s' % (branchname, ', '.join(commits)))
186
+
187
+ ################################################################################
188
+
189
+ def main():
190
+ """ Main function - parse the command line and create or attempt to checkout
191
+ the specified branch """
192
+
193
+ args = parse_arguments()
194
+
195
+ try:
196
+ if args.branch:
197
+ git.checkout(args.branchname[0], create=True)
198
+ else:
199
+ checkout_matching_branch(args, args.branchname[0])
200
+
201
+ except git.GitError as exc:
202
+ colour.error(exc.msg, exc.status)
203
+
204
+ ################################################################################
205
+
206
+ def git_co():
207
+ """Entry point"""
208
+
209
+ try:
210
+ main()
211
+
212
+ except KeyboardInterrupt:
213
+ sys.exit(1)
214
+ except BrokenPipeError:
215
+ sys.exit(2)
216
+
217
+ ################################################################################
218
+
219
+ if __name__ == '__main__':
220
+ git_co()
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env python3
2
+
3
+ """
4
+ Report the oldest commit in common in the history of two commits
5
+ """
6
+
7
+ ################################################################################
8
+
9
+ import sys
10
+ import argparse
11
+
12
+ from skilleter_thingy import colour
13
+ from skilleter_thingy import git
14
+
15
+ ################################################################################
16
+
17
+ def main():
18
+ """ Main function """
19
+
20
+ parser = argparse.ArgumentParser(description='Find the most recent common ancestor for two commits')
21
+
22
+ parser.add_argument('--short', '-s', action='store_true', help='Just output the ancestor commit ID')
23
+ parser.add_argument('--long', '-l', action='store_true', help='Output the log entry for the commit')
24
+ parser.add_argument('commit1', nargs='?', default='HEAD', help='First commit (default=HEAD)')
25
+ parser.add_argument('commit2', nargs='?', default='master', help='Second commit (default=master)')
26
+
27
+ args = parser.parse_args()
28
+
29
+ if args.long and args.short:
30
+ colour.error('[RED:ERROR]: The [BLUE:--long] and [BLUE:--short] options cannot be used together')
31
+
32
+ try:
33
+ ancestor = git.find_common_ancestor(args.commit1, args.commit2)
34
+ except git.GitError as exc:
35
+ colour.error(f'[RED:ERROR]: {exc}', status=exc.status)
36
+
37
+ if args.short:
38
+ print(ancestor)
39
+ elif args.long:
40
+ print('\n'.join(git.log(ancestor)))
41
+ else:
42
+ colour.write(f'Last common commit between [BLUE:{args.commit1}] and [BLUE:{args.commit2}] is [BLUE:{ancestor}]')
43
+
44
+ ################################################################################
45
+ # Entry point
46
+
47
+ def git_common():
48
+ """Entry point"""
49
+
50
+ try:
51
+ main()
52
+
53
+ except KeyboardInterrupt:
54
+ sys.exit(1)
55
+ except BrokenPipeError:
56
+ sys.exit(2)
57
+
58
+ ################################################################################
59
+
60
+ if __name__ == '__main__':
61
+ git_common()
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env python3
2
+ """Archive one or more branches by tagging the branch then deleting it
3
+ The branch tag is 'archive/BRANCH_NAME'"""
4
+
5
+ import sys
6
+ import argparse
7
+ import fnmatch
8
+
9
+ from skilleter_thingy import colour
10
+ from skilleter_thingy import git
11
+
12
+ ################################################################################
13
+ # Prefix for tags representing archived branches
14
+
15
+ ARCHIVE_PREFIX = 'archive/'
16
+
17
+ ################################################################################
18
+
19
+ def archive_tag_name(branch):
20
+ """Return the tag name for an archive branch"""
21
+
22
+ return f'{ARCHIVE_PREFIX}{branch}'
23
+
24
+ ################################################################################
25
+
26
+ def archive_branch_name(tag):
27
+ """Return the branch name for an archive tag"""
28
+
29
+ if not tag.startswith(ARCHIVE_PREFIX):
30
+ raise git.GitError(f'{tag} is not an archive tag')
31
+
32
+ return tag[len(ARCHIVE_PREFIX):]
33
+
34
+ ################################################################################
35
+
36
+ def archive_tags():
37
+ """Return the list of current archive tags"""
38
+
39
+ return [tag for tag in git.tags() if tag.startswith(ARCHIVE_PREFIX)]
40
+
41
+ ################################################################################
42
+
43
+ def archive_branches(branches):
44
+ """Archive one or more branches"""
45
+
46
+ tags = archive_tags()
47
+ current_branch = git.branch()
48
+
49
+ for branch in branches:
50
+ if not git.isbranch(branch):
51
+ colour.error(f'[RED:ERROR:] Branch {branch} does not exist')
52
+
53
+ if archive_tag_name(branch) in tags:
54
+ colour.error(f'[RED:ERROR:] An archive tag already exists for branch {branch}')
55
+
56
+ if branch == current_branch:
57
+ colour.error(f'[RED:ERROR:] Cannot archive the current branch')
58
+
59
+ for branch in branches:
60
+ tag_name = archive_tag_name(branch)
61
+
62
+ git.set_tag(tag_name, branch)
63
+ git.delete_branch(branch, force=True)
64
+
65
+ for remote in git.remotes():
66
+ git.push(repository=remote, tags=True)
67
+
68
+ ################################################################################
69
+
70
+ def list_archive_branches(branches):
71
+ """List archive branches, optionally only those matching entries in the
72
+ branches parameter"""
73
+
74
+ tags = archive_tags()
75
+
76
+ if branches:
77
+ report = set()
78
+
79
+ for branch in branches:
80
+ for tag in tags:
81
+ branch_name = archive_branch_name(tag)
82
+ if branch_name not in report and fnmatch.fnmatch(branch_name, branch):
83
+ report.add(branch_name)
84
+ else:
85
+ report = set(tags)
86
+
87
+ for branch_name in sorted(report):
88
+ print(branch_name)
89
+
90
+ ################################################################################
91
+
92
+ def restore_archive_branches(branches):
93
+ """Restore archived branches"""
94
+
95
+ tags = archive_tags()
96
+
97
+ for branch in branches:
98
+ if not archive_tag_name(branch) in tags:
99
+ colour.error(f'[RED:ERROR:] Archive branch {branch} does not exist')
100
+
101
+ archive_tag_names = []
102
+
103
+ for branch in branches:
104
+ archive_tag = archive_tag_name(branch)
105
+ archive_tag_names.append(archive_tag)
106
+
107
+ git.checkout(branch, commit=archive_tag)
108
+ git.delete_tag(archive_tag)
109
+
110
+ for remote in git.remotes():
111
+ git.push(repository=remote, delete=True, refspec=archive_tag_names)
112
+
113
+ ################################################################################
114
+
115
+ def main():
116
+ """Main function"""
117
+
118
+ parser = argparse.ArgumentParser(description='Archive, list or recover one or more Git branches')
119
+ parser.add_argument('--list', '-l', action='store_true', help='List archived branches')
120
+ parser.add_argument('--restore', '-r', action='store_true', help='Restore archived branches')
121
+ parser.add_argument('branches', nargs='*', help='Branches')
122
+
123
+ args = parser.parse_args()
124
+
125
+ if args.list and args.restore:
126
+ colour.error('[RED:ERROR:] The list and restore options cannot be specified together')
127
+
128
+ if not args.branches and not args.list:
129
+ colour.error('[RED:ERROR:] No branches specified')
130
+
131
+ if args.list:
132
+ list_archive_branches(args.branches)
133
+ elif args.restore:
134
+ restore_archive_branches(args.branches)
135
+ else:
136
+ archive_branches(args.branches)
137
+
138
+ ################################################################################
139
+
140
+ def git_hold():
141
+ """Entry point"""
142
+
143
+ try:
144
+ main()
145
+
146
+ except KeyboardInterrupt:
147
+ sys.exit(1)
148
+ except BrokenPipeError:
149
+ sys.exit(2)
150
+
151
+ ################################################################################
152
+
153
+ if __name__ == '__main__':
154
+ git_hold()
@@ -0,0 +1,92 @@
1
+ #! /usr/bin/env python3
2
+
3
+ ################################################################################
4
+ """ Push to Gitlab and create a merge request at the same time """
5
+ ################################################################################
6
+
7
+ import logging
8
+ import sys
9
+ import argparse
10
+
11
+ from skilleter_thingy import git
12
+ from skilleter_thingy import colour
13
+
14
+ ################################################################################
15
+
16
+ DESCRIPTION = 'Push a feature branch to GitLab and create a merge request'
17
+
18
+ ################################################################################
19
+
20
+ def parse_arguments():
21
+ """ Parse and return command line arguments """
22
+
23
+ parser = argparse.ArgumentParser(description=DESCRIPTION, formatter_class=argparse.RawTextHelpFormatter)
24
+
25
+ parser.add_argument('--debug', action='store_true', help='Enable debug output')
26
+ parser.add_argument('-f', '--force', action='store_true', help='Force-push the branch')
27
+ parser.add_argument('--parent', '-p', action='store', help='Override the default parent and specify the branch to merge onto')
28
+ parser.add_argument('--reviewer', '-r', action='store', help='Specify the name of the reviewer for the merge request')
29
+ parser.add_argument('--keep', '-k', action='store_true', help='Keep the source branch after the merge (default is to delete it).')
30
+
31
+ args = parser.parse_args()
32
+
33
+ # Enable logging if requested
34
+
35
+ if args.debug:
36
+ logging.basicConfig(level=logging.INFO)
37
+
38
+ return args
39
+
40
+ ################################################################################
41
+
42
+ def main():
43
+ """ Main function - parse the command line and perform the pushing """
44
+
45
+ args = parse_arguments()
46
+
47
+ if args.parent:
48
+ parents = [args.parent]
49
+ else:
50
+ parents, _ = git.parents()
51
+
52
+ if len(parents) > 1:
53
+ parent_list = ', '.join(parents)
54
+ colour.error(
55
+ f'Branch has multiple potential parents: [BLUE]{parent_list}[NORMAL]. Use the [BLUE]--parent[NORMAL] option to specify the appropriate one.')
56
+ elif not parents:
57
+ colour.error('Unable to determine parent branch. Use the [BLUE]--parent[NORMAL] option to specify the appropriate one.')
58
+
59
+ options = ['merge_request.create', f'merge_request.target={parents[0]}']
60
+
61
+ if args.reviewer:
62
+ options.append(f'merge_request.assign={args.reviewer}')
63
+
64
+ if not args.keep:
65
+ options.append('merge_request.remove_source_branch')
66
+
67
+ logging.debug('Running git push with:')
68
+ logging.debug(' force: %s', args.force)
69
+ logging.debug(' push options: %s', options)
70
+
71
+ result = git.push(force_with_lease=args.force, push_options=options)
72
+
73
+ for text in result:
74
+ print(text)
75
+
76
+ ################################################################################
77
+
78
+ def git_mr():
79
+ """Entry point"""
80
+
81
+ try:
82
+ main()
83
+
84
+ except KeyboardInterrupt:
85
+ sys.exit(1)
86
+ except BrokenPipeError:
87
+ sys.exit(2)
88
+
89
+ ################################################################################
90
+
91
+ if __name__ == '__main__':
92
+ git_mr()
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env python3
2
+
3
+ """
4
+ Attempt to determine the parent branch of a commit by tracking down
5
+ the branch commit history and looking for other branches that share
6
+ the same commit. Can optionally ignore feature branches and/or report
7
+ the distance to the potential parent.
8
+ """
9
+
10
+ import argparse
11
+ import sys
12
+
13
+ from skilleter_thingy import git
14
+ from skilleter_thingy import colour
15
+
16
+ ################################################################################
17
+
18
+ def main():
19
+ """ Main function """
20
+
21
+ parser = argparse.ArgumentParser(description='Attempt to determine the parent branch for the specified branch (defaulting to the current one)')
22
+ parser.add_argument('-a', '--all', action='store_true', help='Include feature branches as possible parents')
23
+ parser.add_argument('-v', '--verbose', action='store_true', help='Report verbose results (includes number of commits between branch and parent)')
24
+ parser.add_argument('branch', action='store', nargs='?', type=str, default='HEAD', help='Branch, commit or commit')
25
+
26
+ args = parser.parse_args()
27
+
28
+ try:
29
+ if args.all:
30
+ any_parents, any_distance = git.parents(args.branch)
31
+ else:
32
+ any_parents = []
33
+
34
+ parents, distance = git.parents(args.branch, ignore='feature/*')
35
+
36
+ # If we have feature and non-feature branch candidates, decide which to report
37
+ # (one or both) based on distance.
38
+
39
+ if parents and any_parents:
40
+ if any_distance < distance:
41
+ parents = any_parents
42
+ distance = any_distance
43
+ elif any_distance == distance:
44
+ for more in any_parents:
45
+ if more not in parents:
46
+ parents.append(more)
47
+
48
+ except git.GitError as exc:
49
+ colour.error(f'[RED:ERROR:] {exc.msg}', status=exc.status)
50
+
51
+ if parents:
52
+ if args.verbose:
53
+ if len(parents) == 1:
54
+ colour.write(f'Parent branch [BLUE:{parents[0]}] is [BLUE:{distance}] commits away from [BLUE:{args.branch}]')
55
+ else:
56
+ colour.write(f'Parent branches [BLUE:%s] are [BLUE:{distance}] commits away from [BLUE:{args.branch}[' % (', '.join(parents)))
57
+ else:
58
+ print(', '.join(parents))
59
+ else:
60
+ colour.error('[RED:Could not determine parent branch]\n')
61
+
62
+ ################################################################################
63
+
64
+ def git_parent():
65
+ """Entry point"""
66
+
67
+ try:
68
+ main()
69
+ except KeyboardInterrupt:
70
+ sys.exit(1)
71
+ except BrokenPipeError:
72
+ sys.exit(2)
73
+
74
+ ################################################################################
75
+
76
+ if __name__ == '__main__':
77
+ git_parent()