"""
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
"""
import os
import sys
import gclient_utils
import git_common
import setup_color
import subprocess2
import from_third_party
colorama = from_third_party.import_module("colorama")
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
if gclient_utils.IsEnvCog():
print(
"map command is not supported in non-git environment.",
file=sys.stderr,
)
return 1
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))