6 from optparse
import OptionParser
9 from git_stats
import parse
12 """This class represents a metric
14 It is meant to store arbitrary data related to a specific metric.
23 res
= "We found that on branch %s, commit %s has a dilution of %d." % \
24 (self
.branch
, self
.commit
, self
.dilution
)
28 def prettyName(branch
):
29 """Looks up the name of a branch and returns it
31 Returns only the last part of the branchname.
34 branch: The branch to print
39 name
= git
.describe("--all", branch
)
40 splitname
= name
.split('/')
45 def _bestMetric(metrics
):
46 """Finds the best metric from a set
48 Iterates the metrics and selects the ones with the lowest dilution.
49 All the returned metrics are guaranteed to have the same dilution.
52 metrics: The metrics to pick the best ones from.
54 Returns: A list with the best metrics.
59 # Find the best metric
60 for metric
in metrics
:
61 # Store the current value for easy access
62 dilution
= metric
.dilution
64 # First element, set the minimum to the current
68 # Worse than our best, not interesting
72 # Clear the old ones if we have a better minimum
81 def _calculateDilution(target
, start
, parent_lists
):
82 """Calculates the dilution for the specified commit.
85 target: The commit to calculate the dilution for.
86 start: The initial metric information.
87 parent_list: A dictionary containing { commit : parent } pairs.
100 # We found what we are looking for
101 if target
== current
.commit
:
102 metrics
.append(current
)
105 parents
= parent_lists
[current
.commit
]
107 # Root commit, we can't go any further
111 for parent
in parents
:
112 if parent
== parents
[0]:
113 newdilution
= current
.dilution
115 newdilution
= current
.dilution
+ 1
119 next
.branch
= current
.branch
120 next
.dilution
= newdilution
123 min, champs
= _bestMetric(metrics
)
126 def belongsTo(commit
, debug
=False):
127 """Returns which branches the specified commit belongs to
130 commit: The commit to examine.
131 debug: Whether to return debug information as well.
133 Returns: A list of branches that the commit belongs to.
138 result
= git
.for_each_ref(format
="%(objectname)")
140 branches
= result
.split('\n')
142 if commit
in branches
:
143 print("Easy as pie, that's a branch head!")
144 return [prettyName(commit
)]
151 # First mine some data
152 for branch
in branches
:
153 result
= git
.log(branch
, pretty
="format:%H %P")
154 data
= result
.split('\n')
159 splitline
= item
.split(' ')
161 parents
.append(first
)
163 if len(splitline
) == 1:
164 parent_lists
[first
] = []
165 elif splitline
[1] == '':
166 parent_lists
[first
] = []
168 parent_lists
[first
] = splitline
[1:]
170 rev_lists
[branch
] = parents
172 # Early elimination, examine only those that contain the target
173 if commit
in parents
:
178 metric
.branch
= branch
179 metric
.commit
= branch
182 # Find the dilution for this branch
183 metric
= _calculateDilution(commit
, metric
, parent_lists
)
184 metrics
= metrics
+ metric
186 min, champs
= _bestMetric(metrics
)
189 results
.append("The minimal dilution is: " + str(min))
191 # Loop over all the champs and exclude any subsets
192 for metric
in champs
:
193 champlist
= rev_lists
[metric
.branch
]
195 for othermetric
in champs
:
196 # Don't compare to self
197 if metric
.branch
== othermetric
.branch
:
200 otherlist
= rev_lists
[othermetric
.branch
]
202 if set(champlist
).issubset(set(otherlist
)):
206 results
.append(metric
)
208 results
.append(prettyName(metric
.branch
))
212 def branchcontains(branch
, commit
):
213 """returns whether the specified branch contains the specified commit.
220 whether the branch contains the commit.
224 arg
= branch
+ ".." + commit
225 result
= git
.rev_list(arg
)
228 # if there is a difference between these sets, the commit is not in the branch
231 # there is no difference between the two, thus the branch contains the commit
234 def branchList(commitFilter
, includeRemotes
=False):
235 """Returns all branches that contain the specified commit
238 commitFilter: The commit to filter by.
239 includeRemotes: Whether to search remote branches as well.
250 args
.append("--contains")
251 args
.append(commitFilter
)
253 result
= git
.branch(*args
)
255 branches
= result
.split('\n')
259 for branch
in branches
:
260 result
.append(branch
[2:])
265 """Dispatches branch related commands
268 progname
= os
.path
.basename(sys
.argv
[0]) + " branch"
270 parser
= OptionParser(option_class
=parse
.GitOption
, prog
=progname
)
274 "-b", "--belongs-to",
277 help="find out which branch the specified commit belongs to")
282 help="print debug information on the found metrics")
287 help="show only branches that contain the specified commit")
292 help="include remotes in the listing")
294 parser
.set_default("debug", False)
295 parser
.set_default("remotes", False)
297 (options
, args
) = parser
.parse_args(list(args
))
299 if options
.belongs_to
:
300 result
= belongsTo(options
.belongs_to
, options
.debug
)
302 result
= branchList(commitFilter
=options
.contains
,
303 includeRemotes
=options
.remotes
)
305 print("Matching branches:")
307 for branch
in result
: