|
|
|
#!/usr/bin/env python
|
|
|
|
# Copyright 2014 The Chromium Authors. All rights reserved.
|
|
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
|
|
# found in the LICENSE file.
|
|
|
|
|
|
|
|
"""
|
|
|
|
Provides a short mapping of all the branches in your local repo, organized by
|
|
|
|
their upstream ('tracking branch') layout. Example:
|
|
|
|
|
|
|
|
origin/master
|
|
|
|
cool_feature
|
|
|
|
dependent_feature
|
|
|
|
other_dependent_feature
|
|
|
|
other_feature
|
|
|
|
|
|
|
|
Branches are colorized as follows:
|
|
|
|
* Red - a remote branch (usually the root of all local branches)
|
|
|
|
* Cyan - a local branch which is the same as HEAD
|
|
|
|
* Note that multiple branches may be Cyan, if they are all on the same
|
|
|
|
commit, and you have that commit checked out.
|
|
|
|
* Green - a local branch
|
|
|
|
* Magenta - a placeholder for the '{NO UPSTREAM}' "branch". If you have
|
|
|
|
local branches which do not track any upstream, then you will see this.
|
|
|
|
"""
|
|
|
|
import collections
|
|
|
|
import sys
|
|
|
|
|
|
|
|
from third_party import colorama
|
|
|
|
from third_party.colorama import Fore, Style
|
|
|
|
|
|
|
|
from git_common import current_branch, branches, upstream, hash_one, hash_multi
|
|
|
|
|
|
|
|
NO_UPSTREAM = '{NO UPSTREAM}'
|
|
|
|
|
|
|
|
def print_branch(cur, cur_hash, branch, branch_hashes, par_map, branch_map,
|
|
|
|
depth=0):
|
|
|
|
branch_hash = branch_hashes[branch]
|
|
|
|
if branch.startswith('origin'):
|
|
|
|
color = Fore.RED
|
|
|
|
elif branch == NO_UPSTREAM:
|
|
|
|
color = Fore.MAGENTA
|
|
|
|
elif branch_hash == cur_hash:
|
|
|
|
color = Fore.CYAN
|
|
|
|
else:
|
|
|
|
color = Fore.GREEN
|
|
|
|
|
|
|
|
if branch_hash == cur_hash:
|
|
|
|
color += Style.BRIGHT
|
|
|
|
else:
|
|
|
|
color += Style.NORMAL
|
|
|
|
|
|
|
|
suffix = ''
|
|
|
|
if cur == 'HEAD':
|
|
|
|
if branch_hash == cur_hash:
|
|
|
|
suffix = ' *'
|
|
|
|
elif branch == cur:
|
|
|
|
suffix = ' *'
|
|
|
|
|
|
|
|
print color + " "*depth + branch + suffix
|
|
|
|
for child in par_map.pop(branch, ()):
|
|
|
|
print_branch(cur, cur_hash, child, branch_hashes, par_map, branch_map,
|
|
|
|
depth=depth+1)
|
|
|
|
|
|
|
|
|
|
|
|
def main(argv):
|
|
|
|
colorama.init()
|
|
|
|
assert len(argv) == 1, "No arguments expected"
|
|
|
|
branch_map = {}
|
|
|
|
par_map = collections.defaultdict(list)
|
|
|
|
for branch in branches():
|
|
|
|
par = upstream(branch) or NO_UPSTREAM
|
|
|
|
branch_map[branch] = par
|
|
|
|
par_map[par].append(branch)
|
|
|
|
|
|
|
|
current = current_branch()
|
|
|
|
hashes = hash_multi(current, *branch_map.keys())
|
|
|
|
current_hash = hashes[0]
|
|
|
|
par_hashes = {k: hashes[i+1] for i, k in enumerate(branch_map.iterkeys())}
|
|
|
|
par_hashes[NO_UPSTREAM] = 0
|
|
|
|
while par_map:
|
|
|
|
for parent in par_map:
|
|
|
|
if parent not in branch_map:
|
|
|
|
if parent not in par_hashes:
|
|
|
|
par_hashes[parent] = hash_one(parent)
|
|
|
|
print_branch(current, current_hash, parent, par_hashes, par_map,
|
|
|
|
branch_map)
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
sys.exit(main(sys.argv))
|
|
|
|
|