skilleter-thingy 0.3.14__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.
- skilleter_thingy/__init__.py +0 -0
- skilleter_thingy/addpath.py +107 -0
- skilleter_thingy/console_colours.py +63 -0
- skilleter_thingy/ffind.py +535 -0
- skilleter_thingy/ggit.py +88 -0
- skilleter_thingy/ggrep.py +155 -0
- skilleter_thingy/git_br.py +186 -0
- skilleter_thingy/git_ca.py +147 -0
- skilleter_thingy/git_cleanup.py +297 -0
- skilleter_thingy/git_co.py +227 -0
- skilleter_thingy/git_common.py +68 -0
- skilleter_thingy/git_hold.py +162 -0
- skilleter_thingy/git_parent.py +84 -0
- skilleter_thingy/git_retag.py +67 -0
- skilleter_thingy/git_review.py +1450 -0
- skilleter_thingy/git_update.py +398 -0
- skilleter_thingy/git_wt.py +72 -0
- skilleter_thingy/gitcmp_helper.py +328 -0
- skilleter_thingy/gitprompt.py +293 -0
- skilleter_thingy/linecount.py +154 -0
- skilleter_thingy/multigit.py +915 -0
- skilleter_thingy/py_audit.py +133 -0
- skilleter_thingy/remdir.py +127 -0
- skilleter_thingy/rpylint.py +98 -0
- skilleter_thingy/strreplace.py +82 -0
- skilleter_thingy/test.py +34 -0
- skilleter_thingy/tfm.py +948 -0
- skilleter_thingy/tfparse.py +101 -0
- skilleter_thingy/trimpath.py +82 -0
- skilleter_thingy/venv_create.py +47 -0
- skilleter_thingy/venv_template.py +47 -0
- skilleter_thingy/xchmod.py +124 -0
- skilleter_thingy/yamlcheck.py +89 -0
- skilleter_thingy-0.3.14.dist-info/METADATA +606 -0
- skilleter_thingy-0.3.14.dist-info/RECORD +39 -0
- skilleter_thingy-0.3.14.dist-info/WHEEL +5 -0
- skilleter_thingy-0.3.14.dist-info/entry_points.txt +31 -0
- skilleter_thingy-0.3.14.dist-info/licenses/LICENSE +619 -0
- skilleter_thingy-0.3.14.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
#! /usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
################################################################################
|
|
4
|
+
"""Thingy 'git-update' command - update the repo and rebase one more branches
|
|
5
|
+
against their parent branch, if this can be unambiguously determined.
|
|
6
|
+
|
|
7
|
+
Author: John Skilleter
|
|
8
|
+
|
|
9
|
+
Licence: GPL v3 or later
|
|
10
|
+
|
|
11
|
+
TODO: This is a partial solution - to do things properly, we'd have to work
|
|
12
|
+
out the branch tree structure, start at the bottom, pull and/or rebase
|
|
13
|
+
each one working upwards.
|
|
14
|
+
|
|
15
|
+
As it is, I'm assuming that we don't have a tree, but a bush, with
|
|
16
|
+
most things branched off a main, master or develop branch, so we pull
|
|
17
|
+
fixed branches first then rebase everything in no particular order.
|
|
18
|
+
|
|
19
|
+
TODO: Avoid lots of pulls - should be able to fetch then updated each local branch.
|
|
20
|
+
TODO: Add option to specify name of master branch or additional names to add to the list
|
|
21
|
+
TODO: Config entry for regularly-ignored branches
|
|
22
|
+
TODO: Config entry for branches that shouldn't be rebased (main, master, release/*)
|
|
23
|
+
TODO: Command line option when using -a to skip working trees that are modified
|
|
24
|
+
"""
|
|
25
|
+
################################################################################
|
|
26
|
+
|
|
27
|
+
import os
|
|
28
|
+
import sys
|
|
29
|
+
import argparse
|
|
30
|
+
import fnmatch
|
|
31
|
+
import logging
|
|
32
|
+
|
|
33
|
+
from skilleter_modules import git
|
|
34
|
+
from skilleter_modules import colour
|
|
35
|
+
|
|
36
|
+
################################################################################
|
|
37
|
+
|
|
38
|
+
def parse_command_line():
|
|
39
|
+
"""Parse the command line"""
|
|
40
|
+
|
|
41
|
+
parser = argparse.ArgumentParser(description='Rebase branch(es) against their parent branch, updating both in the process')
|
|
42
|
+
|
|
43
|
+
parser.add_argument('--cleanup', '-c', action='store_true',
|
|
44
|
+
help='After updating a branch, delete it if there are no differences between it and its parent branch')
|
|
45
|
+
parser.add_argument('--all', '-a', action='store_true', help='Update all local branches, not just the current one')
|
|
46
|
+
parser.add_argument('--everything', '-A', action='store_true',
|
|
47
|
+
help='Update all local branches, not just the current one and ignore the default ignore list specified in the Git configuration')
|
|
48
|
+
parser.add_argument('--default', '-d', action='store_true', help='Checkout the main or master branch on completion')
|
|
49
|
+
parser.add_argument('--parent', '-p', action='store', help='Specify the parent branch, rather than trying to work it out')
|
|
50
|
+
parser.add_argument('--all-parents', '-P', action='store_true',
|
|
51
|
+
help='Feature branches are not considered as alternative parents unless this option is specified')
|
|
52
|
+
parser.add_argument('--stop', '-s', action='store_true', help='Stop if a rebase problem occurs, instead of skipping the branch')
|
|
53
|
+
parser.add_argument('--ignore', '-i', action='store', default=None,
|
|
54
|
+
help='List of one or more wildcard branch names not to attempt to update (uses update.ignore from the Git configuration if not specified)')
|
|
55
|
+
parser.add_argument('--verbose', action='store_true', help='Enable verbose output')
|
|
56
|
+
parser.add_argument('--dry-run', action='store_true', help='Report what would be done without actually doing it')
|
|
57
|
+
|
|
58
|
+
return parser.parse_args()
|
|
59
|
+
|
|
60
|
+
################################################################################
|
|
61
|
+
|
|
62
|
+
class UpdateFailure(Exception):
|
|
63
|
+
"""Exception raised when a branch fails to update"""
|
|
64
|
+
|
|
65
|
+
def __init__(self, branchname: str) -> None:
|
|
66
|
+
self.branchname = branchname
|
|
67
|
+
super().__init__()
|
|
68
|
+
|
|
69
|
+
################################################################################
|
|
70
|
+
|
|
71
|
+
def branch_rebase(args, results, branch):
|
|
72
|
+
"""Attempt to rebase a branch"""
|
|
73
|
+
|
|
74
|
+
# Either use the specified parent or try to determine the parent branch
|
|
75
|
+
|
|
76
|
+
if args.parent:
|
|
77
|
+
parent = args.parent
|
|
78
|
+
else:
|
|
79
|
+
try:
|
|
80
|
+
git.checkout(branch)
|
|
81
|
+
except git.GitError as exc:
|
|
82
|
+
colour.error(exc.msg)
|
|
83
|
+
sys.exit(1)
|
|
84
|
+
|
|
85
|
+
# Ignore feature branches as potential alternative parents unless told otherwise
|
|
86
|
+
# If they are the only possible parent(s) then we still consider them.
|
|
87
|
+
|
|
88
|
+
if args.all_parents:
|
|
89
|
+
parents, _ = git.parents()
|
|
90
|
+
else:
|
|
91
|
+
parents, _ = git.parents(ignore='feature/*')
|
|
92
|
+
|
|
93
|
+
logging.debug('Probable parents of %s: %s', branch, parents)
|
|
94
|
+
|
|
95
|
+
if not parents:
|
|
96
|
+
parents, _ = git.parents()
|
|
97
|
+
|
|
98
|
+
logging.debug('No non-feature-branch parents found for %s. Feature branch parents could be: %s', branch, parents)
|
|
99
|
+
|
|
100
|
+
if not parents:
|
|
101
|
+
colour.write(f'[RED:WARNING]: Unable to rebase [BLUE:{branch}] branch as unable to determine its parent (no obvious candidates))', indent=4)
|
|
102
|
+
results['failed'].add(branch)
|
|
103
|
+
return
|
|
104
|
+
|
|
105
|
+
# Cheat - if we have multiple possible parents and one is 'develop', 'main' or 'master'
|
|
106
|
+
# choose it.
|
|
107
|
+
|
|
108
|
+
if len(parents) > 1:
|
|
109
|
+
if 'master' in parents:
|
|
110
|
+
parent = 'master'
|
|
111
|
+
if 'main' in parents:
|
|
112
|
+
parent = 'main'
|
|
113
|
+
elif 'develop' in parents:
|
|
114
|
+
parent = 'develop'
|
|
115
|
+
elif 'scv-poc' in parents:
|
|
116
|
+
parent = 'scv-poc'
|
|
117
|
+
else:
|
|
118
|
+
colour.write(f'[RED:WARNING]: Unable to rebase [BLUE:{branch}] branch as unable to determine its parent (could be any of {", ".join(parents)})',
|
|
119
|
+
indent=4)
|
|
120
|
+
results['failed'].add(branch)
|
|
121
|
+
return
|
|
122
|
+
|
|
123
|
+
elif len(parents) == 1:
|
|
124
|
+
parent = parents[0]
|
|
125
|
+
|
|
126
|
+
if args.dry_run:
|
|
127
|
+
colour.write(f'[BOLD:Checking if] [BLUE:{branch}] [BOLD:needs to be rebased onto] [BLUE:{parent}]', indent=4)
|
|
128
|
+
|
|
129
|
+
else:
|
|
130
|
+
if parent not in results['pulled'] and parent not in results['unchanged']:
|
|
131
|
+
colour.write(f'[BOLD:Updating] [BLUE:{parent}]')
|
|
132
|
+
|
|
133
|
+
if not branch_pull(args, results, parent):
|
|
134
|
+
return
|
|
135
|
+
|
|
136
|
+
if branch not in results['pulled']:
|
|
137
|
+
if git.iscommit(branch, remote_only=True):
|
|
138
|
+
colour.write(f'[BOLD:Updating] [BLUE:{branch}]')
|
|
139
|
+
|
|
140
|
+
branch_pull(args, results, branch)
|
|
141
|
+
else:
|
|
142
|
+
results['no-tracking'].add(branch)
|
|
143
|
+
|
|
144
|
+
if git.rebase_required(branch, parent):
|
|
145
|
+
colour.write(f'Rebasing [BLUE:{branch}] [BOLD:onto] [BLUE:{parent}]', indent=4)
|
|
146
|
+
|
|
147
|
+
git.checkout(branch)
|
|
148
|
+
output, status = git.rebase(parent)
|
|
149
|
+
|
|
150
|
+
if status:
|
|
151
|
+
colour.write(f'[RED:WARNING]: Unable to rebase [BLUE:{branch}] onto [BLUE:{parent}]', indent=4)
|
|
152
|
+
|
|
153
|
+
if args.verbose:
|
|
154
|
+
colour.write(output)
|
|
155
|
+
|
|
156
|
+
results['failed'].add(branch)
|
|
157
|
+
|
|
158
|
+
if args.stop:
|
|
159
|
+
raise UpdateFailure(branch)
|
|
160
|
+
|
|
161
|
+
git.abort_rebase()
|
|
162
|
+
return
|
|
163
|
+
|
|
164
|
+
results['rebased'].add(branch)
|
|
165
|
+
else:
|
|
166
|
+
colour.write(f'[BLUE:{branch}] is already up-to-date on parent branch [BLUE:{parent}]', indent=4)
|
|
167
|
+
|
|
168
|
+
results['unchanged'].add(branch)
|
|
169
|
+
|
|
170
|
+
if args.cleanup:
|
|
171
|
+
if args.dry_run:
|
|
172
|
+
colour.write(f'[GREEN:Dry-run: Checking to see if {branch} and {parent} are the same - deleting {branch} if they are]', indent=4)
|
|
173
|
+
|
|
174
|
+
elif git.diff_status(branch, parent):
|
|
175
|
+
git.checkout(parent)
|
|
176
|
+
git.delete_branch(branch, force=True)
|
|
177
|
+
|
|
178
|
+
results['deleted'].add(branch)
|
|
179
|
+
|
|
180
|
+
colour.write(f'Deleted branch [BLUE:{branch}] as it is not different to its parent branch ([BLUE:{parent}])', indent=4)
|
|
181
|
+
|
|
182
|
+
################################################################################
|
|
183
|
+
|
|
184
|
+
def branch_pull(args, results, branch, fail=True):
|
|
185
|
+
"""Attempt to update a branch, logging any failure except no remote tracking branch
|
|
186
|
+
unless fail is False"""
|
|
187
|
+
|
|
188
|
+
colour.write(f'Pulling updates for the [BLUE:{branch}] branch', indent=4)
|
|
189
|
+
|
|
190
|
+
if not args.dry_run:
|
|
191
|
+
if branch not in results['pulled'] and branch not in results['unchanged']:
|
|
192
|
+
try:
|
|
193
|
+
git.checkout(branch)
|
|
194
|
+
output = git.pull()
|
|
195
|
+
|
|
196
|
+
colour.write(output, indent=4)
|
|
197
|
+
|
|
198
|
+
if output[0] == 'Already up-to-date.':
|
|
199
|
+
results['unchanged'].add(branch)
|
|
200
|
+
|
|
201
|
+
results['pulled'].add(branch)
|
|
202
|
+
|
|
203
|
+
except git.GitError as exc:
|
|
204
|
+
if exc.msg.startswith('There is no tracking information for the current branch.'):
|
|
205
|
+
colour.write(f'[RED:WARNING]: There is no tracking information for the [BLUE:{branch}] branch.', indent=4)
|
|
206
|
+
fail = False
|
|
207
|
+
|
|
208
|
+
elif exc.msg.startswith('Your configuration specifies to merge with the ref'):
|
|
209
|
+
colour.write('[RED:WARNING]: The upstream branch no longer exists', indent=4)
|
|
210
|
+
fail = False
|
|
211
|
+
|
|
212
|
+
elif 'no such ref was fetched' in exc.msg:
|
|
213
|
+
colour.write(f'[RED:WARNING]: {exc.msg}', indent=4)
|
|
214
|
+
|
|
215
|
+
else:
|
|
216
|
+
colour.write(f'[RED:ERROR]: Unable to merge upstream changes onto [BLUE:{branch}] branch.', indent=4)
|
|
217
|
+
|
|
218
|
+
if git.merging():
|
|
219
|
+
git.abort_merge()
|
|
220
|
+
elif git.rebasing():
|
|
221
|
+
git.abort_rebase()
|
|
222
|
+
|
|
223
|
+
if fail:
|
|
224
|
+
results['failed'].add(branch)
|
|
225
|
+
|
|
226
|
+
return False
|
|
227
|
+
|
|
228
|
+
return True
|
|
229
|
+
|
|
230
|
+
################################################################################
|
|
231
|
+
|
|
232
|
+
def fixed_branch(branch):
|
|
233
|
+
"""Return True if a branch is 'fixed' (master, develop, release, etc.)
|
|
234
|
+
and shouldn't be rebased automatically"""
|
|
235
|
+
|
|
236
|
+
return branch.startswith(('release/', 'hotfix/')) or \
|
|
237
|
+
branch in ('master', 'main', 'develop') or \
|
|
238
|
+
'/PoC-' in branch
|
|
239
|
+
|
|
240
|
+
################################################################################
|
|
241
|
+
|
|
242
|
+
def report_branches(msg, branches):
|
|
243
|
+
"""Report a list of branches with a message"""
|
|
244
|
+
|
|
245
|
+
colour.write(newline=True)
|
|
246
|
+
colour.write(msg)
|
|
247
|
+
|
|
248
|
+
for branch in branches:
|
|
249
|
+
colour.write(f'[BLUE:{branch}]', indent=4)
|
|
250
|
+
|
|
251
|
+
################################################################################
|
|
252
|
+
|
|
253
|
+
def main():
|
|
254
|
+
"""Entry point"""
|
|
255
|
+
|
|
256
|
+
# Handle the command line
|
|
257
|
+
|
|
258
|
+
args = parse_command_line()
|
|
259
|
+
|
|
260
|
+
# Enable logging if requested
|
|
261
|
+
|
|
262
|
+
if args.verbose:
|
|
263
|
+
logging.basicConfig(level=logging.DEBUG)
|
|
264
|
+
|
|
265
|
+
# Check we are in the right place
|
|
266
|
+
|
|
267
|
+
if not git.working_tree():
|
|
268
|
+
colour.error('Not in a git repo')
|
|
269
|
+
|
|
270
|
+
# Set the default ignore list if none specified and if not using the '-A' option
|
|
271
|
+
|
|
272
|
+
if args.ignore is None and not args.everything:
|
|
273
|
+
args.ignore = git.config_get('update', 'ignore')
|
|
274
|
+
|
|
275
|
+
args.ignore = args.ignore.split(',') if args.ignore else []
|
|
276
|
+
|
|
277
|
+
logging.info('Ignore list: %s', ', '.join(args.ignore))
|
|
278
|
+
|
|
279
|
+
# Make sure we've got no locally-modified files
|
|
280
|
+
|
|
281
|
+
status = git.status_info(ignored=True)
|
|
282
|
+
|
|
283
|
+
for entry in status:
|
|
284
|
+
if status[entry][1] == 'M':
|
|
285
|
+
colour.error('You have unstaged changes - cannot update.')
|
|
286
|
+
|
|
287
|
+
# Get the current branch
|
|
288
|
+
|
|
289
|
+
current_branch = git.branch()
|
|
290
|
+
|
|
291
|
+
if not current_branch:
|
|
292
|
+
colour.error('No branch currently checked out - cannot update.')
|
|
293
|
+
|
|
294
|
+
colour.write(f'[BOLD:Current branch:] [BLUE:{current_branch}]')
|
|
295
|
+
|
|
296
|
+
# Switch the current directory in case it vanishes when we switch branches
|
|
297
|
+
|
|
298
|
+
os.chdir(git.working_tree())
|
|
299
|
+
|
|
300
|
+
# Optionally pull or rebase everything - pull things first, then rebase
|
|
301
|
+
# the rest.
|
|
302
|
+
|
|
303
|
+
branches = git.branches() if args.all or args.everything else [current_branch]
|
|
304
|
+
|
|
305
|
+
logging.info('Updating %s', ', '.join(branches))
|
|
306
|
+
|
|
307
|
+
# Filter out branches that the user wants to ignore
|
|
308
|
+
|
|
309
|
+
if args.ignore:
|
|
310
|
+
for ignore in args.ignore:
|
|
311
|
+
for name in branches[:]:
|
|
312
|
+
if fnmatch.fnmatch(name, ignore) and name in branches:
|
|
313
|
+
branches.remove(name)
|
|
314
|
+
|
|
315
|
+
if not branches:
|
|
316
|
+
colour.error('No matching branches to update')
|
|
317
|
+
|
|
318
|
+
# List of stuff that's been done, to report in the summary
|
|
319
|
+
|
|
320
|
+
results = {'deleted': set(), 'pulled': set(), 'failed': set(), 'rebased': set(), 'unchanged': set(), 'no-tracking': set()}
|
|
321
|
+
|
|
322
|
+
to_rebase = set()
|
|
323
|
+
|
|
324
|
+
try:
|
|
325
|
+
for branch in branches:
|
|
326
|
+
if fixed_branch(branch):
|
|
327
|
+
branch_pull(args, results, branch)
|
|
328
|
+
else:
|
|
329
|
+
to_rebase.add(branch)
|
|
330
|
+
|
|
331
|
+
for branch in to_rebase:
|
|
332
|
+
branch_rebase(args, results, branch)
|
|
333
|
+
|
|
334
|
+
# Return to the original branch if it still exists or the master
|
|
335
|
+
|
|
336
|
+
all_branches = git.branches()
|
|
337
|
+
|
|
338
|
+
return_branch = current_branch if current_branch in all_branches \
|
|
339
|
+
else 'develop' if 'develop' in all_branches \
|
|
340
|
+
else 'main' if 'main' in all_branches \
|
|
341
|
+
else 'master' if 'master' in all_branches else None
|
|
342
|
+
|
|
343
|
+
if return_branch:
|
|
344
|
+
colour.write('')
|
|
345
|
+
colour.write(f'[BOLD]Checking out the [BLUE:{return_branch}] [BOLD:branch]')
|
|
346
|
+
|
|
347
|
+
if not args.dry_run:
|
|
348
|
+
git.checkout(return_branch)
|
|
349
|
+
|
|
350
|
+
except UpdateFailure as exc:
|
|
351
|
+
update_failed = exc.branchname
|
|
352
|
+
|
|
353
|
+
else:
|
|
354
|
+
update_failed = None
|
|
355
|
+
|
|
356
|
+
for entry in ('rebased', 'unchanged', 'pulled', 'failed', 'no-tracking'):
|
|
357
|
+
results[entry] -= results['deleted']
|
|
358
|
+
|
|
359
|
+
results['pulled'] -= results['unchanged']
|
|
360
|
+
|
|
361
|
+
if results['rebased']:
|
|
362
|
+
report_branches('[BOLD:The following branches have been rebased:]', results['rebased'])
|
|
363
|
+
|
|
364
|
+
if results['unchanged']:
|
|
365
|
+
report_branches('[BOLD:The following branches were already up-to-date:]', results['unchanged'])
|
|
366
|
+
|
|
367
|
+
if results['pulled']:
|
|
368
|
+
report_branches('[BOLD:The following branches have been updated:]', results['pulled'])
|
|
369
|
+
|
|
370
|
+
if results['deleted']:
|
|
371
|
+
report_branches('[BOLD:The following branches have been deleted:]', results['deleted'])
|
|
372
|
+
|
|
373
|
+
if results['failed']:
|
|
374
|
+
report_branches('[RED:WARNING:] [BOLD:The following branches failed to update:]', results['failed'])
|
|
375
|
+
|
|
376
|
+
if results['no-tracking']:
|
|
377
|
+
report_branches('[YELLOW:NOTE:] [BOLD:The following branches have been rebased, but no upstream branch exists]', results['no-tracking'])
|
|
378
|
+
|
|
379
|
+
if update_failed:
|
|
380
|
+
colour.write('')
|
|
381
|
+
colour.write(f'Halted during failed rebase of branch [BLUE:{update_failed}]')
|
|
382
|
+
|
|
383
|
+
################################################################################
|
|
384
|
+
|
|
385
|
+
def git_update():
|
|
386
|
+
"""Entry point"""
|
|
387
|
+
|
|
388
|
+
try:
|
|
389
|
+
main()
|
|
390
|
+
except KeyboardInterrupt:
|
|
391
|
+
sys.exit(1)
|
|
392
|
+
except BrokenPipeError:
|
|
393
|
+
sys.exit(2)
|
|
394
|
+
|
|
395
|
+
################################################################################
|
|
396
|
+
|
|
397
|
+
if __name__ == '__main__':
|
|
398
|
+
git_update()
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#! /usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
################################################################################
|
|
4
|
+
""" Output the top level directory of the git working tree or return
|
|
5
|
+
an error if we are not in a git working tree.
|
|
6
|
+
|
|
7
|
+
Copyright (C) 2017, 2018 John Skilleter
|
|
8
|
+
|
|
9
|
+
Licence: GPL v3 or later
|
|
10
|
+
"""
|
|
11
|
+
################################################################################
|
|
12
|
+
|
|
13
|
+
import sys
|
|
14
|
+
import argparse
|
|
15
|
+
import os
|
|
16
|
+
|
|
17
|
+
from skilleter_modules import git
|
|
18
|
+
from skilleter_modules import colour
|
|
19
|
+
|
|
20
|
+
################################################################################
|
|
21
|
+
|
|
22
|
+
def main():
|
|
23
|
+
""" Main function """
|
|
24
|
+
|
|
25
|
+
# Command line parameters
|
|
26
|
+
|
|
27
|
+
parser = argparse.ArgumentParser(description='Report top-level directory of the current git working tree.')
|
|
28
|
+
parser.add_argument('--parent', '-p', action='store_true',
|
|
29
|
+
help='If we are already at the top of the working tree, check if the parent directory is in a working tree and output the top-level directory of that tree.')
|
|
30
|
+
parser.add_argument('--dir', '-d', action='store', default=None,
|
|
31
|
+
help='Find the location of the top-level directory in the working tree starting at the specified directory')
|
|
32
|
+
|
|
33
|
+
args = parser.parse_args()
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
start_dir = os.path.abspath(args.dir or os.getcwd())
|
|
37
|
+
except FileNotFoundError:
|
|
38
|
+
sys.stderr.write('Unable to determine initial directory\n')
|
|
39
|
+
sys.exit(1)
|
|
40
|
+
|
|
41
|
+
# Search for a .git directory in the current or parent directories
|
|
42
|
+
|
|
43
|
+
working_tree = git.working_tree(start_dir)
|
|
44
|
+
|
|
45
|
+
# If we are in a working tree and also looking for the parent working
|
|
46
|
+
# tree, check if we are at the top of the current tree, and, if so,
|
|
47
|
+
# hop up a level and try again.
|
|
48
|
+
|
|
49
|
+
if args.parent and working_tree == start_dir:
|
|
50
|
+
working_tree = git.working_tree(os.path.join(working_tree, os.pardir))
|
|
51
|
+
|
|
52
|
+
if working_tree:
|
|
53
|
+
print(working_tree)
|
|
54
|
+
|
|
55
|
+
################################################################################
|
|
56
|
+
|
|
57
|
+
def git_wt():
|
|
58
|
+
"""Entry point"""
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
main()
|
|
62
|
+
except KeyboardInterrupt:
|
|
63
|
+
sys.exit(1)
|
|
64
|
+
except BrokenPipeError:
|
|
65
|
+
sys.exit(2)
|
|
66
|
+
except git.GitError as exc:
|
|
67
|
+
colour.error(exc.msg, status=exc.status, prefix=True)
|
|
68
|
+
|
|
69
|
+
################################################################################
|
|
70
|
+
|
|
71
|
+
if __name__ == '__main__':
|
|
72
|
+
git_wt()
|