-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsetup-git.sh
More file actions
executable file
·350 lines (290 loc) · 12.3 KB
/
setup-git.sh
File metadata and controls
executable file
·350 lines (290 loc) · 12.3 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
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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
#!/usr/bin/env bash
# git-setup.sh — Interactive Git setup using charmbracelet/gum
# Usage: bash git-setup.sh
set -euo pipefail
# ─── Colors & styles ────────────────────────────────────────────────────────
BOLD="--foreground 212 --bold"
# ─── Check dependencies ──────────────────────────────────────────────────────
check_deps() {
for cmd in git gum; do
if ! command -v "$cmd" &>/dev/null; then
echo "❌ '$cmd' is required but not installed."
if [[ "$cmd" == "gum" ]]; then
echo "Install gum: https://github.com/charmbracelet/gum#installation"
fi
exit 1
fi
done
}
# ─── Header ──────────────────────────────────────────────────────────────────
print_header() {
gum style \
--foreground 212 --border-foreground 212 --border double \
--align center --width 50 --margin "1 2" --padding "1 4" \
'🔧 Git Setup Wizard' \
'Configure your new machine for Git'
}
# ─── Identity ────────────────────────────────────────────────────────────────
setup_identity() {
gum style --foreground 99 --bold "── Identity ──────────────────────────"
local current_name current_email
current_name=$(git config --global user.name 2>/dev/null || echo "")
current_email=$(git config --global user.email 2>/dev/null || echo "")
local name
name=$(gum input \
--placeholder "Your full name" \
--value "$current_name" \
--prompt "👤 Name: ")
[[ -z "$name" ]] && { gum style --foreground 196 "Name cannot be empty."; exit 1; }
local email
email=$(gum input \
--placeholder "you@example.com" \
--value "$current_email" \
--prompt "📧 Email: ")
[[ -z "$email" ]] && { gum style --foreground 196 "Email cannot be empty."; exit 1; }
git config --global user.name "$name"
git config --global user.email "$email"
gum style --foreground 82 "✔ Identity set: $name <$email>"
}
# ─── Default branch ──────────────────────────────────────────────────────────
setup_default_branch() {
gum style --foreground 99 --bold "── Default Branch ────────────────────"
local current
current=$(git config --global init.defaultBranch 2>/dev/null || echo "main")
local branch
branch=$(gum choose --selected "$current" "main" "master" "trunk" "develop" "(custom)")
if [[ "$branch" == "(custom)" ]]; then
branch=$(gum input --placeholder "branch-name" --prompt "🌿 Branch name: ")
fi
[[ -z "$branch" ]] && branch="main"
git config --global init.defaultBranch "$branch"
gum style --foreground 82 "✔ Default branch: $branch"
}
# ─── Editor ──────────────────────────────────────────────────────────────────
setup_editor() {
gum style --foreground 99 --bold "── Default Editor ────────────────────"
local current
current=$(git config --global core.editor 2>/dev/null || echo "")
local editor
editor=$(gum choose --selected "${current:-vim}" \
"vim" "nvim" "nano" "emacs" "code --wait" "hx" "(custom)")
if [[ "$editor" == "(custom)" ]]; then
editor=$(gum input --placeholder "e.g. micro" --prompt "✏️ Editor: ")
fi
[[ -z "$editor" ]] && editor="vim"
git config --global core.editor "$editor"
gum style --foreground 82 "✔ Editor: $editor"
}
# ─── GPG signing ─────────────────────────────────────────────────────────────
setup_gpg() {
gum style --foreground 99 --bold "── GPG Commit Signing ────────────────"
if ! gum confirm "Enable GPG commit signing?"; then
gum style --foreground 243 "⏭ Skipped GPG signing."
return
fi
if ! command -v gpg &>/dev/null; then
gum style --foreground 196 "gpg not found — skipping GPG setup."
return
fi
# List available keys
local keys
keys=$(gpg --list-secret-keys --keyid-format=long 2>/dev/null \
| grep '^sec' | awk '{print $2}' | cut -d'/' -f2 || true)
local signing_key
if [[ -z "$keys" ]]; then
gum style --foreground 214 "No GPG keys found. Generate one with: gpg --full-generate-key"
signing_key=$(gum input --placeholder "Paste your GPG key ID" --prompt "🔑 Key ID: ")
else
signing_key=$(echo "$keys" | gum choose --header "Select your signing key:")
fi
if [[ -n "$signing_key" ]]; then
git config --global user.signingkey "$signing_key"
git config --global commit.gpgsign true
git config --global tag.gpgSign true
gum style --foreground 82 "✔ GPG signing enabled with key: $signing_key"
fi
}
# ─── SSH key ─────────────────────────────────────────────────────────────────
setup_ssh() {
gum style --foreground 99 --bold "── SSH Key ───────────────────────────"
# Check for existing keys
local existing=()
for f in ~/.ssh/id_ed25519 ~/.ssh/id_rsa ~/.ssh/id_ecdsa; do
[[ -f "$f" ]] && existing+=("$f")
done
if [[ ${#existing[@]} -gt 0 ]]; then
gum style --foreground 82 "Existing SSH keys found:"
for k in "${existing[@]}"; do
gum style --foreground 243 " • $k"
done
if ! gum confirm "Generate a new SSH key anyway?"; then
gum style --foreground 243 "⏭ Using existing SSH key."
return
fi
fi
local key_type
key_type=$(gum choose --selected "ed25519" "ed25519" "rsa" --header "Key type:")
local key_path="$HOME/.ssh/id_${key_type}"
local comment
comment=$(git config --global user.email 2>/dev/null || echo "")
comment=$(gum input --value "$comment" --prompt "💬 Key comment: ")
if [[ "$key_type" == "rsa" ]]; then
ssh-keygen -t rsa -b 4096 -C "$comment" -f "$key_path"
else
ssh-keygen -t ed25519 -C "$comment" -f "$key_path"
fi
# Start ssh-agent and add key
eval "$(ssh-agent -s)" &>/dev/null
ssh-add "$key_path" 2>/dev/null || true
gum style --foreground 82 "✔ SSH key generated: ${key_path}.pub"
gum style --foreground 214 "📋 Copy this public key to GitHub/GitLab:"
gum style --border normal --padding "0 1" "$(cat "${key_path}.pub")"
}
# ─── Useful aliases ──────────────────────────────────────────────────────────
setup_aliases() {
gum style --foreground 99 --bold "── Git Aliases ───────────────────────"
declare -A ALIASES=(
[st]="status -sb"
[co]="checkout"
[br]="branch"
[lg]="log --oneline --graph --decorate --all"
[last]="log -1 HEAD --stat"
[undo]="reset HEAD~1 --mixed"
[aliases]="config --get-regexp alias"
[pushf]="push --force-with-lease"
[stash-all]="stash save --include-untracked"
)
local selected
selected=$(printf '%s\n' "${!ALIASES[@]}" | sort | \
gum choose --no-limit --header "Select aliases to install (space to toggle):")
if [[ -z "$selected" ]]; then
gum style --foreground 243 "⏭ No aliases selected."
return
fi
while IFS= read -r alias_name; do
git config --global "alias.${alias_name}" "${ALIASES[$alias_name]}"
gum style --foreground 82 " ✔ git $alias_name → ${ALIASES[$alias_name]}"
done <<< "$selected"
}
# ─── Extra quality-of-life settings ─────────────────────────────────────────
setup_extras() {
gum style --foreground 99 --bold "── Extra Settings ────────────────────"
declare -A EXTRAS=(
["Auto-correct typos (autocorrect=10)"]="core.autocorrect|10"
["Color UI always on"]="color.ui|always"
["Push current branch only (simple)"]="push.default|simple"
["Pull rebase by default"]="pull.rebase|true"
["Rebase autostash"]="rebase.autoStash|true"
["Rerere (reuse recorded resolutions)"]="rerere.enabled|true"
["Prune on fetch"]="fetch.prune|true"
["Diff algorithm: histogram"]="diff.algorithm|histogram"
["Merge tool: verbose conflict markers"]="merge.conflictstyle|diff3"
["Credential helper: store"]="credential.helper|store"
)
local selected
selected=$(printf '%s\n' "${!EXTRAS[@]}" | sort | \
gum choose --no-limit --header "Select extra settings to enable:")
[[ -z "$selected" ]] && { gum style --foreground 243 "⏭ No extras selected."; return; }
while IFS= read -r label; do
local pair="${EXTRAS[$label]}"
local key="${pair%%|*}"
local val="${pair##*|}"
git config --global "$key" "$val"
gum style --foreground 82 " ✔ $key = $val"
done <<< "$selected"
}
# ─── Global .gitignore ───────────────────────────────────────────────────────
setup_gitignore() {
gum style --foreground 99 --bold "── Global .gitignore ─────────────────"
if ! gum confirm "Set up a global .gitignore?"; then
gum style --foreground 243 "⏭ Skipped."
return
fi
local ignore_file="$HOME/.gitignore_global"
cat > "$ignore_file" <<'IGNORE'
# OS
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
Thumbs.db
ehthumbs.db
Desktop.ini
# Editors
.vscode/
.idea/
*.swp
*.swo
*~
.project
.classpath
# Secrets & env
.env
.env.*
!.env.example
*.pem
*.key
*.cert
# Logs & temp
*.log
*.tmp
*.bak
*.orig
npm-debug.log*
yarn-error.log*
# Build artifacts
dist/
build/
__pycache__/
*.pyc
*.pyo
node_modules/
.cache/
IGNORE
git config --global core.excludesFile "$ignore_file"
gum style --foreground 82 "✔ Global .gitignore created at $ignore_file"
}
# ─── Summary ─────────────────────────────────────────────────────────────────
print_summary() {
gum style --foreground 99 --bold "── Final Configuration ───────────────"
git config --global --list | sort | while IFS='=' read -r key val; do
printf " %-35s %s\n" "$key" "$val"
done | gum pager
}
# ─── Main ────────────────────────────────────────────────────────────────────
main() {
check_deps
print_header
gum style --foreground 243 "Choose which steps to run:"
local steps
steps=$(gum choose --no-limit \
--selected "Identity,Default Branch,Editor,Aliases,Extra Settings,Global .gitignore" \
"Identity" \
"Default Branch" \
"Editor" \
"GPG Signing" \
"SSH Key" \
"Aliases" \
"Extra Settings" \
"Global .gitignore" \
--header "Setup steps (space to toggle, enter to confirm):")
echo ""
[[ "$steps" == *"Identity"* ]] && setup_identity
[[ "$steps" == *"Default Branch"* ]] && setup_default_branch
[[ "$steps" == *"Editor"* ]] && setup_editor
[[ "$steps" == *"GPG Signing"* ]] && setup_gpg
[[ "$steps" == *"SSH Key"* ]] && setup_ssh
[[ "$steps" == *"Aliases"* ]] && setup_aliases
[[ "$steps" == *"Extra Settings"* ]] && setup_extras
[[ "$steps" == *"Global .gitignore"* ]] && setup_gitignore
echo ""
gum style \
--foreground 82 --border-foreground 82 --border rounded \
--align center --width 50 --padding "0 2" \
"🎉 Git setup complete!"
if gum confirm "View full git config?"; then
print_summary
fi
}
main "$@"