gitbash 0.2.7 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +26 -28
- package/bin/gitbash +137 -1
- package/commands/_utils.sh +142 -0
- package/commands/branch.sh +13 -25
- package/commands/cleanstash.sh +2 -26
- package/commands/cleanup.sh +51 -34
- package/commands/commit.sh +126 -22
- package/commands/commits.sh +7 -28
- package/commands/create.sh +137 -40
- package/commands/stale.sh +33 -36
- package/commands/stash.sh +11 -3
- package/commands/stashes.sh +13 -25
- package/commands/status.sh +10 -34
- package/commands/switch.sh +4 -32
- package/commands/unstash.sh +2 -26
- package/package.json +1 -1
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2025 Matthias Jäggli
|
|
3
|
+
Copyright (c) 2025 Matthias Jäggli, https://github.com/jaggli
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
Interactive git utilities for bash with fzf-powered menus.
|
|
4
4
|
|
|
5
|
+

|
|
6
|
+
|
|
5
7
|
## Installation
|
|
6
8
|
|
|
7
9
|
### Via npm
|
|
8
10
|
|
|
9
11
|
```bash
|
|
10
|
-
npm i -g gitbash
|
|
12
|
+
npm i -g gitbash && gitbash --config
|
|
11
13
|
```
|
|
12
14
|
|
|
13
15
|
### Options
|
|
@@ -19,33 +21,6 @@ gitbash --init # Print shell init code
|
|
|
19
21
|
gitbash --config # Interactive configuration wizard
|
|
20
22
|
```
|
|
21
23
|
|
|
22
|
-
### Shell Aliases
|
|
23
|
-
|
|
24
|
-
Add these aliases to your `.zshrc` or `.bashrc` for individual command access:
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
alias branch="gitbash branch"
|
|
28
|
-
alias cleanstash="gitbash cleanstash"
|
|
29
|
-
alias cleanup="gitbash cleanup"
|
|
30
|
-
alias commit="gitbash commit"
|
|
31
|
-
alias commits="gitbash commits"
|
|
32
|
-
alias create="gitbash create"
|
|
33
|
-
alias pr="gitbash pr"
|
|
34
|
-
alias stale="gitbash stale"
|
|
35
|
-
alias stash="gitbash stash"
|
|
36
|
-
alias stashes="gitbash stashes"
|
|
37
|
-
alias status="gitbash status"
|
|
38
|
-
alias switch="gitbash switch"
|
|
39
|
-
alias unstash="gitbash unstash"
|
|
40
|
-
alias update="gitbash update"
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
Or use the built-in shell integration, for all commands:
|
|
44
|
-
|
|
45
|
-
```bash
|
|
46
|
-
eval "$(gitbash --init)"
|
|
47
|
-
```
|
|
48
|
-
|
|
49
24
|
### Dependencies
|
|
50
25
|
|
|
51
26
|
```bash
|
|
@@ -216,6 +191,29 @@ commits # Show last 20 commits
|
|
|
216
191
|
commits 50 # Show last 50 commits
|
|
217
192
|
```
|
|
218
193
|
|
|
194
|
+
### Individual aliases
|
|
195
|
+
|
|
196
|
+
Instead of adding every command via `eval "$(gitbash --init)"` in `.zshrc` or `.bashrc`
|
|
197
|
+
direct usage with `gitbash [command]` is also possible. Or if desired, individual aliases
|
|
198
|
+
can be made.
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
alias branch="gitbash branch"
|
|
202
|
+
alias cleanstash="gitbash cleanstash"
|
|
203
|
+
alias cleanup="gitbash cleanup"
|
|
204
|
+
alias commit="gitbash commit"
|
|
205
|
+
alias commits="gitbash commits"
|
|
206
|
+
alias create="gitbash create"
|
|
207
|
+
alias pr="gitbash pr"
|
|
208
|
+
alias stale="gitbash stale"
|
|
209
|
+
alias stash="gitbash stash"
|
|
210
|
+
alias stashes="gitbash stashes"
|
|
211
|
+
alias status="gitbash status"
|
|
212
|
+
alias switch="gitbash switch"
|
|
213
|
+
alias unstash="gitbash unstash"
|
|
214
|
+
alias update="gitbash update"
|
|
215
|
+
```
|
|
216
|
+
|
|
219
217
|
## License
|
|
220
218
|
|
|
221
219
|
See [LICENSE](LICENSE) file for details.
|
package/bin/gitbash
CHANGED
|
@@ -17,33 +17,169 @@ configure_gitbash() {
|
|
|
17
17
|
|
|
18
18
|
local current_prefix="${GITBASH_FEATURE_BRANCH_PREFIX:-feature/}"
|
|
19
19
|
local current_merge="${GITBASH_MERGE_COMMAND:-fork}"
|
|
20
|
+
local current_theme="${GITBASH_THEME:-auto}"
|
|
21
|
+
local current_stale_months="${GITBASH_STALE_MONTHS:-3}"
|
|
22
|
+
local current_cleanup_days="${GITBASH_CLEANUP_DAYS:-7}"
|
|
20
23
|
|
|
21
24
|
echo "Configure gitbash (writes to $CONFIG_FILE)"
|
|
22
25
|
echo
|
|
23
26
|
|
|
24
|
-
local input prefix merge_cmd
|
|
27
|
+
local input prefix merge_cmd theme stale_months cleanup_days
|
|
25
28
|
|
|
29
|
+
# Branch prefix
|
|
26
30
|
read -e -p "Feature branch prefix (used by create) [${current_prefix}]: " input
|
|
27
31
|
prefix=${input:-$current_prefix}
|
|
28
32
|
|
|
33
|
+
# Merge tool
|
|
29
34
|
read -e -p "Merge tool command (used by update on conflicts) [${current_merge}]: " input
|
|
30
35
|
merge_cmd=${input:-$current_merge}
|
|
31
36
|
|
|
37
|
+
# Theme preference
|
|
38
|
+
echo
|
|
39
|
+
echo "Theme preference for delta/bat (affects diff highlighting):"
|
|
40
|
+
echo " auto - Use terminal's theme detection"
|
|
41
|
+
echo " dark - Force dark theme"
|
|
42
|
+
echo " light - Force light theme (GitHub style)"
|
|
43
|
+
read -e -p "Theme [${current_theme}]: " input
|
|
44
|
+
theme=${input:-$current_theme}
|
|
45
|
+
case "$theme" in
|
|
46
|
+
auto|dark|light) ;;
|
|
47
|
+
*)
|
|
48
|
+
echo "Invalid theme. Using 'auto'."
|
|
49
|
+
theme="auto"
|
|
50
|
+
;;
|
|
51
|
+
esac
|
|
52
|
+
|
|
53
|
+
# Stale branch threshold
|
|
54
|
+
echo
|
|
55
|
+
read -e -p "Stale branch threshold in months (used by stale) [${current_stale_months}]: " input
|
|
56
|
+
stale_months=${input:-$current_stale_months}
|
|
57
|
+
if ! [[ "$stale_months" =~ ^[0-9]+$ ]] || [[ "$stale_months" -lt 1 ]]; then
|
|
58
|
+
echo "Invalid value. Using default of 3 months."
|
|
59
|
+
stale_months=3
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
# Cleanup threshold
|
|
63
|
+
read -e -p "Cleanup threshold in days (used by cleanup) [${current_cleanup_days}]: " input
|
|
64
|
+
cleanup_days=${input:-$current_cleanup_days}
|
|
65
|
+
if ! [[ "$cleanup_days" =~ ^[0-9]+$ ]] || [[ "$cleanup_days" -lt 1 ]]; then
|
|
66
|
+
echo "Invalid value. Using default of 7 days."
|
|
67
|
+
cleanup_days=7
|
|
68
|
+
fi
|
|
69
|
+
|
|
32
70
|
cat > "$CONFIG_FILE" <<EOF
|
|
33
71
|
# gitbash configuration
|
|
34
72
|
# Prefix for feature branches created by 'create'
|
|
35
73
|
GITBASH_FEATURE_BRANCH_PREFIX="$prefix"
|
|
36
74
|
# Merge tool command invoked by 'update' when conflicts occur
|
|
37
75
|
GITBASH_MERGE_COMMAND="$merge_cmd"
|
|
76
|
+
# Theme for delta/bat: auto, dark, or light
|
|
77
|
+
GITBASH_THEME="$theme"
|
|
78
|
+
# Stale branch threshold in months (branches older than this in 'stale')
|
|
79
|
+
GITBASH_STALE_MONTHS="$stale_months"
|
|
80
|
+
# Cleanup threshold in days (branches merged more than this many days ago)
|
|
81
|
+
GITBASH_CLEANUP_DAYS="$cleanup_days"
|
|
38
82
|
EOF
|
|
39
83
|
|
|
40
84
|
echo
|
|
41
85
|
echo "Saved configuration to $CONFIG_FILE"
|
|
42
86
|
|
|
87
|
+
# Check for dependencies
|
|
88
|
+
check_dependencies
|
|
89
|
+
|
|
43
90
|
# Check for shell integration
|
|
44
91
|
check_shell_integration
|
|
45
92
|
}
|
|
46
93
|
|
|
94
|
+
# Check and offer to install dependencies
|
|
95
|
+
check_dependencies() {
|
|
96
|
+
local missing_required=()
|
|
97
|
+
local missing_optional=()
|
|
98
|
+
|
|
99
|
+
# Required dependencies
|
|
100
|
+
if ! command -v fzf >/dev/null 2>&1; then
|
|
101
|
+
missing_required+=("fzf")
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
# Optional dependencies
|
|
105
|
+
if ! command -v delta >/dev/null 2>&1; then
|
|
106
|
+
missing_optional+=("git-delta")
|
|
107
|
+
fi
|
|
108
|
+
if ! command -v bat >/dev/null 2>&1; then
|
|
109
|
+
missing_optional+=("bat")
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
# If nothing missing, we're done
|
|
113
|
+
if [[ ${#missing_required[@]} -eq 0 && ${#missing_optional[@]} -eq 0 ]]; then
|
|
114
|
+
echo
|
|
115
|
+
echo "All dependencies installed ✓"
|
|
116
|
+
return 0
|
|
117
|
+
fi
|
|
118
|
+
|
|
119
|
+
echo
|
|
120
|
+
echo "Dependencies:"
|
|
121
|
+
|
|
122
|
+
# Show status of each dependency
|
|
123
|
+
if command -v fzf >/dev/null 2>&1; then
|
|
124
|
+
echo " ✓ fzf (required)"
|
|
125
|
+
else
|
|
126
|
+
echo " ✗ fzf (required) - fuzzy finder for interactive selection"
|
|
127
|
+
fi
|
|
128
|
+
|
|
129
|
+
if command -v delta >/dev/null 2>&1; then
|
|
130
|
+
echo " ✓ git-delta (optional)"
|
|
131
|
+
else
|
|
132
|
+
echo " ✗ git-delta (optional) - better diff highlighting"
|
|
133
|
+
fi
|
|
134
|
+
|
|
135
|
+
if command -v bat >/dev/null 2>&1; then
|
|
136
|
+
echo " ✓ bat (optional)"
|
|
137
|
+
else
|
|
138
|
+
echo " ✗ bat (optional) - syntax highlighting for file previews"
|
|
139
|
+
fi
|
|
140
|
+
|
|
141
|
+
# Build list of all missing dependencies
|
|
142
|
+
local all_missing=()
|
|
143
|
+
[[ ${#missing_required[@]} -gt 0 ]] && all_missing+=("${missing_required[@]}")
|
|
144
|
+
[[ ${#missing_optional[@]} -gt 0 ]] && all_missing+=("${missing_optional[@]}")
|
|
145
|
+
|
|
146
|
+
# If nothing to install, we're done
|
|
147
|
+
if [[ ${#all_missing[@]} -eq 0 ]]; then
|
|
148
|
+
return 0
|
|
149
|
+
fi
|
|
150
|
+
|
|
151
|
+
# Check if Homebrew is available
|
|
152
|
+
if ! command -v brew >/dev/null 2>&1; then
|
|
153
|
+
echo
|
|
154
|
+
echo "Homebrew not found. Install dependencies manually:"
|
|
155
|
+
for dep in "${all_missing[@]}"; do
|
|
156
|
+
echo " brew install $dep"
|
|
157
|
+
done
|
|
158
|
+
return 0
|
|
159
|
+
fi
|
|
160
|
+
|
|
161
|
+
# Offer to install missing dependencies
|
|
162
|
+
echo
|
|
163
|
+
local install_deps
|
|
164
|
+
read -e -p "Install missing dependencies with Homebrew? (Y/n): " install_deps
|
|
165
|
+
case "$install_deps" in
|
|
166
|
+
[nN][oO]|[nN])
|
|
167
|
+
echo "Skipped dependency installation."
|
|
168
|
+
;;
|
|
169
|
+
*)
|
|
170
|
+
echo "Installing dependencies..."
|
|
171
|
+
for dep in "${all_missing[@]}"; do
|
|
172
|
+
echo " Installing $dep..."
|
|
173
|
+
if brew install "$dep" 2>/dev/null; then
|
|
174
|
+
echo " ✓ $dep installed"
|
|
175
|
+
else
|
|
176
|
+
echo " ✗ Failed to install $dep"
|
|
177
|
+
fi
|
|
178
|
+
done
|
|
179
|
+
;;
|
|
180
|
+
esac
|
|
181
|
+
}
|
|
182
|
+
|
|
47
183
|
# Check if gitbash shell integration is set up
|
|
48
184
|
check_shell_integration() {
|
|
49
185
|
local shell_rc=""
|
package/commands/_utils.sh
CHANGED
|
@@ -2,6 +2,33 @@
|
|
|
2
2
|
# shellcheck disable=SC2155
|
|
3
3
|
# Common utilities for gitbash commands - compatible with bash and zsh
|
|
4
4
|
|
|
5
|
+
# Color codes for consistent output
|
|
6
|
+
COLOR_RED='\033[0;31m'
|
|
7
|
+
COLOR_GREEN='\033[0;32m'
|
|
8
|
+
COLOR_YELLOW='\033[0;33m'
|
|
9
|
+
COLOR_BLUE='\033[0;34m'
|
|
10
|
+
COLOR_RESET='\033[0m'
|
|
11
|
+
|
|
12
|
+
# Print success message (green checkmark)
|
|
13
|
+
print_success() {
|
|
14
|
+
echo -e "${COLOR_GREEN}✓${COLOR_RESET} $*"
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
# Print error message (red X)
|
|
18
|
+
print_error() {
|
|
19
|
+
echo -e "${COLOR_RED}✗${COLOR_RESET} $*" >&2
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
# Print warning message (yellow warning)
|
|
23
|
+
print_warning() {
|
|
24
|
+
echo -e "${COLOR_YELLOW}⚠${COLOR_RESET} $*"
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
# Print info message (blue)
|
|
28
|
+
print_info() {
|
|
29
|
+
echo -e "${COLOR_BLUE}ℹ${COLOR_RESET} $*"
|
|
30
|
+
}
|
|
31
|
+
|
|
5
32
|
# Portable read with prompt that works in both bash and zsh
|
|
6
33
|
# Usage: prompt_read "prompt text" variable_name
|
|
7
34
|
# The result is stored in the variable name provided
|
|
@@ -32,3 +59,118 @@ prompt_read_edit() {
|
|
|
32
59
|
read -e -rp "$prompt" "$varname"
|
|
33
60
|
fi
|
|
34
61
|
}
|
|
62
|
+
|
|
63
|
+
# Check if fzf is installed, offer to install if not
|
|
64
|
+
# Returns 0 if fzf is available, 1 if not
|
|
65
|
+
require_fzf() {
|
|
66
|
+
if command -v fzf >/dev/null 2>&1; then
|
|
67
|
+
return 0
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
print_error "fzf is not installed."
|
|
71
|
+
|
|
72
|
+
local ans
|
|
73
|
+
prompt_read "Install fzf with Homebrew? (y/N): " ans
|
|
74
|
+
case "$ans" in
|
|
75
|
+
[yY][eE][sS]|[yY])
|
|
76
|
+
echo "Installing fzf with brew..."
|
|
77
|
+
if ! command -v brew >/dev/null 2>&1; then
|
|
78
|
+
print_error "Homebrew is not installed. Aborting."
|
|
79
|
+
return 1
|
|
80
|
+
fi
|
|
81
|
+
if brew install fzf; then
|
|
82
|
+
# Optional: install shell integrations automatically
|
|
83
|
+
if [[ -f "$(brew --prefix)/opt/fzf/install" ]]; then
|
|
84
|
+
echo "Running fzf install script..."
|
|
85
|
+
yes | "$(brew --prefix)/opt/fzf/install"
|
|
86
|
+
fi
|
|
87
|
+
print_success "fzf installed successfully."
|
|
88
|
+
return 0
|
|
89
|
+
else
|
|
90
|
+
print_error "fzf install failed. Aborting."
|
|
91
|
+
return 1
|
|
92
|
+
fi
|
|
93
|
+
;;
|
|
94
|
+
*)
|
|
95
|
+
echo "Aborted (skipped fzf installation)."
|
|
96
|
+
return 1
|
|
97
|
+
;;
|
|
98
|
+
esac
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
# Check if inside a git repository
|
|
102
|
+
# Returns 0 if in a git repo, 1 if not
|
|
103
|
+
require_git_repo() {
|
|
104
|
+
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
105
|
+
return 0
|
|
106
|
+
fi
|
|
107
|
+
print_error "Not inside a git repository."
|
|
108
|
+
return 1
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# Get delta arguments based on theme setting
|
|
112
|
+
# Uses GITBASH_THEME: auto (default), dark, or light
|
|
113
|
+
_get_delta_args() {
|
|
114
|
+
local theme="${GITBASH_THEME:-auto}"
|
|
115
|
+
case "$theme" in
|
|
116
|
+
light)
|
|
117
|
+
echo "--light"
|
|
118
|
+
;;
|
|
119
|
+
dark)
|
|
120
|
+
echo "--dark"
|
|
121
|
+
;;
|
|
122
|
+
*)
|
|
123
|
+
# auto - let delta detect (no args needed, but we can add --light for lighter terminals)
|
|
124
|
+
echo ""
|
|
125
|
+
;;
|
|
126
|
+
esac
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
# Get bat arguments based on theme setting
|
|
130
|
+
_get_bat_args() {
|
|
131
|
+
local theme="${GITBASH_THEME:-auto}"
|
|
132
|
+
case "$theme" in
|
|
133
|
+
light)
|
|
134
|
+
echo "--theme=GitHub"
|
|
135
|
+
;;
|
|
136
|
+
dark)
|
|
137
|
+
echo "--theme=Dracula"
|
|
138
|
+
;;
|
|
139
|
+
*)
|
|
140
|
+
# auto - let bat detect
|
|
141
|
+
echo ""
|
|
142
|
+
;;
|
|
143
|
+
esac
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
# Get the diff command to use (delta if installed, otherwise git diff)
|
|
147
|
+
# Usage: get_diff_cmd
|
|
148
|
+
# Returns the command name to use for diffs
|
|
149
|
+
get_diff_cmd() {
|
|
150
|
+
if command -v delta >/dev/null 2>&1; then
|
|
151
|
+
local delta_args
|
|
152
|
+
delta_args=$(_get_delta_args)
|
|
153
|
+
if [[ -n "$delta_args" ]]; then
|
|
154
|
+
echo "delta $delta_args"
|
|
155
|
+
else
|
|
156
|
+
echo "delta"
|
|
157
|
+
fi
|
|
158
|
+
else
|
|
159
|
+
echo "git diff"
|
|
160
|
+
fi
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
# Show a diff using delta if available, otherwise git diff
|
|
164
|
+
# Usage: show_diff [git diff args...]
|
|
165
|
+
# Example: show_diff --cached
|
|
166
|
+
# Example: show_diff HEAD~1
|
|
167
|
+
show_diff() {
|
|
168
|
+
if command -v delta >/dev/null 2>&1; then
|
|
169
|
+
local delta_args
|
|
170
|
+
delta_args=$(_get_delta_args)
|
|
171
|
+
# shellcheck disable=SC2086
|
|
172
|
+
git diff "$@" | delta $delta_args
|
|
173
|
+
else
|
|
174
|
+
git diff "$@"
|
|
175
|
+
fi
|
|
176
|
+
}
|
package/commands/branch.sh
CHANGED
|
@@ -107,31 +107,7 @@ EOF
|
|
|
107
107
|
# -----------------------------
|
|
108
108
|
# 1. Check for fzf
|
|
109
109
|
# -----------------------------
|
|
110
|
-
|
|
111
|
-
echo "fzf is not installed."
|
|
112
|
-
|
|
113
|
-
# Ask whether to install with Homebrew
|
|
114
|
-
prompt_read "Install fzf with Homebrew? (y/N): " ans
|
|
115
|
-
case "$ans" in
|
|
116
|
-
[yY][eE][sS]|[yY])
|
|
117
|
-
echo "Installing fzf with brew..."
|
|
118
|
-
if ! command -v brew >/dev/null 2>&1; then
|
|
119
|
-
echo "Homebrew is not installed. Aborting."
|
|
120
|
-
return 1
|
|
121
|
-
fi
|
|
122
|
-
brew install fzf || { echo "fzf install failed. Aborting."; return 1; }
|
|
123
|
-
# Optional: install shell integrations automatically
|
|
124
|
-
if [[ -f "$(brew --prefix)/opt/fzf/install" ]]; then
|
|
125
|
-
echo "Running fzf install script..."
|
|
126
|
-
yes | "$(brew --prefix)/opt/fzf/install"
|
|
127
|
-
fi
|
|
128
|
-
;;
|
|
129
|
-
*)
|
|
130
|
-
echo "Aborted (skipped fzf installation)."
|
|
131
|
-
return 1
|
|
132
|
-
;;
|
|
133
|
-
esac
|
|
134
|
-
fi
|
|
110
|
+
require_fzf || return 1
|
|
135
111
|
|
|
136
112
|
# -----------------------------
|
|
137
113
|
# 2. Build action menu
|
|
@@ -176,12 +152,24 @@ EOF
|
|
|
176
152
|
# -----------------------------
|
|
177
153
|
case "$selection" in
|
|
178
154
|
"$create_option")
|
|
155
|
+
# Source create.sh if create function not available
|
|
156
|
+
if ! declare -f create >/dev/null 2>&1; then
|
|
157
|
+
source "$SOURCE_DIR/create.sh"
|
|
158
|
+
fi
|
|
179
159
|
create
|
|
180
160
|
;;
|
|
181
161
|
"$switch_option")
|
|
162
|
+
# Source switch.sh if switch function not available
|
|
163
|
+
if ! declare -f switch >/dev/null 2>&1; then
|
|
164
|
+
source "$SOURCE_DIR/switch.sh"
|
|
165
|
+
fi
|
|
182
166
|
switch
|
|
183
167
|
;;
|
|
184
168
|
"$update_option")
|
|
169
|
+
# Source update.sh if update function not available
|
|
170
|
+
if ! declare -f update >/dev/null 2>&1; then
|
|
171
|
+
source "$SOURCE_DIR/update.sh"
|
|
172
|
+
fi
|
|
185
173
|
update
|
|
186
174
|
;;
|
|
187
175
|
"$abort_label")
|
package/commands/cleanstash.sh
CHANGED
|
@@ -73,31 +73,7 @@ EOF
|
|
|
73
73
|
# -----------------------------
|
|
74
74
|
# 1. Check for fzf
|
|
75
75
|
# -----------------------------
|
|
76
|
-
|
|
77
|
-
echo "fzf is not installed."
|
|
78
|
-
|
|
79
|
-
# Ask whether to install with Homebrew
|
|
80
|
-
prompt_read "Install fzf with Homebrew? (y/N): " ans
|
|
81
|
-
case "$ans" in
|
|
82
|
-
[yY][eE][sS]|[yY])
|
|
83
|
-
echo "Installing fzf with brew..."
|
|
84
|
-
if ! command -v brew >/dev/null 2>&1; then
|
|
85
|
-
echo "Homebrew is not installed. Aborting."
|
|
86
|
-
return 1
|
|
87
|
-
fi
|
|
88
|
-
brew install fzf || { echo "fzf install failed. Aborting."; return 1; }
|
|
89
|
-
# Optional: install shell integrations automatically
|
|
90
|
-
if [[ -f "$(brew --prefix)/opt/fzf/install" ]]; then
|
|
91
|
-
echo "Running fzf install script..."
|
|
92
|
-
yes | "$(brew --prefix)/opt/fzf/install"
|
|
93
|
-
fi
|
|
94
|
-
;;
|
|
95
|
-
*)
|
|
96
|
-
echo "Aborted (skipped fzf installation)."
|
|
97
|
-
return 1
|
|
98
|
-
;;
|
|
99
|
-
esac
|
|
100
|
-
fi
|
|
76
|
+
require_fzf || return 1
|
|
101
77
|
|
|
102
78
|
# -----------------------------
|
|
103
79
|
# 2. Build menu entries
|
|
@@ -126,7 +102,7 @@ EOF
|
|
|
126
102
|
--preview='
|
|
127
103
|
sel=$(echo {} | grep -o "stash@{[0-9]\+}" || true);
|
|
128
104
|
if [[ -n "$sel" ]]; then
|
|
129
|
-
git stash show -p "$sel";
|
|
105
|
+
git stash show -p "$sel" | delta --light 2>/dev/null || git stash show -p "$sel";
|
|
130
106
|
else
|
|
131
107
|
echo "No preview";
|
|
132
108
|
fi
|
package/commands/cleanup.sh
CHANGED
|
@@ -12,6 +12,8 @@ cleanup() {
|
|
|
12
12
|
# 0. Check for help/version flag and parse options
|
|
13
13
|
# -----------------------------
|
|
14
14
|
local json_mode=false
|
|
15
|
+
local dry_run=false
|
|
16
|
+
local days_threshold="${GITBASH_CLEANUP_DAYS:-7}"
|
|
15
17
|
|
|
16
18
|
while [[ $# -gt 0 ]]; do
|
|
17
19
|
case "$1" in
|
|
@@ -26,15 +28,17 @@ Usage: cleanup [OPTIONS]
|
|
|
26
28
|
Find and delete local branches that are no longer needed.
|
|
27
29
|
|
|
28
30
|
Options:
|
|
29
|
-
-h, --help
|
|
30
|
-
--json
|
|
31
|
+
-h, --help Show this help message
|
|
32
|
+
--json Output branch data as JSON (non-interactive)
|
|
33
|
+
--dry-run Show what would be deleted without actually deleting
|
|
34
|
+
--days=N Override stale threshold (default: 7 days, configurable via GITBASH_CLEANUP_DAYS)
|
|
31
35
|
|
|
32
36
|
Categories (pre-selected for deletion):
|
|
33
37
|
- Merged branches: Local branches whose remote was merged and deleted
|
|
34
|
-
- Stale branches: Local branches with no commits in
|
|
38
|
+
- Stale branches: Local branches with no commits in N+ days (default 7)
|
|
35
39
|
|
|
36
40
|
Not pre-selected (but listed):
|
|
37
|
-
- Recent branches: Local branches with commits in the last
|
|
41
|
+
- Recent branches: Local branches with commits in the last N days
|
|
38
42
|
|
|
39
43
|
Navigation:
|
|
40
44
|
↑/↓ or j/k Navigate through branches
|
|
@@ -42,6 +46,9 @@ Navigation:
|
|
|
42
46
|
Enter Delete selected branch(es)
|
|
43
47
|
ESC/Ctrl-C Exit without action
|
|
44
48
|
|
|
49
|
+
Configuration:
|
|
50
|
+
GITBASH_CLEANUP_DAYS - Set default days threshold (run 'gitbash --config')
|
|
51
|
+
|
|
45
52
|
Notes:
|
|
46
53
|
- Only deletes LOCAL branches (never touches remote)
|
|
47
54
|
- If current branch is selected, switches to main/master first
|
|
@@ -55,6 +62,12 @@ Examples:
|
|
|
55
62
|
[RECENT] feature/work-in-progress 2 days ago
|
|
56
63
|
✖ Abort
|
|
57
64
|
|
|
65
|
+
$ cleanup --dry-run
|
|
66
|
+
# Shows what would be deleted without deleting
|
|
67
|
+
|
|
68
|
+
$ cleanup --days=14
|
|
69
|
+
# Use 14-day threshold for stale branches
|
|
70
|
+
|
|
58
71
|
$ cleanup --json
|
|
59
72
|
[{"last_change_timestamp":1733123456,"author_email":"dev@example.com",...}]
|
|
60
73
|
|
|
@@ -69,6 +82,18 @@ EOF
|
|
|
69
82
|
json_mode=true
|
|
70
83
|
shift
|
|
71
84
|
;;
|
|
85
|
+
--dry-run)
|
|
86
|
+
dry_run=true
|
|
87
|
+
shift
|
|
88
|
+
;;
|
|
89
|
+
--days=*)
|
|
90
|
+
days_threshold="${1#--days=}"
|
|
91
|
+
if ! [[ "$days_threshold" =~ ^[0-9]+$ ]] || [[ "$days_threshold" -lt 1 ]]; then
|
|
92
|
+
print_error "Invalid days value: $days_threshold"
|
|
93
|
+
return 1
|
|
94
|
+
fi
|
|
95
|
+
shift
|
|
96
|
+
;;
|
|
72
97
|
*)
|
|
73
98
|
echo "Unknown option: $1"
|
|
74
99
|
return 1
|
|
@@ -82,38 +107,20 @@ EOF
|
|
|
82
107
|
if [[ "$json_mode" == true ]]; then
|
|
83
108
|
echo "[]"
|
|
84
109
|
else
|
|
85
|
-
|
|
110
|
+
print_error "Not inside a git repository."
|
|
86
111
|
fi
|
|
87
112
|
return 1
|
|
88
113
|
fi
|
|
89
114
|
|
|
90
115
|
if [[ "$json_mode" == false ]]; then
|
|
91
|
-
|
|
92
|
-
echo "fzf is not installed."
|
|
93
|
-
prompt_read "Install fzf with Homebrew? (y/N): " ans
|
|
94
|
-
case "$ans" in
|
|
95
|
-
[yY][eE][sS]|[yY])
|
|
96
|
-
echo "Installing fzf with brew..."
|
|
97
|
-
if ! command -v brew >/dev/null 2>&1; then
|
|
98
|
-
echo "Homebrew is not installed. Aborting."
|
|
99
|
-
return 1
|
|
100
|
-
fi
|
|
101
|
-
brew install fzf || { echo "fzf install failed. Aborting."; return 1; }
|
|
102
|
-
;;
|
|
103
|
-
*)
|
|
104
|
-
echo "Aborted (skipped fzf installation)."
|
|
105
|
-
return 1
|
|
106
|
-
;;
|
|
107
|
-
esac
|
|
108
|
-
fi
|
|
116
|
+
require_fzf || return 1
|
|
109
117
|
fi
|
|
110
|
-
|
|
111
118
|
# -----------------------------
|
|
112
119
|
# 2. Fetch and prune to sync with remote
|
|
113
120
|
# -----------------------------
|
|
114
121
|
if ! git fetch --prune origin 2>/dev/null; then
|
|
115
122
|
if [[ "$json_mode" == false ]]; then
|
|
116
|
-
|
|
123
|
+
print_warning "Fetch failed; continuing with local data." >&2
|
|
117
124
|
fi
|
|
118
125
|
fi
|
|
119
126
|
|
|
@@ -141,8 +148,8 @@ EOF
|
|
|
141
148
|
# 4. Build branch lists
|
|
142
149
|
# -----------------------------
|
|
143
150
|
local abort_label="✖ Abort"
|
|
144
|
-
local
|
|
145
|
-
|
|
151
|
+
local threshold_ago
|
|
152
|
+
threshold_ago=$(date -v-"${days_threshold}d" +%s 2>/dev/null || date -d "${days_threshold} days ago" +%s 2>/dev/null)
|
|
146
153
|
|
|
147
154
|
# Get list of remote branches (without origin/ prefix)
|
|
148
155
|
local remote_branches
|
|
@@ -185,8 +192,8 @@ EOF
|
|
|
185
192
|
if [[ "$has_remote" == false && -n "$configured_upstream" ]]; then
|
|
186
193
|
# Had upstream but remote is gone = merged and deleted remotely
|
|
187
194
|
merged_branches+=("$entry")
|
|
188
|
-
elif [[ -n "$last_commit_ts" && "$last_commit_ts" -lt "$
|
|
189
|
-
# Stale: no commits in
|
|
195
|
+
elif [[ -n "$last_commit_ts" && "$last_commit_ts" -lt "$threshold_ago" ]]; then
|
|
196
|
+
# Stale: no commits in N+ days (pre-select for deletion)
|
|
190
197
|
stale_branches+=("$entry")
|
|
191
198
|
else
|
|
192
199
|
# Recent: has recent activity (don't pre-select)
|
|
@@ -458,6 +465,16 @@ Found $total_count branches ($preselect_count pre-selected for deletion)" \
|
|
|
458
465
|
fi
|
|
459
466
|
echo ""
|
|
460
467
|
|
|
468
|
+
# Handle dry-run mode
|
|
469
|
+
if [[ "$dry_run" == true ]]; then
|
|
470
|
+
print_info "Dry run mode - no branches will be deleted"
|
|
471
|
+
echo "Would delete ${#branches_to_delete[@]} branch(es):"
|
|
472
|
+
for branch in "${branches_to_delete[@]}"; do
|
|
473
|
+
echo " - $branch"
|
|
474
|
+
done
|
|
475
|
+
return 0
|
|
476
|
+
fi
|
|
477
|
+
|
|
461
478
|
# Default to Y if only merged branches, otherwise N
|
|
462
479
|
local confirm
|
|
463
480
|
if [[ "$only_merged" == true ]]; then
|
|
@@ -482,20 +499,20 @@ Found $total_count branches ($preselect_count pre-selected for deletion)" \
|
|
|
482
499
|
|
|
483
500
|
# Switch to base branch if needed
|
|
484
501
|
if [[ "$need_switch" == true ]]; then
|
|
485
|
-
|
|
502
|
+
print_info "Switching to '$base_branch'..."
|
|
486
503
|
git checkout "$base_branch" || {
|
|
487
|
-
|
|
504
|
+
print_warning "Failed to switch to '$base_branch'. Aborting deletion."
|
|
488
505
|
return 1
|
|
489
506
|
}
|
|
490
507
|
fi
|
|
491
508
|
|
|
492
|
-
|
|
509
|
+
print_info "Deleting branches..."
|
|
493
510
|
for branch in "${branches_to_delete[@]}"; do
|
|
494
511
|
echo "Deleting $branch ..."
|
|
495
512
|
if git branch -D "$branch" 2>/dev/null; then
|
|
496
|
-
|
|
513
|
+
print_success "Deleted $branch"
|
|
497
514
|
else
|
|
498
|
-
|
|
515
|
+
print_error "Failed to delete $branch"
|
|
499
516
|
fi
|
|
500
517
|
done
|
|
501
518
|
}
|