-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathgit_map.py
executable file
·167 lines (132 loc) · 4.61 KB
/
git_map.py
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
#!/usr/bin/env python3
# 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.
"""
usage: git map [-h] [--help] [<args>]
Enhances `git log --graph` view with information on commit branches + tags that
point to them. Items are colorized as follows:
* Cyan - Currently checked out branch
* Green - Local branch
* Red - Remote branches
* Magenta - Tags
* White - Merge Base Markers
* Blue background - The currently checked out commit
"""
from __future__ import unicode_literals
import os
import sys
import git_common
import setup_color
import subprocess2
from third_party import colorama
if sys.version_info.major == 2:
# On Python 3, BrokenPipeError is raised instead.
# pylint:disable=redefined-builtin
BrokenPipeError = IOError
RESET = colorama.Fore.RESET + colorama.Back.RESET + colorama.Style.RESET_ALL
BRIGHT = colorama.Style.BRIGHT
BLUE_BACK = colorama.Back.BLUE + BRIGHT
BRIGHT_RED = colorama.Fore.RED + BRIGHT
CYAN = colorama.Fore.CYAN + BRIGHT
GREEN = colorama.Fore.GREEN + BRIGHT
MAGENTA = colorama.Fore.MAGENTA + BRIGHT
RED = colorama.Fore.RED
WHITE = colorama.Fore.WHITE + BRIGHT
YELLOW = colorama.Fore.YELLOW
def _print_help(outbuf):
names = {
'Cyan': CYAN,
'Green': GREEN,
'Magenta': MAGENTA,
'Red': RED,
'White': WHITE,
'Blue background': BLUE_BACK,
}
msg = ''
for line in __doc__.splitlines():
for name, color in names.items():
if name in line:
msg += line.replace('* ' + name, color + '* ' + name + RESET) + '\n'
break
else:
msg += line + '\n'
outbuf.write(msg.encode('utf-8', 'replace'))
def _color_branch(branch, all_branches, all_tags, current):
if branch in (current, 'HEAD -> ' + current):
color = CYAN
current = None
elif branch in all_branches:
color = GREEN
all_branches.remove(branch)
elif branch in all_tags:
color = MAGENTA
elif branch.startswith('tag: '):
color = MAGENTA
branch = branch[len('tag: '):]
else:
color = RED
return color + branch + RESET
def _color_branch_list(branch_list, all_branches, all_tags, current):
if not branch_list:
return ''
colored_branches = (GREEN + ', ').join(
_color_branch(branch, all_branches, all_tags, current)
for branch in branch_list if branch != 'HEAD')
return (GREEN + '(' + colored_branches + GREEN + ') ' + RESET)
def _parse_log_line(line):
graph, branch_list, commit_date, subject = (
line.decode('utf-8', 'replace').strip().split('\x00'))
branch_list = [] if not branch_list else branch_list.split(', ')
commit = graph.split()[-1]
graph = graph[:-len(commit)]
return graph, commit, branch_list, commit_date, subject
def main(argv, outbuf):
if '-h' in argv or '--help' in argv:
_print_help(outbuf)
return 0
map_extra = git_common.get_config_list('depot_tools.map_extra')
cmd = [
git_common.GIT_EXE, 'log', git_common.root(),
'--graph', '--branches', '--tags', '--color=always', '--date=short',
'--pretty=format:%H%x00%D%x00%cd%x00%s'
] + map_extra + argv
log_proc = subprocess2.Popen(cmd, stdout=subprocess2.PIPE, shell=False)
current = git_common.current_branch()
all_tags = set(git_common.tags())
all_branches = set(git_common.branches())
if current in all_branches:
all_branches.remove(current)
merge_base_map = {}
for branch in all_branches:
merge_base = git_common.get_or_create_merge_base(branch)
if merge_base:
merge_base_map.setdefault(merge_base, set()).add(branch)
for merge_base, branches in merge_base_map.items():
merge_base_map[merge_base] = ', '.join(branches)
try:
for line in log_proc.stdout:
if b'\x00' not in line:
outbuf.write(line)
continue
graph, commit, branch_list, commit_date, subject = _parse_log_line(line)
if 'HEAD' in branch_list:
graph = graph.replace('*', BLUE_BACK + '*')
line = '{graph}{commit}\t{branches}{date} ~ {subject}'.format(
graph=graph,
commit=BRIGHT_RED + commit[:10] + RESET,
branches=_color_branch_list(
branch_list, all_branches, all_tags, current),
date=YELLOW + commit_date + RESET,
subject=subject)
if commit in merge_base_map:
line += ' <({})'.format(WHITE + merge_base_map[commit] + RESET)
line += os.linesep
outbuf.write(line.encode('utf-8', 'replace'))
except (BrokenPipeError, KeyboardInterrupt):
pass
return 0
if __name__ == '__main__':
setup_color.init()
with git_common.less() as less_input:
sys.exit(main(sys.argv[1:], less_input))