gitstats: Use Repo(".").git instead of Git(".")
[git-stats.git] / src / git_stats / branch.py
bloba0734ab182452b9d4c5b842b0ba999c2263af9c8
1 #!/usr/bin/env python
3 import os
4 import sys
6 from optparse import OptionParser
7 from git import Repo
9 from git_stats import parse
11 def belongsTo(commit):
12 """
13 """
15 git = Repo(".").git
17 result = git.for_each_ref("refs/heads", format="%(objectname)")
19 branches = result.split('\n')
21 if commit in branches:
22 print("Easy as pie, that's a branch head!")
23 return
25 results = {}
26 rev_lists = {}
28 for branch in branches:
29 result = git.rev_list(branch)
30 commits = result.split('\n')
32 # No need to keep going if the commit is not part of this branch
33 if not commit in commits:
34 continue
36 result = git.rev_list("--no-merges", branch)
37 no_merges = result.split('\n')
39 # Make the ommits into a set
40 commits = set(commits)
41 no_merges = set(no_merges)
43 # Store all commits for later use
44 rev_lists[branch] = commits
46 # The merges are 'all_commits - no_merges'
47 merges = commits.difference(no_merges)
49 dilution = 0
51 # Check all the merges to see if they diluted this branch
52 for merge in merges:
53 result = git.cat_file("-p", merge)
54 log = result.split('\n')
56 # We really only have to check the first parent
57 # If it's not in there, it is a dilution (for this branch at least)
58 for line in log:
59 if not line.startswith("parent "):
60 continue
62 parent = line[7:]
63 break
65 result = git.rev_list(parent)
66 children = result.split('\n')
68 # Diluted iff the commit is not a child of the primary parent
69 if not commit in children:
70 dilution += 1
72 results[branch] = dilution
74 print(results)
76 min = -1
77 champs = []
79 for branch in results.iteritems():
80 if min == -1:
81 min = branch[1]
83 if branch[1] > min:
84 continue
86 # Clear the old ones if we have a better set
87 if branch[1] < min:
88 champs = []
89 min = branch[1]
91 champs.append(branch[0])
93 result = []
95 # Loop over all the champs and exclude any subsets
96 for champ in champs:
97 champlist = rev_lists[champ]
98 for otherchamp in champs:
99 # Don't compare to self
100 if champ == otherchamp:
101 continue
103 otherlist = rev_lists[otherchamp]
104 if champlist.issubset(otherlist):
105 break
106 else:
107 result.append(champ)
109 print(result)
112 def branchcontains(branch, commit):
113 """returns whether the specified branch contains the specified commit.
115 params:
116 branch: the branch.
117 commit: the commit.
119 returns:
120 whether the branch contains the commit.
123 git = git(".")
124 arg = branch + ".." + commit
125 result = git.rev_list(arg)
127 if result:
128 # if there is a difference between these sets, the commit is not in the branch
129 return false
130 else:
131 # there is no difference between the two, thus the branch contains the commit
132 return true
134 def branchList(commitFilter, includeRemotes=False):
138 git = Repo(".").git
140 args = []
142 if includeRemotes:
143 args.append("-a")
145 if commitFilter:
146 args.append("--contains")
147 args.append(commitFilter)
149 result = git.branch(*args)
151 branches = result.split('\n')
153 result = []
155 for branch in branches:
156 result.append(branch[2:])
158 return result
160 def dispatch(*args):
161 """Dispatches branch related commands
164 progname = os.path.basename(sys.argv[0]) + " branch"
166 parser = OptionParser(option_class=parse.GitOption, prog=progname)
169 parser.add_option(
170 "-b", "--belongs-to",
171 type="commit",
172 metavar="COMMIT",
173 help="find out which branch the specified commit belongs to")
175 parser.add_option(
176 "-c", "--contains",
177 type="commit",
178 help="show only branches that contain the specified commit")
180 parser.add_option(
181 "-r", "--remotes",
182 action="store_true",
183 help="include remotes in the listing")
185 (options, args) = parser.parse_args(list(args))
187 if options.belongs_to:
188 result = belongsTo(options.belongs_to)
189 else:
190 result = branchList(commitFilter=options.contains,
191 includeRemotes=options.remotes)
193 print("Matching branches:")
195 for branch in result:
196 print(branch)