blob: c16623e35331168c236c205237f836d970670cb9 (
plain)
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
|
#!/bin/sh
# Git Trach, track the state of multiple repos from a single file.
# dependencies:
# - git
# - $EDITOR: -e
repos=$HOME/sync/share/git-track.txt
# prevent file not found errors
touch "$repos" || exit 1
help() {
cat >&2 <<EOF
usage: gt [OPTION]
-a PATH add repo
-s update and show status of each repo
-c COMMAND run 'git COMMAND' in each repo
-h show this help
-l list repos
-e edit repos in \$EDITOR
EOF
}
# fetch repository prettily, outputs nothing if failed
fetch() {
# fetch with one-line printing of progress
git fetch --progress 2>/dev/null | while read -r line; do # \r\033[0K : clear current line
printf >&2 '\r\033[0K%s' "$line"
done
}
# Print repositories prettily
# This function function prints animations (eg. clearing the line)
# to stderr and the final status line is outputted to stdout.
status() {
while read -r repo; do
repo_pretty="$(printf '%s' "$repo" | sed "s@$HOME@~@")"
if [ ! -d "$repo" ]; then
printf '%s missing\n' "$repo_pretty"
continue
fi
# absolute path
cd "$repo"
# replace line with status
printf >&2 '\r\033[0K'
status="$(git status --porcelain 2>/dev/null |
awk '{print $1}' |
sort | uniq | tr -s '?' |
tr -d '\n')"
remote="$(git branch -v 2>/dev/null |
sed '/^*/!d;s/ahead/↑/;s/behind/↓/;s/[^↓↑]*//g')"
printf '%s %s %s\n' "$repo_pretty" "$status" "$remote"
done <"$repos"
}
# run git command in each repo
# $1: command
repos_cmd() {
while read -r repo; do
repo_pretty="$(printf '%s' "$repo" | sed "s@$HOME@~@")"
printf ''\''%s'\'' in %s' "$1" "$repo_pretty"
(
cd "$repo"
git "$1" >/dev/null 2>&1
[ $? -gt 0 ] && s="x" || s="o"
printf '\r\033[0K%s: %s\n' "$repo_pretty" "$s"
)
done <"$repos"
}
# no options
if [ -z "$1" ]; then
help
exit 1
fi
while getopts ":a:c:f:lshe" opt; do
case "$opt" in
a)
cd "$OPTARG" || exit 1
r="$(git rev-parse --show-toplevel)"
[ "$r" ] || exit 2
if grep "$r" "$repos" >/dev/null 2>&1; then
printf >&2 'added already.\n'
exit 2
fi
printf '%s\n' "$r" >>"$repos"
printf >&2 'added.\n'
;;
c)
f_command=1
f_arg="$OPTARG"
;;
s) f_status=1 ;;
l) cat "$repos" ;;
e) $EDITOR "$repos" ;;
f) repos="$OPTARG" ;;
h) help ;;
:)
printf >&2 -- '-%s requires argument\n' "$OPTARG"
exit 1
;;
?)
printf >&2 -- 'Invalid option: -%s\n' "$OPTARG"
exit 1
;;
esac
done
# commands hereafter must happen in order
[ "$(wc -l <"$repos")" -gt 0 ] || exit 0
if [ "$f_command" ]; then
repos_cmd "$f_arg"
fi
if [ "$f_status" ]; then
status
fi
# eval "herbe $(status | sed 's/"/\"/g;s/.*/"&"/' | tr '\n' ' ')"
|