gitbash 0.1.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Matthias Jäggli
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,194 @@
1
+ # gitbash
2
+
3
+ Interactive git utilities for bash with fzf-powered menus.
4
+
5
+ ## Installation
6
+
7
+ ### Via npm
8
+
9
+ ```bash
10
+ npm i -g gitbash
11
+ ```
12
+
13
+ Run `gitbash --help` for more options.
14
+
15
+ ### Shell Aliases
16
+
17
+ Add these aliases to your `.zshrc` or `.bashrc` for individual command access:
18
+
19
+ ```bash
20
+ alias branch="gitbash branch"
21
+ alias cleanstash="gitbash cleanstash"
22
+ alias cleanup="gitbash cleanup"
23
+ alias commit="gitbash commit"
24
+ alias commits="gitbash commits"
25
+ alias create="gitbash create"
26
+ alias pr="gitbash pr"
27
+ alias stale="gitbash stale"
28
+ alias stash="gitbash stash"
29
+ alias stashes="gitbash stashes"
30
+ alias status="gitbash status"
31
+ alias switch="gitbash switch"
32
+ alias unstash="gitbash unstash"
33
+ alias update="gitbash update"
34
+ ```
35
+
36
+ Or use the built-in shell integration, for all commands:
37
+
38
+ ```bash
39
+ eval "$(gitbash --init)"
40
+ ```
41
+
42
+ ### Dependencies
43
+
44
+ ```bash
45
+ # Required
46
+ brew install fzf
47
+
48
+ # Optional (recommended)
49
+ brew install git-delta # Better diff highlighting
50
+ brew install bat # File preview with syntax highlighting
51
+ ```
52
+
53
+ ## Commands
54
+
55
+ ### branch
56
+
57
+ Interactive menu for branch operations (create/switch/update).
58
+
59
+ ### create
60
+
61
+ ```bash
62
+ create [JIRA_LINK|ISSUE] [TITLE...]
63
+ ```
64
+
65
+ Create feature branch with Jira parsing. Updates main first, pushes and tracks.
66
+
67
+ ```bash
68
+ create PROJ-123 fix login bug # → feature/PROJ-123-fix-login-bug
69
+ create # Interactive mode
70
+ ```
71
+
72
+ ### switch
73
+
74
+ ```bash
75
+ switch [FILTER...]
76
+ ```
77
+
78
+ Switch branches with fzf. Shows local first, then remotes (deduped). Preview shows commit history.
79
+
80
+ ```bash
81
+ switch # Browse all branches
82
+ switch captcha # Pre-filter for "captcha"
83
+ ```
84
+
85
+ ### commit
86
+
87
+ ```bash
88
+ commit [MESSAGE] [-p|--push] [-s|--staged]
89
+ ```
90
+
91
+ Commit with optional push. Smart staging: prompts if both staged/unstaged exist.
92
+
93
+ ```bash
94
+ commit fix bug # Commit all
95
+ commit -s fix bug # Commit staged only
96
+ commit -p add feature # Commit and push
97
+ ```
98
+
99
+ ### status
100
+
101
+ Interactive staging with fzf. Toggle files with Enter, ESC to exit. Shows diffs in preview.
102
+
103
+ ### pr
104
+
105
+ ```bash
106
+ pr [-p|--push]
107
+ ```
108
+
109
+ Open PR in browser. `-p` pushes first.
110
+
111
+ ### update
112
+
113
+ ```bash
114
+ update [-p|--push]
115
+ ```
116
+
117
+ Merge latest main/master into current branch. Opens merge tool on conflicts.
118
+
119
+ ### stale
120
+
121
+ ```bash
122
+ stale [-m|--my] [--json] [FILTER...]
123
+ ```
124
+
125
+ List remote branches >3 months old (oldest first). Multi-select with TAB to delete.
126
+
127
+ - `Ctrl-A` toggles showing all branches
128
+ - `--my` filters by your git username
129
+ - `--json` outputs JSON for scripting (same format as cleanup)
130
+
131
+ ### stashes
132
+
133
+ Interactive stash menu: create, apply, or delete stashes.
134
+
135
+ ### stash
136
+
137
+ ```bash
138
+ stash [NAME...]
139
+ ```
140
+
141
+ Create named stash (includes untracked files).
142
+
143
+ ### unstash
144
+
145
+ Apply stash with fzf picker. Optionally drop after applying.
146
+
147
+ ### cleanstash
148
+
149
+ Delete stashes (multi-select with TAB).
150
+
151
+ ### cleanup
152
+
153
+ ```bash
154
+ cleanup [--json]
155
+ ```
156
+
157
+ Find and delete leftover local branches. Shows all local branches categorized:
158
+
159
+ - **[MERGED]** - Remote was deleted (pre-selected)
160
+ - **[STALE]** - No commits in 7+ days (pre-selected)
161
+ - **[RECENT]** - Recent activity (not selected)
162
+
163
+ Switches to main/master first if current branch is selected for deletion.
164
+
165
+ `--json` outputs non-interactive JSON for scripting:
166
+
167
+ ```json
168
+ [
169
+ {
170
+ "last_change_timestamp": 1733123456,
171
+ "author_email": "dev@example.com",
172
+ "author_name": "Dev",
173
+ "name": "feature/old",
174
+ "last_change_relative": "2 weeks ago"
175
+ }
176
+ ]
177
+ ```
178
+
179
+ ### commits
180
+
181
+ ```bash
182
+ commits [COUNT]
183
+ ```
184
+
185
+ List recent commits with option to revert. Multi-select with TAB to revert multiple.
186
+
187
+ ```bash
188
+ commits # Show last 20 commits
189
+ commits 50 # Show last 50 commits
190
+ ```
191
+
192
+ ## License
193
+
194
+ See [LICENSE](LICENSE) file for details.
package/bin/gitbash ADDED
@@ -0,0 +1,124 @@
1
+ #!/usr/bin/env bash
2
+ # gitbash - Interactive git utilities for bash with fzf-powered menus
3
+
4
+ set -euo pipefail
5
+
6
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
7
+ COMMANDS_DIR="$SCRIPT_DIR/commands"
8
+
9
+ # Available commands
10
+ COMMANDS=(
11
+ "branch"
12
+ "cleanstash"
13
+ "cleanup"
14
+ "commit"
15
+ "commits"
16
+ "create"
17
+ "pr"
18
+ "stale"
19
+ "stash"
20
+ "stashes"
21
+ "status"
22
+ "switch"
23
+ "unstash"
24
+ "update"
25
+ )
26
+
27
+ show_help() {
28
+ cat << 'EOF'
29
+ gitbash - Interactive git utilities for bash
30
+
31
+ Usage:
32
+ gitbash <command> [args...]
33
+ gitbash --help
34
+ gitbash --init
35
+
36
+ Commands:
37
+ branch Interactive menu for branch operations
38
+ cleanstash Delete stashes (multi-select)
39
+ cleanup Find and delete leftover local branches
40
+ commit Commit with optional push
41
+ commits List recent commits with revert option
42
+ create Create feature branch with Jira parsing
43
+ pr Open PR in browser
44
+ stale List stale remote branches
45
+ stash Create named stash
46
+ stashes Interactive stash menu
47
+ status Interactive staging with fzf
48
+ switch Switch branches with fzf
49
+ unstash Apply stash with fzf picker
50
+ update Merge latest main/master into current branch
51
+
52
+ Options:
53
+ -h, --help Show this help message
54
+ --init Print shell initialization code (for sourcing)
55
+
56
+ Examples:
57
+ gitbash commit fix bug -p # Commit and push
58
+ gitbash switch feature # Switch to branch containing "feature"
59
+ gitbash create PROJ-123 fix # Create feature/PROJ-123-fix
60
+
61
+ Shell Integration:
62
+ Add to your .bashrc or .bash_profile:
63
+ eval "$(gitbash --init)"
64
+
65
+ This enables calling commands directly:
66
+ commit fix bug -p
67
+ switch feature
68
+
69
+ Dependencies:
70
+ brew install fzf # Required
71
+ brew install git-delta # Optional: better diffs
72
+ brew install bat # Optional: syntax highlighting
73
+ EOF
74
+ }
75
+
76
+ show_init() {
77
+ cat << EOF
78
+ # gitbash shell integration
79
+ # Add this to your .bashrc or .bash_profile:
80
+ # eval "\$(gitbash --init)"
81
+
82
+ GITBASH_COMMANDS_DIR="$COMMANDS_DIR"
83
+
84
+ EOF
85
+ # Output source commands for each script
86
+ for cmd in "${COMMANDS[@]}"; do
87
+ if [[ -f "$COMMANDS_DIR/$cmd.sh" ]]; then
88
+ echo "source \"\$GITBASH_COMMANDS_DIR/$cmd.sh\""
89
+ fi
90
+ done
91
+ }
92
+
93
+ # Main entry point
94
+ main() {
95
+ case "${1:-}" in
96
+ -h|--help|"")
97
+ show_help
98
+ exit 0
99
+ ;;
100
+ --init)
101
+ show_init
102
+ exit 0
103
+ ;;
104
+ *)
105
+ local cmd="$1"
106
+ shift
107
+
108
+ # Check if command exists
109
+ if [[ -f "$COMMANDS_DIR/$cmd.sh" ]]; then
110
+ # Source the command file and execute the function
111
+ source "$COMMANDS_DIR/$cmd.sh"
112
+ "$cmd" "$@"
113
+ else
114
+ echo "Error: Unknown command '$cmd'" >&2
115
+ echo "Run 'gitbash --help' for available commands." >&2
116
+ exit 1
117
+ fi
118
+ ;;
119
+ esac
120
+ }
121
+
122
+ main "$@"
123
+
124
+
@@ -0,0 +1,184 @@
1
+ branch() {
2
+ # -----------------------------
3
+ # 0. Check for help flag
4
+ # -----------------------------
5
+ if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
6
+ cat << 'EOF'
7
+ Usage: branch [OPTIONS]
8
+
9
+ Interactive menu to manage git branches.
10
+ Choose between creating, switching, or updating branches.
11
+
12
+ Options:
13
+ -h, --help Show this help message
14
+
15
+ Features:
16
+ - Interactive action selection
17
+ - Create: Create a new branch with Jira issue parsing
18
+ - Switch: Switch between branches with fzf selector
19
+ - Update: Update current branch with latest main/master
20
+
21
+ Navigation:
22
+ ↑/↓ or j/k Navigate through options
23
+ Enter Select action
24
+ ESC/Ctrl-C Abort
25
+
26
+ Examples:
27
+ $ branch
28
+ Branch action >
29
+ > 🌿 Create - Create a new feature branch
30
+ 🔀 Switch - Switch to another branch
31
+ ⬆️ Update - Update current branch with main/master
32
+ ✖ Abort
33
+
34
+ # Select "Create" and press Enter
35
+ Enter Jira link (e.g., https://jira.company.com/browse/PROJ-123):
36
+ > PROJ-123
37
+ Parsed issue number: PROJ-123
38
+
39
+ Enter branch title (will be converted to lowercase with dashes):
40
+ > add new feature
41
+
42
+ Branch name: feature/PROJ-123-add-new-feature
43
+ Updating 'main' from origin...
44
+ ✓ 'main' is up to date.
45
+ ✓ Successfully created and switched to branch: feature/PROJ-123-add-new-feature (from main)
46
+
47
+ ---
48
+
49
+ $ branch
50
+ Branch action >
51
+ > 🌿 Create - Create a new feature branch
52
+ 🔀 Switch - Switch to another branch
53
+ ⬆️ Update - Update current branch with main/master
54
+ ✖ Abort
55
+
56
+ # Select "Switch" and press Enter
57
+ Select branch:
58
+ Current: main
59
+ > local: main
60
+ local: feature/PROJ-123-add-new-feature
61
+ remote: origin/develop
62
+
63
+ ---
64
+
65
+ $ branch
66
+ Branch action >
67
+ > 🌿 Create - Create a new feature branch
68
+ 🔀 Switch - Switch to another branch
69
+ ⬆️ Update - Update current branch with main/master
70
+ ✖ Abort
71
+
72
+ # Select "Update" and press Enter
73
+ Fetching latest 'main' from origin...
74
+ Merging updated 'main' into 'feature/PROJ-123-add-new-feature'...
75
+ ✓ 'feature/PROJ-123-add-new-feature' is now up-to-date with 'main'.
76
+
77
+ Actions:
78
+ 🌿 Create - Create a new feature branch with Jira parsing
79
+ 🔀 Switch - Switch to another branch using fzf
80
+ ⬆️ Update - Update current branch with latest main/master
81
+
82
+ Requirements:
83
+ - fzf (fuzzy finder) - will prompt to install if not found
84
+ - create, switch, and update functions must be available
85
+
86
+ See also:
87
+ create -h Show help for create command
88
+ switch -h Show help for switch command
89
+ update -h Show help for update command
90
+
91
+ EOF
92
+ return 0
93
+ fi
94
+
95
+ # -----------------------------
96
+ # 1. Check for fzf
97
+ # -----------------------------
98
+ if ! command -v fzf >/dev/null 2>&1; then
99
+ echo "fzf is not installed."
100
+
101
+ # Ask whether to install with Homebrew
102
+ read -rp "Install fzf with Homebrew? (y/N): " ans
103
+ case "$ans" in
104
+ [yY][eE][sS]|[yY])
105
+ echo "Installing fzf with brew..."
106
+ if ! command -v brew >/dev/null 2>&1; then
107
+ echo "Homebrew is not installed. Aborting."
108
+ return 1
109
+ fi
110
+ brew install fzf || { echo "fzf install failed. Aborting."; return 1; }
111
+ # Optional: install shell integrations automatically
112
+ if [[ -f "$(brew --prefix)/opt/fzf/install" ]]; then
113
+ echo "Running fzf install script..."
114
+ yes | "$(brew --prefix)/opt/fzf/install"
115
+ fi
116
+ ;;
117
+ *)
118
+ echo "Aborted (skipped fzf installation)."
119
+ return 1
120
+ ;;
121
+ esac
122
+ fi
123
+
124
+ # -----------------------------
125
+ # 2. Build action menu
126
+ # -----------------------------
127
+ local create_option="🌿 Create - Create a new feature branch"
128
+ local switch_option="🔀 Switch - Switch to another branch"
129
+ local update_option="⬆️ Update - Update current branch with main/master"
130
+ local abort_label="✖ Abort"
131
+
132
+ local choices
133
+ choices=$(
134
+ {
135
+ echo "$create_option"
136
+ echo "$switch_option"
137
+ echo "$update_option"
138
+ echo "$abort_label"
139
+ }
140
+ )
141
+
142
+ # -----------------------------
143
+ # 3. Run fzf menu
144
+ # -----------------------------
145
+ local selection
146
+ selection=$(printf "%s\n" "$choices" \
147
+ | fzf --prompt="Branch action > " \
148
+ -i \
149
+ --reverse \
150
+ --border \
151
+ --header="What would you like to do?" \
152
+ --no-multi \
153
+ --bind=enter:accept
154
+ )
155
+
156
+ # ESC or Ctrl-C
157
+ if [[ -z "$selection" ]]; then
158
+ echo "Aborted."
159
+ return 1
160
+ fi
161
+
162
+ # -----------------------------
163
+ # 4. Execute based on selection
164
+ # -----------------------------
165
+ case "$selection" in
166
+ "$create_option")
167
+ create
168
+ ;;
169
+ "$switch_option")
170
+ switch
171
+ ;;
172
+ "$update_option")
173
+ update
174
+ ;;
175
+ "$abort_label")
176
+ echo "Aborted."
177
+ return 1
178
+ ;;
179
+ *)
180
+ echo "Unknown selection."
181
+ return 1
182
+ ;;
183
+ esac
184
+ }
@@ -0,0 +1,187 @@
1
+ cleanstash() {
2
+ # -----------------------------
3
+ # 0. Check for help flag
4
+ # -----------------------------
5
+ if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
6
+ cat << 'EOF'
7
+ Usage: cleanstash [OPTIONS]
8
+
9
+ Delete git stashes without applying them.
10
+ Interactive fuzzy finder (fzf) with preview and multi-select support.
11
+
12
+ Options:
13
+ -h, --help Show this help message
14
+
15
+ Features:
16
+ - Multi-select support (use TAB to select multiple stashes)
17
+ - Preview stash contents before deletion
18
+ - Confirmation prompt before deletion
19
+ - Safe deletion (deletes in reverse order to maintain indices)
20
+
21
+ Navigation:
22
+ ↑/↓ or j/k Navigate through stashes
23
+ TAB Select/deselect stash (multi-select)
24
+ Enter Confirm selection
25
+ ESC/Ctrl-C Abort
26
+
27
+ Examples:
28
+ $ cleanstash
29
+ Available stashes >
30
+ > stash@{0}: WIP on main: 1a2b3c4 commit message
31
+ stash@{1}: WIP on feature: 5d6e7f8 another commit
32
+ stash@{2}: On dev: 9a8b7c6 old work
33
+ ✖ Abort
34
+
35
+ # Select stash@{0} and stash@{2} using TAB, then press Enter
36
+
37
+ Selected stashes to delete:
38
+ - stash@{0}
39
+ - stash@{2}
40
+
41
+ Delete these 2 stash(es)? (y/N): y
42
+ Deleting stashes...
43
+ Dropping stash@{2} ...
44
+ ✓ Deleted stash@{2}
45
+ Dropping stash@{0} ...
46
+ ✓ Deleted stash@{0}
47
+
48
+ Requirements:
49
+ - fzf (fuzzy finder) - will prompt to install if not found
50
+ - git stash list with at least one stash
51
+
52
+ Notes:
53
+ - Stashes are deleted in reverse order to prevent index shifts
54
+ - Preview shows the full diff of the selected stash
55
+ - No changes are applied to your working directory
56
+
57
+ EOF
58
+ return 0
59
+ fi
60
+
61
+ # -----------------------------
62
+ # 1. Check for fzf
63
+ # -----------------------------
64
+ if ! command -v fzf >/dev/null 2>&1; then
65
+ echo "fzf is not installed."
66
+
67
+ # Ask whether to install with Homebrew
68
+ read -r -p "Install fzf with Homebrew? (y/N): " ans
69
+ case "$ans" in
70
+ [yY][eE][sS]|[yY])
71
+ echo "Installing fzf with brew..."
72
+ if ! command -v brew >/dev/null 2>&1; then
73
+ echo "Homebrew is not installed. Aborting."
74
+ return 1
75
+ fi
76
+ brew install fzf || { echo "fzf install failed. Aborting."; return 1; }
77
+ # Optional: install shell integrations automatically
78
+ if [[ -f "$(brew --prefix)/opt/fzf/install" ]]; then
79
+ echo "Running fzf install script..."
80
+ yes | "$(brew --prefix)/opt/fzf/install"
81
+ fi
82
+ ;;
83
+ *)
84
+ echo "Aborted (skipped fzf installation)."
85
+ return 1
86
+ ;;
87
+ esac
88
+ fi
89
+
90
+ # -----------------------------
91
+ # 2. Build menu entries
92
+ # -----------------------------
93
+ local abort_label="✖ Abort"
94
+
95
+ local choices
96
+ choices=$(
97
+ {
98
+ git stash list
99
+ echo "$abort_label"
100
+ }
101
+ )
102
+
103
+ # -----------------------------
104
+ # 3. Run fzf full-screen picker with preview (multi-select)
105
+ # -----------------------------
106
+ local selection
107
+ selection=$(printf "%s\n" "$choices" \
108
+ | fzf --prompt="Available stashes > " \
109
+ -i \
110
+ --reverse \
111
+ --border \
112
+ --header="Select stashes to delete (TAB for multi-select)" \
113
+ --multi \
114
+ --bind=enter:accept \
115
+ --preview='
116
+ sel=$(echo {} | grep -o "stash@{[0-9]\+}" || true);
117
+ if [[ -n "$sel" ]]; then
118
+ git stash show -p "$sel";
119
+ else
120
+ echo "No preview";
121
+ fi
122
+ '
123
+ )
124
+
125
+ # ESC or Ctrl-C
126
+ if [[ -z "$selection" ]]; then
127
+ echo "Aborted."
128
+ return 1
129
+ fi
130
+
131
+ # Abort option
132
+ if echo "$selection" | grep -q "^$abort_label$"; then
133
+ echo "Aborted."
134
+ return 1
135
+ fi
136
+
137
+ # -----------------------------
138
+ # 4. Extract stash IDs safely
139
+ # -----------------------------
140
+ local stash_ids=()
141
+ while IFS= read -r line; do
142
+ local stash_id
143
+ stash_id=$(echo "$line" | grep -o 'stash@{[0-9]\+}')
144
+ if [[ -n "$stash_id" ]]; then
145
+ stash_ids+=("$stash_id")
146
+ fi
147
+ done <<< "$selection"
148
+
149
+ if [[ ${#stash_ids[@]} -eq 0 ]]; then
150
+ echo "Error: Could not determine any stash IDs."
151
+ return 1
152
+ fi
153
+
154
+ # -----------------------------
155
+ # 5. Confirm before deletion
156
+ # -----------------------------
157
+ echo "Selected stashes to delete:"
158
+ for stash_id in "${stash_ids[@]}"; do
159
+ echo " - $stash_id"
160
+ done
161
+ echo
162
+
163
+ read -rp "Delete these ${#stash_ids[@]} stash(es)? (y/N): " confirm_ans
164
+ case "$confirm_ans" in
165
+ [yY][eE][sS]|[yY])
166
+ # -----------------------------
167
+ # 6. Delete stashes (in reverse order to maintain indices)
168
+ # -----------------------------
169
+ echo "Deleting stashes..."
170
+ # Sort by stash number in descending order to delete safely
171
+ local sorted_ids
172
+ mapfile -t sorted_ids < <(printf '%s\n' "${stash_ids[@]}" | sort -t'{' -k2 -rn)
173
+
174
+ for stash_id in "${sorted_ids[@]}"; do
175
+ echo "Dropping $stash_id ..."
176
+ if git stash drop "$stash_id"; then
177
+ echo "✓ Deleted $stash_id"
178
+ else
179
+ echo "✗ Failed to delete $stash_id"
180
+ fi
181
+ done
182
+ ;;
183
+ *)
184
+ echo "Deletion cancelled. No stashes were removed."
185
+ ;;
186
+ esac
187
+ }