-
Notifications
You must be signed in to change notification settings - Fork 9
/
git-xlog
executable file
·147 lines (124 loc) · 3.01 KB
/
git-xlog
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
#!/usr/bin/env bash
app_name="$(basename "${BASH_SOURCE[0]}")"
print_help() {
expand -t 4 << EOF
Usage:
$app_name
Search history for string only in added or removed lines.
Options:
-t, --diff-type=<A|R|Added|Removed>
Whether to search in added or removed lines.
-l, --log-opt=<LOG_OPTIONS>
Options to pass on to git log commands.
-d, --diff-opt=<DIFF_OPTIONS>
Options to pass on to git diff commands.
-?, --help
Show this help information and exit.
EOF
}
getopt -q -T
if [[ $? -ne 4 ]]; then
echo "$app_name: [Error] This script requires an enhanced getopt version." >&2
exit 1
fi
for ((i=1; i <= $#; i++)); do
opt="${!i}"
case "$opt" in
-\?|--help)
print_help
exit 0
;;
--)
break
;;
esac
done
opts=$(getopt -o 't:l:d:' -l 'diff-type:,log-opt:,diff-opt:' -n "$app_name" -- "$@") || exit $?
eval "opts=($opts)"
for ((i=0; i < ${#opts[@]}; i++)); do
opt="${opts[$i]}"
case "$opt" in
-t|--diff-type)
diff_type="${opts[++i]}"
;;
-l|--log-opt)
log_opt="${opts[++i]}"
;;
-d|--diff-opt)
diff_opt="${opts[++i]}"
;;
--)
break
;;
esac
done
if [[ ! -v diff_type ]]; then
echo "$app_name: [Error] Missing '--diff-type' argument." >&2
exit 1
elif [[ -z $diff_type ]]; then
echo "$app_name: [Error] Missing value for argument '--diff-type'." >&2
exit 1
elif [[ ${diff_type@U} == 'A' || ${diff_type@U} == "ADDED" ]]; then
diff_mark='>'
elif [[ ${diff_type@U} == 'R' || ${diff_type@U} == "REMOVED" ]]; then
diff_mark='<'
else
echo "$app_name: [Error] Unrecognized diff-type: '$diff_type'. Accepted values: 'A', 'Added', 'R', 'Removed'." >&2
exit 1
fi
if [[ ! -v log_opt ]]; then
echo "$app_name: [Error] Missing '--log-opt' argument." >&2
exit 1
elif [[ -z $log_opt ]]; then
echo "$app_name: [Error] Missing value for argument '--log-opt'." >&2
exit 1
fi
opts=$(eval getopt -q -o 'S:G:' -n "$app_name" -- "$log_opt")
eval "opts=($opts)"
for ((i=0; i < ${#opts[@]}; i++)); do
opt="${opts[$i]}"
case "$opt" in
-S)
search_text="${opts[++i]}"
;;
-G)
search_regex="${opts[++i]}"
;;
--)
break
;;
*)
echo 'Internal error!' >&2
exit 1
;;
esac
done
if [[ ! -v search_text && ! -v search_regex ]]; then
echo "$app_name: [Error] No '-S' or '-G' found in log options." >&2
exit 1
elif [[ -z $search_text && -z $search_regex ]]; then
echo "$app_name: [Error] Missing value for argument '-S' or '-G' in log options." >&2
exit 1
fi
interrupt () {
echo "$app_name: [Error] Interrupted." >&2
exit 1
}
trap interrupt INT
if [[ -t 1 ]]; then
git_color="--color"
less_color="-r"
fi
if [[ -n $search_regex ]]; then
grep_opt='-E "$search_regex"'
elif [[ -n $search_text ]]; then
grep_opt='"$search_text"'
fi
set -e
eval git --no-pager log "$log_opt" --no-patch --format=%H |
while read -r sha; do
eval git --no-pager diff -U0 "$sha~" "$sha" --output-indicator-new='\>' --output-indicator-old='\<' |
grep -E "^$diff_mark" |
eval grep -q "$grep_opt" &&
eval git --no-pager log "$git_color" --no-walk "$sha" "$log_opt" "$diff_opt"
done | less -deFX $less_color