-
Notifications
You must be signed in to change notification settings - Fork 3
/
git-clean-branches
executable file
·171 lines (125 loc) · 4.62 KB
/
git-clean-branches
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#!/usr/bin/env python3
import argparse
import re
import subprocess
from sys import exit
parser = argparse.ArgumentParser(
description="Remove local branches, which are no longer available in the remote"
)
parser.add_argument("--prune", action="store_true", help="Remove branches")
parser.add_argument("--force", action="store_true", help="Force deletion")
parser.add_argument("--remote", default="origin", help="Remote name (default: origin)")
parser.add_argument("--verbose", action="store_true", help="Verbose output")
args = parser.parse_args()
def find_local_branches():
branches = subprocess.check_output(["git", "branch"]).decode("utf-8")
correct_branches = []
for line in branches.splitlines():
# take out the active branch, we are only intersted in the name of the
# branch
branch_name = re.sub(r"\*", "", line).strip()
# find out what is the remote of the branch
try:
remoteName = subprocess.check_output(
["git", "config", "--get", "branch.%s.remote" % branch_name]
).decode("utf-8")
except Exception as e:
# Branch has no config"
remoteName = ""
remoteName = remoteName.strip()
if "%s" % remoteName == args.remote:
correct_branches.append(branch_name)
return correct_branches
def find_remote_branches():
branches = subprocess.check_output(["git", "branch", "-r"]).decode("utf-8")
correct_branches = []
for line in branches.splitlines():
branch_name = line.strip()
result = re.search(r"%s/([^\s]*)" % args.remote, branch_name)
if result:
correct_branches.append(result.group(1))
return correct_branches
def find_live_branches():
correct_branches = []
try:
branches = subprocess.check_output(
["git", "ls-remote", "-h", args.remote]
).decode("utf-8")
except Exception as e:
# TODO: test that this is error 128
return None
for line in branches.splitlines():
branch_name = line.strip()
result = re.search(r"refs/heads/([^\s]*)", branch_name)
if result:
correct_branches.append(result.group(1))
return correct_branches
def delete_branches(branches):
broken = []
if not branches:
print("No removed branches found")
return
if not args.prune:
print("Found removed branches:")
for branch_name in branches:
if args.prune:
if args.verbose:
print("Removing %s" % branch_name)
if args.force:
deleteFlag = "-D"
else:
deleteFlag = "-d"
return_code = subprocess.call(
["git", "branch", deleteFlag, branch_name], stderr=subprocess.DEVNULL
)
if return_code != 0:
if args.verbose:
print("ERROR: Unable to remove branch")
broken.append(branch_name)
else:
print(" - %s" % branch_name)
if broken:
print("Not all branches are removed (try --force):")
for branch_name in broken:
print(" - %s" % branch_name)
elif args.prune:
pass
else:
print("INFO: To remove all found branches use --prune flag")
def analyze_live_and_remote(live_branches, remote_branches):
if live_branches == None:
return remote_branches
notFound = []
for branch_name in remote_branches:
if branch_name != "HEAD":
try:
index = live_branches.index(branch_name)
except ValueError:
notFound.append(branch_name)
if notFound:
print('WARNING: Your git repository is outdated, please run "git fetch -p"')
print(" Following branches are not pruned:")
for name in notFound:
print(" - %s" % name)
return live_branches
def find_to_remove(local=[], remote=[]):
will_remove = []
for branch_name in local_branches:
try:
index = remote_branches.index(branch_name)
except ValueError:
will_remove.append(branch_name)
return will_remove
try:
subprocess.check_output(["git", "rev-parse", "--show-toplevel"])
except Exception:
exit(1)
# walk through the local branches
# if local branch is not in remote branch list
# prepare for removing
remote_branches = find_remote_branches()
local_branches = find_local_branches()
live_branches = find_live_branches()
remote_branches = analyze_live_and_remote(live_branches, remote_branches)
to_remove = find_to_remove(local=local_branches, remote=remote_branches)
delete_branches(to_remove)