blob: 73517903c2a3096e031201fe656f7e4bf68945c8 [file] [log] [blame]
iannucci@chromium.org8bc9b5c2014-03-12 01:36:18 +00001#!/usr/bin/env python
iannucci@chromium.orga112f032014-03-13 07:47:50 +00002# Copyright 2014 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
iannucci@chromium.org8bc9b5c2014-03-12 01:36:18 +00006"""
7Provides a short mapping of all the branches in your local repo, organized by
8their upstream ('tracking branch') layout. Example:
9
10origin/master
11 cool_feature
12 dependent_feature
13 other_dependent_feature
14 other_feature
15
16Branches are colorized as follows:
17 * Red - a remote branch (usually the root of all local branches)
18 * Cyan - a local branch which is the same as HEAD
19 * Note that multiple branches may be Cyan, if they are all on the same
20 commit, and you have that commit checked out.
21 * Green - a local branch
iannucci@chromium.orgc050a5b2014-03-26 06:18:50 +000022 * Magenta - a tag
23 * Magenta '{NO UPSTREAM}' - If you have local branches which do not track any
24 upstream, then you will see this.
iannucci@chromium.org8bc9b5c2014-03-12 01:36:18 +000025"""
iannucci@chromium.orgc050a5b2014-03-26 06:18:50 +000026
iannucci@chromium.org8bc9b5c2014-03-12 01:36:18 +000027import collections
28import sys
29
30from third_party import colorama
31from third_party.colorama import Fore, Style
32
33from git_common import current_branch, branches, upstream, hash_one, hash_multi
iannucci@chromium.orgc050a5b2014-03-26 06:18:50 +000034from git_common import tags
iannucci@chromium.org8bc9b5c2014-03-12 01:36:18 +000035
36NO_UPSTREAM = '{NO UPSTREAM}'
37
iannucci@chromium.orgc050a5b2014-03-26 06:18:50 +000038def color_for_branch(branch, branch_hash, cur_hash, tag_set):
iannucci@chromium.org8bc9b5c2014-03-12 01:36:18 +000039 if branch.startswith('origin'):
40 color = Fore.RED
iannucci@chromium.orgc050a5b2014-03-26 06:18:50 +000041 elif branch == NO_UPSTREAM or branch in tag_set:
iannucci@chromium.org8bc9b5c2014-03-12 01:36:18 +000042 color = Fore.MAGENTA
43 elif branch_hash == cur_hash:
44 color = Fore.CYAN
45 else:
46 color = Fore.GREEN
47
48 if branch_hash == cur_hash:
49 color += Style.BRIGHT
50 else:
51 color += Style.NORMAL
52
iannucci@chromium.orgc050a5b2014-03-26 06:18:50 +000053 return color
54
55
56def print_branch(cur, cur_hash, branch, branch_hashes, par_map, branch_map,
57 tag_set, depth=0):
58 branch_hash = branch_hashes[branch]
59
60 color = color_for_branch(branch, branch_hash, cur_hash, tag_set)
61
iannucci@chromium.orga112f032014-03-13 07:47:50 +000062 suffix = ''
63 if cur == 'HEAD':
64 if branch_hash == cur_hash:
65 suffix = ' *'
66 elif branch == cur:
67 suffix = ' *'
68
69 print color + " "*depth + branch + suffix
iannucci@chromium.org8bc9b5c2014-03-12 01:36:18 +000070 for child in par_map.pop(branch, ()):
71 print_branch(cur, cur_hash, child, branch_hashes, par_map, branch_map,
iannucci@chromium.orgc050a5b2014-03-26 06:18:50 +000072 tag_set, depth=depth+1)
iannucci@chromium.org8bc9b5c2014-03-12 01:36:18 +000073
74
75def main(argv):
76 colorama.init()
77 assert len(argv) == 1, "No arguments expected"
78 branch_map = {}
79 par_map = collections.defaultdict(list)
80 for branch in branches():
81 par = upstream(branch) or NO_UPSTREAM
82 branch_map[branch] = par
83 par_map[par].append(branch)
84
85 current = current_branch()
86 hashes = hash_multi(current, *branch_map.keys())
87 current_hash = hashes[0]
88 par_hashes = {k: hashes[i+1] for i, k in enumerate(branch_map.iterkeys())}
89 par_hashes[NO_UPSTREAM] = 0
iannucci@chromium.orgc050a5b2014-03-26 06:18:50 +000090 tag_set = tags()
iannucci@chromium.org8bc9b5c2014-03-12 01:36:18 +000091 while par_map:
92 for parent in par_map:
93 if parent not in branch_map:
94 if parent not in par_hashes:
95 par_hashes[parent] = hash_one(parent)
96 print_branch(current, current_hash, parent, par_hashes, par_map,
iannucci@chromium.orgc050a5b2014-03-26 06:18:50 +000097 branch_map, tag_set)
iannucci@chromium.org8bc9b5c2014-03-12 01:36:18 +000098 break
99
100
101if __name__ == '__main__':
102 sys.exit(main(sys.argv))
103