-
Notifications
You must be signed in to change notification settings - Fork 3
/
git-recon
executable file
·206 lines (177 loc) · 4.81 KB
/
git-recon
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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#!/usr/bin/env bash
# A tool for reconciling your local git repositories.
# Source: https://gitlab.com/leipert-projects/git-recon
CURR_DIR="$(pwd)"
VERBOSE_MODE=true
PORCELAIN_MODE=false
RECURSIVE_MODE=false
function help() {
cat <<EndOfMessage
git-recon - reconcile your local git repos [version v1.0.1]
USAGE
git recon [--version] [--help] [--recursive] [--porcelain]
OPTIONS
--recursive Recursively check subfolders, if the current directory is
NOT a git folder, this will be enabled by default
--porcelain Machine readable output
--help Prints this help
--version Prints current version
git-recon is a tool for reconciling your local git repositories.
git has a lot of things to keep track of: files, branches, tags, stashes,
submodules and worktrees.
With git-recon you can quickly check the status of all of them.
EndOfMessage
}
function indent() { sed 's/^/ /'; }
function success() {
# shellcheck disable=SC2059
printf "\U2705 $1\n" "${@:2}"
}
function error() {
# shellcheck disable=SC2059
printf "\U274C $1\n" "${@:2}"
}
function check_remotes {
local remotes
remotes=$(git remote -v)
if [ "$remotes" != "" ]; then
success "%s Remotes configured" "$(echo "$remotes" | wc -l)"
if [ "$VERBOSE_MODE" == "true" ]; then
echo "$remotes" | indent | indent
fi
else
error "No remote configured, did you ever push this repo?"
return 1
fi
}
function check_branches {
local branches
branches=$(git log --branches --not --remotes --no-walk --decorate --pretty='format:Refs:%d; Last commit: %h %s')
if [ "$branches" != "" ]; then
error "%s branches with unpushed commits" "$(echo "$branches" | wc -l)"
if [ "$VERBOSE_MODE" == "true" ]; then
echo "$branches" | indent | indent
fi
return 1
else
success "No branch contains unpushed commits"
fi
}
function check_tags {
local tags
tags=$(comm -23 <(git show-ref --tags | cut -d ' ' -f 2) <(git ls-remote --tags origin | cut -f 2) | sed 's#refs/tags/##g')
if [ "$tags" != "" ]; then
error "%s unpushed tags" "$(echo "$tags" | wc -l)"
if [ "$VERBOSE_MODE" == "true" ]; then
echo "$tags" | indent | indent
fi
return 1
else
success "No unpushed tags"
fi
}
function check_stashes {
local stashes
stashes=$(git stash list)
if [ "$stashes" != "" ]; then
error "%s stashes found" "$(echo "$stashes" | wc -l)"
if [ "$VERBOSE_MODE" == "true" ]; then
echo "$stashes" | indent | indent
fi
return 1
else
success "No stashes found"
fi
}
function check_status {
local files
files=$(git status --porcelain)
if [ "$files" != "" ]; then
error "Unclean repo state, %s files touched " "$(echo "$files" | wc -l)"
if [ "$VERBOSE_MODE" == "true" ]; then
echo "$files" | indent | indent
fi
return 1
else
success "The repo status is clean"
fi
}
function run_checks {
fail=0
check_remotes || return 1
check_branches || fail=1
check_tags || fail=1
check_stashes || fail=1
check_status || fail=1
return $fail
}
function check_repo {
local DIR
cd "$(dirname "$1")" || return 1
DIR="$(pwd)"
if [ "$PORCELAIN_MODE" != "true" ]; then
printf "Checking: %s\n\n" "$DIR"
fi
output=$(run_checks)
success=$?
if [ "$PORCELAIN_MODE" == "true" ]; then
if [ "$success" == "0" ]; then
echo "SYNC $DIR"
else
echo "???? $DIR"
fi
else
echo "$output" | indent
echo ""
if [ "$success" == "0" ]; then
success "$DIR is synced up with remote"
else
error "$DIR is not synced up with remote"
fi
fi
cd "$CURR_DIR" || return 1
}
function find_git_dirs() {
if command -v fd &>/dev/null; then
fd --hidden --no-ignore-vcs --glob --print0 '.git' "$CURR_DIR" | sort -z -d
else
find "$CURR_DIR" -iname '.git' -print0 | sort -z -d
fi
}
function execute() {
if { [ -d .git ] || [ -f .git ]; } && [ "$RECURSIVE_MODE" == "false" ]; then
check_repo "$CURR_DIR/.git"
else
while IFS= read -r -d '' file; do
check_repo "$file"
echo ""
done < <(find_git_dirs)
fi
}
while [ $# -ne 0 ]; do
arg="$1"
case "$arg" in
--recursive)
RECURSIVE_MODE=true
;;
--porcelain)
VERBOSE_MODE=false
PORCELAIN_MODE=true
;;
--help)
help
exit 0
;;
--version)
echo "git-recon version v1.0.1"
exit 0
;;
*) ;;
esac
shift
done
if [ "$PORCELAIN_MODE" == "true" ]; then
execute | column -t
else
execute
fi