Repository navigation
Expand file tree
/
Copy pathgit-lg
More file actions
executable file
·115 lines (102 loc) · 3.74 KB
/
Copy pathgit-lg
File metadata and controls
executable file
·115 lines (102 loc) · 3.74 KB
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
#!/bin/bash -e
# Git script for printing beautiful logs.
if echo "$*" | grep -Eq -- '--help\b|-h\b'; then
echo "usage: ${0##*/} [-h|--help] [ARGS]" 1>&2
echo "Forwards any additional ARGS to the git log command." 1>&2
exit 1
fi
HASH='%C(red)%h%C(reset)'
DATE='%C(green)(%cr)%C(reset)'
AUTHOR='%C(bold blue)<%an>%C(reset)'
REFS='%C(yellow)%d%C(reset)'
MESSAGE='%s'
# Unit separator: can't appear in a hash, date, author name, ref name or subject,
# so it never collides with the content it delimits.
DELIM=$'\037'
# tput fails when stdout isn't a tty, which -e would turn into an early exit.
TERM_WIDTH="$(tput cols 2>/dev/null || echo 80)"
MAX_HASH_WIDTH="$((TERM_WIDTH / 4))"
make_log() {
git log \
--date=relative \
--graph \
--pretty="tformat:$HASH$DELIM$DATE$DELIM$AUTHOR$DELIM$REFS $MESSAGE" \
"$@"
}
# Align the leading columns, padding to the widest value in each one.
#
# This replaces column(1), which on macOS refuses any line longer than 2048
# bytes ("line too long") and then mangles the rest of the table along with it.
# A single commit carrying a lot of tags is enough to blow past that.
#
# Widths are measured with the ANSI escapes stripped, so columns line up by what
# is actually on screen rather than by escape-sequence bytes.
#
# If the first column comes out wider than MAX_HASH_WIDTH -- a deep --graph
# prefix, say -- fall back to single-space separation rather than aligning.
columnize() {
awk -v delim="$DELIM" -v max_width="$MAX_HASH_WIDTH" '
function visible_width(s) {
gsub(/\033\[[0-9;]*m/, "", s)
return length(s)
}
# Split on at most the first FIELDS-1 delimiters, so that a delimiter in
# the trailing field is left alone rather than becoming a new column.
function split_fields(s, out, n, p) {
n = 0
while (n < FIELDS - 1) {
p = index(s, delim)
if (p == 0) break
out[++n] = substr(s, 1, p - 1)
s = substr(s, p + length(delim))
}
out[++n] = s
return n
}
BEGIN {
FIELDS = 4 # hash, date, author, then refs and subject together
GAP = 2
BLANKS = sprintf("%256s", "")
}
{
lines[NR] = $0
n = split_fields($0, field)
# The trailing field is never padded, so it needs no width.
for (i = 1; i < n; i++) {
w = visible_width(field[i])
if (w > width[i]) width[i] = w
}
}
END {
aligned = (width[1] <= max_width)
for (r = 1; r <= NR; r++) {
n = split_fields(lines[r], field)
line = field[1]
for (i = 2; i <= n; i++) {
pad = aligned ? width[i - 1] - visible_width(field[i - 1]) + GAP : 1
line = line substr(BLANKS, 1, pad) field[i]
}
print line
}
}
'
}
git_pretty_log() {
# 1. Replace (2 years, 5 months) with (2 years)
# 2. Replace (2 years ago) with (2 years)
# 3. Color merge commits specially
# 4. Align the columns
# 5. Page only if we're asked to (GIT_NO_PAGER)
# 6. Page only if needed
make_log "$@" |
sed -Ee 's/([[:digit:]]+ [[:alpha:]]+), [[:digit:]]+ months? ago/\1/' |
sed -Ee 's/([[:digit:]]+ [[:alpha:]]+) ago/\1/' |
sed -Ee "s/(Merge (branch|remote-tracking branch|pull request) .*$)/$(printf '\033[31m')\\1$(printf '\033[0m')/" |
columnize |
if [ -n "$GIT_NO_PAGER" ]; then
cat
else
less --quit-if-one-screen --no-init --RAW-CONTROL-CHARS --chop-long-lines
fi
}
git_pretty_log "$@"