gitbasher 5.2.1 → 5.3.1
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/CHANGELOG.md +18 -0
- package/README.md +6 -2
- package/dist/gitb +167 -25
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to gitbasher are generated automatically by [semantic-release](https://github.com/semantic-release/semantic-release) from [Conventional Commits](https://www.conventionalcommits.org/) on `main`. The project follows [Semantic Versioning](https://semver.org/).
|
|
4
4
|
|
|
5
|
+
## [5.3.1](https://github.com/maxbolgarin/gitbasher/compare/v5.3.0...v5.3.1) (2026-10-13)
|
|
6
|
+
|
|
7
|
+
### 🐛 Bug Fixes
|
|
8
|
+
|
|
9
|
+
* **push:** avoid fatal errors when pushing a branch with no own commits ([d8ff3f8](https://github.com/maxbolgarin/gitbasher/commit/d8ff3f83340101f8d4992bcecebac443d5fa8e8e))
|
|
10
|
+
|
|
11
|
+
## [5.3.0](https://github.com/maxbolgarin/gitbasher/compare/v5.2.1...v5.3.0) (2026-09-30)
|
|
12
|
+
|
|
13
|
+
### 🚀 Features
|
|
14
|
+
|
|
15
|
+
* **config:** add `gitb cfg fast-split` to toggle split in fast modes ([c56e173](https://github.com/maxbolgarin/gitbasher/commit/c56e1735efeaea8c71f83e5d983cd24ff26fcd2b))
|
|
16
|
+
* **commit:** ask before splitting, add undo split and fast-split setting ([1de1fcd](https://github.com/maxbolgarin/gitbasher/commit/1de1fcd523b5080da0c8248347558a421c8d72bb))
|
|
17
|
+
* **commit:** show undo-split hint in the split type menu ([520e66a](https://github.com/maxbolgarin/gitbasher/commit/520e66aec25b43b7fb83b27f863cc6af4a0ab0e2))
|
|
18
|
+
|
|
19
|
+
### 🐛 Bug Fixes
|
|
20
|
+
|
|
21
|
+
* **branch:** pass HEAD to --merged when deleting merged branches ([2cdaf58](https://github.com/maxbolgarin/gitbasher/commit/2cdaf58c3a92e9f26eba47bd180b582cb9676d04))
|
|
22
|
+
|
|
5
23
|
## [5.2.1](https://github.com/maxbolgarin/gitbasher/compare/v5.2.0...v5.2.1) (2026-07-11)
|
|
6
24
|
|
|
7
25
|
### 🐛 Bug Fixes
|
package/README.md
CHANGED
|
@@ -360,7 +360,7 @@ gitb commit <combined> # compact form: ff, aifp, fastsp, ...
|
|
|
360
360
|
| `staged` | `st` | Use already-staged files (skip the add step) |
|
|
361
361
|
| `push` | `p` `pu` | Push after the commit succeeds |
|
|
362
362
|
| `scope` | `s` | Force a scope: `type(scope): message` (useful with fast mode) |
|
|
363
|
-
| `no-split` | `nsp` `nsl` |
|
|
363
|
+
| `no-split` | `nos` `nsp` `nsl` | Don't offer to split this commit (fast modes split by default) |
|
|
364
364
|
| `ai` | `i` `llm` | Generate the commit message with AI |
|
|
365
365
|
| `msg` | `m` | Open `$EDITOR` for a multiline message body |
|
|
366
366
|
| `ticket` | `t` `j` `jira` | Append ticket info to the header |
|
|
@@ -383,6 +383,8 @@ gitb commit <combined> # compact form: ff, aifp, fastsp, ...
|
|
|
383
383
|
- Word order doesn't matter: `ai fast push` == `push fast ai` == `aifp`.
|
|
384
384
|
- Modifiers stack on actions: `ai+fixup`, `fast+amend`, `split+push`, `ai+staged`, …
|
|
385
385
|
- `fast` and `staged` are mutually exclusive (one stages all, the other uses what's staged).
|
|
386
|
+
- Splitting: a regular commit **asks first** whether to try a split (before any grouping or AI work), then asks again to confirm the resulting groups. Fast modes (`fast`, `ff`, …) split without asking unless you turn it off with `gitb cfg fast-split`.
|
|
387
|
+
- Press `u` at any split prompt to **undo the split**: commits already made by the split are dropped, staging is restored, and you continue with a single commit. `ff` never stops, so use the setting or `no-split` there.
|
|
386
388
|
- `revert` and `ff` only accept `push` (as `revp` / `ffp`); to rewrite the last commit message use [`gitb edit`](#gitb-edit).
|
|
387
389
|
|
|
388
390
|
### `gitb edit`
|
|
@@ -804,6 +806,7 @@ gitb origin remove # delete the remote
|
|
|
804
806
|
| `history` | `hist` | How many recent commits to include in AI prompts |
|
|
805
807
|
| `diff` | `payload` | AI diff payload size (line and character caps) |
|
|
806
808
|
| `push-size` | `ps` `pushsize` | Warn before pushing more than N MB (0 disables) |
|
|
809
|
+
| `fast-split` | `fs` `fastsplit` | Split automatically in fast commit modes (on/off) |
|
|
807
810
|
| `completion` | `comp` | Install / uninstall bash & zsh tab completion |
|
|
808
811
|
| `delete` | `unset` `del` | Remove global config |
|
|
809
812
|
|
|
@@ -890,7 +893,8 @@ Overview-first diffs built for the gitbasher workflow — no flag memorization.
|
|
|
890
893
|
| `gitbasher.ai-commit-history-limit` | `gitb cfg history` | Recent commits included in AI prompts (default `10`) |
|
|
891
894
|
| `gitbasher.push-warn-size` | `gitb cfg push-size` | Warn before pushing more than N MB (default `50`, `0` disables) |
|
|
892
895
|
| `gitbasher.worktreebase` | `git config gitbasher.worktreebase <dir>` | Base directory for new worktrees (default `.worktree` under the repo root) |
|
|
893
|
-
| `gitbasher.commit-auto-split` | `git config gitbasher.commit-auto-split <ask\|always\|never>` | Offer to split a commit per scope (default `ask
|
|
896
|
+
| `gitbasher.commit-auto-split` | `git config gitbasher.commit-auto-split <ask\|always\|never>` | Offer to split a commit per scope (default `ask`: ask before splitting, then confirm the groups) |
|
|
897
|
+
| `gitbasher.commit-fast-split` | `gitb cfg fast-split` | Fast modes split automatically (default `true`); `false` makes `fast` ask and `ff` commit as one |
|
|
894
898
|
| `gitbasher.commit-max-split-groups` | `git config gitbasher.commit-max-split-groups <2..20>` | Cap on split commits per run (default `7`) |
|
|
895
899
|
| `gitbasher.commit-split-order` | `git config gitbasher.commit-split-order <auto\|alpha>` | Order split commits by dependency (`auto`, default) or alphabetically (`alpha`) |
|
|
896
900
|
| `gitbasher.commit-ai-grouping` | `git config gitbasher.commit-ai-grouping <never\|auto\|always>` | AI feature grouping for commit splits (default `auto`) |
|
package/dist/gitb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
set -o pipefail
|
|
3
|
-
GITBASHER_VERSION="5.
|
|
3
|
+
GITBASHER_VERSION="5.3.1"
|
|
4
4
|
if [ "$1" == "init" ] || [ "$1" == "i" ]; then
|
|
5
5
|
git init
|
|
6
6
|
fi
|
|
@@ -948,6 +948,11 @@ function print_configuration {
|
|
|
948
948
|
else
|
|
949
949
|
echo -e "\tPush warn:\t${GREEN}${push_warn} MB${ENDCOLOR} $(config_source_tag gitbasher.push-warn-size)"
|
|
950
950
|
fi
|
|
951
|
+
if [ "$(get_fast_split)" = "true" ]; then
|
|
952
|
+
echo -e "\tFast split:\t${GREEN}auto${ENDCOLOR} $(config_source_tag gitbasher.commit-fast-split)"
|
|
953
|
+
else
|
|
954
|
+
echo -e "\tFast split:\t${YELLOW}off${ENDCOLOR} $(config_source_tag gitbasher.commit-fast-split)"
|
|
955
|
+
fi
|
|
951
956
|
echo
|
|
952
957
|
echo -e "${GRAY}Source:${ENDCOLOR} ${BLUE}(project)${ENDCOLOR}${GRAY} this repo,${ENDCOLOR} ${PURPLE}(global)${ENDCOLOR}${GRAY} ~/.gitconfig,${ENDCOLOR} ${GRAY}(default) built-in fallback${ENDCOLOR}"
|
|
953
958
|
}
|
|
@@ -1204,6 +1209,14 @@ function get_push_warn_size {
|
|
|
1204
1209
|
function set_push_warn_size {
|
|
1205
1210
|
set_config_value gitbasher.push-warn-size "$1"
|
|
1206
1211
|
}
|
|
1212
|
+
function get_fast_split {
|
|
1213
|
+
local v
|
|
1214
|
+
v=$(get_config_value gitbasher.commit-fast-split "true")
|
|
1215
|
+
if [ "$v" = "false" ]; then echo "false"; else echo "true"; fi
|
|
1216
|
+
}
|
|
1217
|
+
function set_fast_split {
|
|
1218
|
+
set_config_value gitbasher.commit-fast-split "$1"
|
|
1219
|
+
}
|
|
1207
1220
|
function human_size {
|
|
1208
1221
|
local bytes="${1:-0}"
|
|
1209
1222
|
case "$bytes" in ''|*[!0-9]*) bytes=0;; esac
|
|
@@ -1259,17 +1272,18 @@ function get_push_list {
|
|
|
1259
1272
|
fi
|
|
1260
1273
|
fi
|
|
1261
1274
|
base_commit=$(diff -u <(git rev-list --first-parent "$1" 2>/dev/null) <(git rev-list --first-parent "$2" 2>/dev/null) | sed -ne 's/^ //p' | head -1 || true)
|
|
1275
|
+
if [ -z "$base_commit" ]; then
|
|
1276
|
+
base_commit=$(git merge-base "$1" "$2" 2>/dev/null || true)
|
|
1277
|
+
fi
|
|
1262
1278
|
if [ -n "$base_commit" ]; then
|
|
1263
1279
|
push_list=$(commit_list 999 "tab" "$base_commit..HEAD")
|
|
1264
1280
|
history_from="${base_commit::7}"
|
|
1281
|
+
elif git rev-parse --verify --quiet "$origin/$2" >/dev/null 2>&1; then
|
|
1282
|
+
push_list=$(commit_list 999 "tab" "$origin/$2..HEAD")
|
|
1283
|
+
history_from="$origin/$2"
|
|
1265
1284
|
else
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
history_from=""
|
|
1269
|
-
else
|
|
1270
|
-
push_list=$(commit_list 999 "tab" "$origin/$2..HEAD")
|
|
1271
|
-
history_from="$origin/$2"
|
|
1272
|
-
fi
|
|
1285
|
+
push_list=$(commit_list 999 "tab")
|
|
1286
|
+
history_from="HEAD"
|
|
1273
1287
|
fi
|
|
1274
1288
|
}
|
|
1275
1289
|
function list_branches {
|
|
@@ -3691,6 +3705,40 @@ function configure_push_warn_size {
|
|
|
3691
3705
|
yes_no_choice "\nSet push size warning globally" "true"
|
|
3692
3706
|
git config --global gitbasher.push-warn-size "$limit_input"
|
|
3693
3707
|
}
|
|
3708
|
+
function configure_fast_split {
|
|
3709
|
+
echo -e "${YELLOW}Configure Fast Mode Split${ENDCOLOR}"
|
|
3710
|
+
echo
|
|
3711
|
+
if [ "$(get_fast_split)" = "true" ]; then
|
|
3712
|
+
echo -e "Current: ${GREEN}auto${ENDCOLOR} (fast modes split without asking)"
|
|
3713
|
+
else
|
|
3714
|
+
echo -e "Current: ${YELLOW}off${ENDCOLOR} (fast asks first, ff commits everything as one)"
|
|
3715
|
+
fi
|
|
3716
|
+
echo
|
|
3717
|
+
echo -e "When staged changes span several scopes, fast commit modes (${BLUE}fast${ENDCOLOR}, ${BLUE}ff${ENDCOLOR}, ...)"
|
|
3718
|
+
echo -e "split them into atomic commits without asking. Turn it off to have ${BLUE}fast${ENDCOLOR}"
|
|
3719
|
+
echo -e "ask first (like a regular commit) and ${BLUE}ff${ENDCOLOR} make a single commit."
|
|
3720
|
+
echo
|
|
3721
|
+
echo -e "1. ${GREEN}auto${ENDCOLOR}:\tsplit automatically in fast modes"
|
|
3722
|
+
echo -e "2. ${YELLOW}off${ENDCOLOR}:\tdon't split by default in fast modes"
|
|
3723
|
+
echo -e "0. Exit without changes"
|
|
3724
|
+
local choice value label
|
|
3725
|
+
while true; do
|
|
3726
|
+
read_key choice || exit
|
|
3727
|
+
case "$choice" in
|
|
3728
|
+
1) value="true"; label="auto"; break ;;
|
|
3729
|
+
2) value="false"; label="off"; break ;;
|
|
3730
|
+
0) exit ;;
|
|
3731
|
+
esac
|
|
3732
|
+
done
|
|
3733
|
+
echo
|
|
3734
|
+
set_fast_split "$value" >/dev/null
|
|
3735
|
+
echo -e "${GREEN}✓ Set fast mode split to ${label} for '${project_name}'${ENDCOLOR}"
|
|
3736
|
+
echo
|
|
3737
|
+
[ "$GITBASHER_NO_REPO" = "true" ] && exit
|
|
3738
|
+
echo -e "Do you want to set it ${YELLOW}globally${ENDCOLOR} for all projects (Y/n)?"
|
|
3739
|
+
yes_no_choice "\nSet fast mode split globally" "true"
|
|
3740
|
+
set_config_value gitbasher.commit-fast-split "$value" "true" >/dev/null
|
|
3741
|
+
}
|
|
3694
3742
|
function configure_ai_diff {
|
|
3695
3743
|
echo -e "${YELLOW}Configure AI Diff Payload Size${ENDCOLOR}"
|
|
3696
3744
|
echo
|
|
@@ -3852,6 +3900,8 @@ function delete_global {
|
|
|
3852
3900
|
_delete_global_add "gitbasher.ai-commit-history-limit" "AI commit history limit" "$global_ai_history" "$GREEN"
|
|
3853
3901
|
local global_push_warn=$(git config --global --get gitbasher.push-warn-size)
|
|
3854
3902
|
_delete_global_add "gitbasher.push-warn-size" "Push size warning" "${global_push_warn:+${global_push_warn} MB}" "$GREEN"
|
|
3903
|
+
local global_fast_split=$(git config --global --get gitbasher.commit-fast-split)
|
|
3904
|
+
_delete_global_add "gitbasher.commit-fast-split" "Fast mode split" "$global_fast_split" "$GREEN"
|
|
3855
3905
|
local global_ai_diff_lines=$(git config --global --get gitbasher.ai-diff-limit)
|
|
3856
3906
|
local global_ai_diff_chars=$(git config --global --get gitbasher.ai-diff-max-chars)
|
|
3857
3907
|
if [ -n "$global_ai_diff_lines" ] || [ -n "$global_ai_diff_chars" ]; then
|
|
@@ -3949,6 +3999,7 @@ function config_script {
|
|
|
3949
3999
|
history|hist) set_ai_history_cfg="true";;
|
|
3950
4000
|
diff|payload) set_ai_diff_cfg="true";;
|
|
3951
4001
|
push-size|pushsize|ps) set_push_warn_cfg="true";;
|
|
4002
|
+
fast-split|fastsplit|fs) set_fast_split_cfg="true";;
|
|
3952
4003
|
delete|unset|del) delete_cfg="true";;
|
|
3953
4004
|
user|name|email|u) set_user_cfg="true";;
|
|
3954
4005
|
auto|completion|comp) auto_cfg="true";;
|
|
@@ -3982,6 +4033,8 @@ function config_script {
|
|
|
3982
4033
|
header="$header AI DIFF PAYLOAD"
|
|
3983
4034
|
elif [ -n "${set_push_warn_cfg}" ]; then
|
|
3984
4035
|
header="$header PUSH SIZE WARNING"
|
|
4036
|
+
elif [ -n "${set_fast_split_cfg}" ]; then
|
|
4037
|
+
header="$header FAST MODE SPLIT"
|
|
3985
4038
|
elif [ -n "${delete_cfg}" ]; then
|
|
3986
4039
|
header="$header UNSET GLOBAL CONFIG"
|
|
3987
4040
|
elif [ -n "${set_user_cfg}" ]; then
|
|
@@ -4055,6 +4108,10 @@ function config_script {
|
|
|
4055
4108
|
configure_push_warn_size
|
|
4056
4109
|
exit
|
|
4057
4110
|
fi
|
|
4111
|
+
if [ "$set_fast_split_cfg" == "true" ]; then
|
|
4112
|
+
configure_fast_split
|
|
4113
|
+
exit
|
|
4114
|
+
fi
|
|
4058
4115
|
if [ "$delete_cfg" == "true" ]; then
|
|
4059
4116
|
delete_global
|
|
4060
4117
|
exit
|
|
@@ -4083,6 +4140,7 @@ function config_script {
|
|
|
4083
4140
|
print_help_row $PAD "history" "hist" "Set how many recent commits to include in AI prompts"
|
|
4084
4141
|
print_help_row $PAD "diff" "payload" "Set the diff payload size (lines and char cap) sent to AI"
|
|
4085
4142
|
print_help_row $PAD "push-size" "ps, pushsize" "Warn before pushing more than N MB (0 disables)"
|
|
4143
|
+
print_help_row $PAD "fast-split" "fs, fastsplit" "Split automatically in fast commit modes (on/off)"
|
|
4086
4144
|
print_help_row $PAD "auto" "completion, comp" "Install/remove tab completion for bash, zsh, or fish"
|
|
4087
4145
|
print_help_row $PAD "delete" "unset, del" "Unset a global gitbasher configuration value"
|
|
4088
4146
|
print_help_row $PAD "help" "h" "Show this help"
|
|
@@ -7295,11 +7353,35 @@ function _restore_split_snapshot {
|
|
|
7295
7353
|
done < "$snapshot"
|
|
7296
7354
|
rm -f "$snapshot"
|
|
7297
7355
|
}
|
|
7356
|
+
function _undo_commit_split {
|
|
7357
|
+
local start_head="$1"
|
|
7358
|
+
local orig_tree="$2"
|
|
7359
|
+
local snapshot="$3"
|
|
7360
|
+
local made="$4"
|
|
7361
|
+
if [ "${made:-0}" -gt 0 ]; then
|
|
7362
|
+
if [ -n "$start_head" ]; then
|
|
7363
|
+
git reset -q --soft "$start_head" >/dev/null 2>&1
|
|
7364
|
+
else
|
|
7365
|
+
git update-ref -d HEAD >/dev/null 2>&1
|
|
7366
|
+
fi
|
|
7367
|
+
fi
|
|
7368
|
+
if [ -n "$orig_tree" ] && git read-tree "$orig_tree" >/dev/null 2>&1; then
|
|
7369
|
+
rm -f "$snapshot"
|
|
7370
|
+
else
|
|
7371
|
+
_restore_split_snapshot "$snapshot"
|
|
7372
|
+
fi
|
|
7373
|
+
}
|
|
7298
7374
|
function print_split_type_menu {
|
|
7299
7375
|
local scope="$1"
|
|
7300
7376
|
local ai_available="$2"
|
|
7377
|
+
local made="${3:-0}"
|
|
7301
7378
|
echo -e "${YELLOW}What type of changes for ${BLUE}${BOLD}${scope}${ENDCOLOR}${YELLOW}?${ENDCOLOR}"
|
|
7302
7379
|
echo -e "Final message will be ${YELLOW}<type>${ENDCOLOR}(${BLUE}<scope>${ENDCOLOR}): ${BLUE}<summary>${ENDCOLOR}"
|
|
7380
|
+
if [ "$made" -gt 0 ]; then
|
|
7381
|
+
echo -e "${GRAY}Changes were split into groups — press ${ENDCOLOR}${BOLD}u${NORMAL}${GRAY} to undo the split (drops the ${made} split commit(s) made so far) and commit everything at once.${ENDCOLOR}"
|
|
7382
|
+
else
|
|
7383
|
+
echo -e "${GRAY}Changes were split into groups — press ${ENDCOLOR}${BOLD}u${NORMAL}${GRAY} to undo the split and commit everything at once.${ENDCOLOR}"
|
|
7384
|
+
fi
|
|
7303
7385
|
echo -e "1. ${BOLD}feat${ENDCOLOR}:\tnew feature, logic change or performance improvement"
|
|
7304
7386
|
echo -e "2. ${BOLD}fix${ENDCOLOR}:\t\tsmall changes, eg. bug fix"
|
|
7305
7387
|
echo -e "3. ${BOLD}refactor${ENDCOLOR}:\tcode change that neither fixes a bug nor adds a feature, style changes"
|
|
@@ -7313,6 +7395,7 @@ function print_split_type_menu {
|
|
|
7313
7395
|
echo -e "g. ${GREEN}${BOLD}ai${ENDCOLOR}:\t\tgenerate commit message using AI"
|
|
7314
7396
|
fi
|
|
7315
7397
|
echo -e "s. ${YELLOW}${BOLD}skip${ENDCOLOR}:\tSkip this group and leave its files unstaged"
|
|
7398
|
+
echo -e "u. ${CYAN}${BOLD}undo${ENDCOLOR}:\tUndo split and commit all changes as a single commit"
|
|
7316
7399
|
echo -e "0. ${RED}${BOLD}abort${ENDCOLOR}:\tAbort split and restore original staging"
|
|
7317
7400
|
echo
|
|
7318
7401
|
}
|
|
@@ -7386,7 +7469,7 @@ function run_split_ai_for_scope {
|
|
|
7386
7469
|
echo
|
|
7387
7470
|
echo -e "${GREEN}AI suggestion:${ENDCOLOR} ${BOLD}$ai_msg${ENDCOLOR}"
|
|
7388
7471
|
echo
|
|
7389
|
-
read_key choice "Use it? (y/e to edit/r to regenerate/s to skip group/0 to abort) " || choice="0"
|
|
7472
|
+
read_key choice "Use it? (y/e to edit/r to regenerate/s to skip group/u to undo split/0 to abort) " || choice="0"
|
|
7390
7473
|
echo
|
|
7391
7474
|
normalize_key "$choice"
|
|
7392
7475
|
while [ "$normalized_key" = "r" ]; do
|
|
@@ -7406,7 +7489,7 @@ ${ai_msg}"
|
|
|
7406
7489
|
echo
|
|
7407
7490
|
echo -e "${GREEN}AI suggestion:${ENDCOLOR} ${BOLD}$ai_msg${ENDCOLOR}"
|
|
7408
7491
|
echo
|
|
7409
|
-
read_key choice "Use it? (y/e to edit/r to regenerate/s to skip group/0 to abort) " || choice="0"
|
|
7492
|
+
read_key choice "Use it? (y/e to edit/r to regenerate/s to skip group/u to undo split/0 to abort) " || choice="0"
|
|
7410
7493
|
echo
|
|
7411
7494
|
normalize_key "$choice"
|
|
7412
7495
|
done
|
|
@@ -7423,6 +7506,8 @@ ${ai_msg}"
|
|
|
7423
7506
|
[ -n "$f" ] && git restore --staged -- ":(top,literal)$f" >/dev/null 2>&1
|
|
7424
7507
|
done <<< "$_files_str"
|
|
7425
7508
|
return 2
|
|
7509
|
+
elif [ "$normalized_key" = "u" ]; then
|
|
7510
|
+
return 4
|
|
7426
7511
|
elif [ "$choice" = "0" ]; then
|
|
7427
7512
|
return 3
|
|
7428
7513
|
fi
|
|
@@ -7436,6 +7521,9 @@ function perform_commit_split {
|
|
|
7436
7521
|
return 1
|
|
7437
7522
|
fi
|
|
7438
7523
|
_capture_split_statuses
|
|
7524
|
+
local start_head orig_tree
|
|
7525
|
+
start_head=$(git rev-parse -q --verify HEAD 2>/dev/null)
|
|
7526
|
+
orig_tree=$(git write-tree 2>/dev/null)
|
|
7439
7527
|
local snapshot_file
|
|
7440
7528
|
snapshot_file=$(mktemp "${TMPDIR:-/tmp}/gitb-split-snapshot.XXXXXX")
|
|
7441
7529
|
chmod 600 "$snapshot_file" 2>/dev/null || true
|
|
@@ -7458,6 +7546,10 @@ function perform_commit_split {
|
|
|
7458
7546
|
fi
|
|
7459
7547
|
local scope files_str msg ai_msg choice scope_for_msg prefix manual_input
|
|
7460
7548
|
local -a files_array
|
|
7549
|
+
if [ -z "$auto_accept" ] && [ -n "$llm" ] && [ "$ai_ok" = "true" ]; then
|
|
7550
|
+
echo
|
|
7551
|
+
echo -e "${GRAY}Tip: press ${ENDCOLOR}${BOLD}u${NORMAL}${GRAY} at a split prompt to undo the split and make a single commit instead.${ENDCOLOR}"
|
|
7552
|
+
fi
|
|
7461
7553
|
for scope in "${split_group_keys[@]}"; do
|
|
7462
7554
|
idx=$((idx + 1))
|
|
7463
7555
|
echo
|
|
@@ -7506,6 +7598,13 @@ function perform_commit_split {
|
|
|
7506
7598
|
run_split_ai_for_scope "$scope" "$scope_for_msg" "$files_str"
|
|
7507
7599
|
case $? in
|
|
7508
7600
|
2) continue ;;
|
|
7601
|
+
4)
|
|
7602
|
+
_undo_commit_split "$start_head" "$orig_tree" "$snapshot_file" "$commit_count"
|
|
7603
|
+
trap - INT TERM
|
|
7604
|
+
echo
|
|
7605
|
+
echo -e "${YELLOW}Split undone, continuing with a single commit.${ENDCOLOR}"
|
|
7606
|
+
return 3
|
|
7607
|
+
;;
|
|
7509
7608
|
3)
|
|
7510
7609
|
_restore_split_snapshot "$snapshot_file"
|
|
7511
7610
|
trap - INT TERM
|
|
@@ -7526,11 +7625,11 @@ function perform_commit_split {
|
|
|
7526
7625
|
local commit_type=""
|
|
7527
7626
|
local is_empty_msg=""
|
|
7528
7627
|
echo
|
|
7529
|
-
print_split_type_menu "$scope" "$ai_ok"
|
|
7628
|
+
print_split_type_menu "$scope" "$ai_ok" "$commit_count"
|
|
7530
7629
|
local tchoice
|
|
7531
7630
|
while true; do
|
|
7532
7631
|
read_key tchoice || tchoice="0"
|
|
7533
|
-
if ! sanitize_choice_input "$tchoice" "^[0-
|
|
7632
|
+
if ! sanitize_choice_input "$tchoice" "^[0-9sgu]$"; then
|
|
7534
7633
|
continue
|
|
7535
7634
|
fi
|
|
7536
7635
|
tchoice="$sanitized_choice"
|
|
@@ -7552,6 +7651,13 @@ function perform_commit_split {
|
|
|
7552
7651
|
case $? in
|
|
7553
7652
|
0) break ;;
|
|
7554
7653
|
2) continue 2 ;;
|
|
7654
|
+
4)
|
|
7655
|
+
_undo_commit_split "$start_head" "$orig_tree" "$snapshot_file" "$commit_count"
|
|
7656
|
+
trap - INT TERM
|
|
7657
|
+
echo
|
|
7658
|
+
echo -e "${YELLOW}Split undone, continuing with a single commit.${ENDCOLOR}"
|
|
7659
|
+
return 3
|
|
7660
|
+
;;
|
|
7555
7661
|
3)
|
|
7556
7662
|
_restore_split_snapshot "$snapshot_file"
|
|
7557
7663
|
trap - INT TERM
|
|
@@ -7561,10 +7667,17 @@ function perform_commit_split {
|
|
|
7561
7667
|
;;
|
|
7562
7668
|
*)
|
|
7563
7669
|
echo
|
|
7564
|
-
print_split_type_menu "$scope" "$ai_ok"
|
|
7670
|
+
print_split_type_menu "$scope" "$ai_ok" "$commit_count"
|
|
7565
7671
|
;;
|
|
7566
7672
|
esac
|
|
7567
7673
|
;;
|
|
7674
|
+
u)
|
|
7675
|
+
_undo_commit_split "$start_head" "$orig_tree" "$snapshot_file" "$commit_count"
|
|
7676
|
+
trap - INT TERM
|
|
7677
|
+
echo
|
|
7678
|
+
echo -e "${YELLOW}Split undone, continuing with a single commit.${ENDCOLOR}"
|
|
7679
|
+
return 3
|
|
7680
|
+
;;
|
|
7568
7681
|
s)
|
|
7569
7682
|
echo -e "${YELLOW}Skipping scope '${scope}' (files left unstaged)${ENDCOLOR}"
|
|
7570
7683
|
while IFS= read -r f; do
|
|
@@ -7661,6 +7774,24 @@ function try_offer_commit_split {
|
|
|
7661
7774
|
if [ -n "$llm" ] && should_attempt_ai_grouping "${#split_group_keys[@]}" "$ai_grouping"; then
|
|
7662
7775
|
should_use_ai="true"
|
|
7663
7776
|
fi
|
|
7777
|
+
if [ ${#split_group_keys[@]} -lt 2 ] && [ "$should_use_ai" != "true" ]; then
|
|
7778
|
+
if [ -n "$force_split" ]; then
|
|
7779
|
+
echo -e "${YELLOW}Cannot split: all changes look like a single feature.${ENDCOLOR}"
|
|
7780
|
+
fi
|
|
7781
|
+
return 1
|
|
7782
|
+
fi
|
|
7783
|
+
local choice
|
|
7784
|
+
if [ -z "$force_split" ] && [ -z "$auto_yes" ] && [ "$auto_split" != "always" ]; then
|
|
7785
|
+
echo
|
|
7786
|
+
if [ ${#split_group_keys[@]} -ge 2 ]; then
|
|
7787
|
+
echo -e "${YELLOW}Staged changes span ${#split_group_keys[@]} scopes:${ENDCOLOR} ${BLUE}${split_group_keys[*]}${ENDCOLOR}"
|
|
7788
|
+
fi
|
|
7789
|
+
read_key choice "Try to split them into atomic commits? (y/N) " || choice=""
|
|
7790
|
+
echo
|
|
7791
|
+
if [ -z "$choice" ] || ! is_yes "$choice"; then
|
|
7792
|
+
return 1
|
|
7793
|
+
fi
|
|
7794
|
+
fi
|
|
7664
7795
|
if [ "$should_use_ai" = "true" ] && check_ai_available 2>/dev/null; then
|
|
7665
7796
|
echo
|
|
7666
7797
|
echo -e "${YELLOW}Grouping changes by feature with AI...${ENDCOLOR}"
|
|
@@ -7682,7 +7813,6 @@ function try_offer_commit_split {
|
|
|
7682
7813
|
echo
|
|
7683
7814
|
print_split_groups_preview
|
|
7684
7815
|
echo
|
|
7685
|
-
local choice
|
|
7686
7816
|
if [ -n "$force_split" ] || [ -n "$auto_yes" ] || [ "$auto_split" = "always" ]; then
|
|
7687
7817
|
choice="y"
|
|
7688
7818
|
else
|
|
@@ -7692,8 +7822,13 @@ function try_offer_commit_split {
|
|
|
7692
7822
|
if [ -z "$choice" ] || ! is_yes "$choice"; then
|
|
7693
7823
|
return 1
|
|
7694
7824
|
fi
|
|
7695
|
-
|
|
7696
|
-
|
|
7825
|
+
local split_rc=0
|
|
7826
|
+
perform_commit_split || split_rc=$?
|
|
7827
|
+
case "$split_rc" in
|
|
7828
|
+
0) return 0 ;;
|
|
7829
|
+
3) return 3 ;;
|
|
7830
|
+
*) return 2 ;;
|
|
7831
|
+
esac
|
|
7697
7832
|
}
|
|
7698
7833
|
function handle_ai_commit_generation {
|
|
7699
7834
|
local step="$1"
|
|
@@ -8122,7 +8257,7 @@ function commit_script {
|
|
|
8122
8257
|
print_help_row $FPAD "staged" "st" "Use already-staged files (skip the add step)"
|
|
8123
8258
|
print_help_row $FPAD "push" "p, pu" "Push after the commit succeeds"
|
|
8124
8259
|
print_help_row $FPAD "scope" "s" "Force a scope: 'type(scope): message' (useful with fast mode)"
|
|
8125
|
-
print_help_row $FPAD "no-split" "nos, nsp, nsl" "
|
|
8260
|
+
print_help_row $FPAD "no-split" "nos, nsp, nsl" "Don't offer to split this commit (fast modes split by default)"
|
|
8126
8261
|
print_help_row $FPAD "ai" "i, llm" "Generate the commit message with AI"
|
|
8127
8262
|
print_help_row $FPAD "msg" "m" "Open \$EDITOR for a multiline message body"
|
|
8128
8263
|
print_help_row $FPAD "ticket" "t, j, jira" "Append ticket info to the header"
|
|
@@ -8141,6 +8276,8 @@ function commit_script {
|
|
|
8141
8276
|
echo -e " ${BLUE}•${ENDCOLOR} Word order doesn't matter: ${GREEN}ai fast push${ENDCOLOR} == ${GREEN}push fast ai${ENDCOLOR} == ${GREEN}aifp${ENDCOLOR}"
|
|
8142
8277
|
echo -e " ${BLUE}•${ENDCOLOR} Modifiers stack on actions: ${GREEN}ai+fixup${ENDCOLOR}, ${GREEN}fast+amend${ENDCOLOR}, ${GREEN}split+push${ENDCOLOR}, ${GREEN}ai+staged${ENDCOLOR}, ..."
|
|
8143
8278
|
echo -e " ${BLUE}•${ENDCOLOR} ${BOLD}fast${NORMAL} and ${BOLD}staged${NORMAL} are mutually exclusive (one stages all, the other uses what's staged)"
|
|
8279
|
+
echo -e " ${BLUE}•${ENDCOLOR} Regular commits ask before splitting; fast modes split by default (toggle: ${GREEN}gitb cfg fast-split${ENDCOLOR})"
|
|
8280
|
+
echo -e " ${BLUE}•${ENDCOLOR} Press ${BOLD}u${NORMAL} at a split prompt to undo the split and commit everything as one"
|
|
8144
8281
|
echo -e " ${BLUE}•${ENDCOLOR} ${BOLD}revert${NORMAL} and ${BOLD}ff${NORMAL} only accept ${BOLD}push${NORMAL} (as ${BOLD}revp${NORMAL}/${BOLD}ffp${NORMAL}); to rewrite the last message use ${GREEN}gitb edit${ENDCOLOR}"
|
|
8145
8282
|
git config --unset gitbasher.cached-git-add 2>/dev/null || true
|
|
8146
8283
|
exit 0
|
|
@@ -8295,14 +8432,19 @@ function commit_script {
|
|
|
8295
8432
|
else
|
|
8296
8433
|
staged_files_list="$(sed 's/^/\t/' <<< "$(git -c core.quotePath=false diff --no-renames --name-only --cached)")"
|
|
8297
8434
|
fi
|
|
8298
|
-
|
|
8299
|
-
|
|
8300
|
-
|
|
8435
|
+
_split_skip="${no_split}"
|
|
8436
|
+
_split_auto_yes=""
|
|
8437
|
+
if [ -z "$split" ] && { [ -n "$fast" ] || [ -n "$auto_accept" ]; }; then
|
|
8438
|
+
if [ "$(get_fast_split)" = "false" ]; then
|
|
8439
|
+
[ -n "$auto_accept" ] && _split_skip="true"
|
|
8440
|
+
else
|
|
8301
8441
|
_split_auto_yes="true"
|
|
8302
8442
|
fi
|
|
8443
|
+
fi
|
|
8444
|
+
if [ -z "${amend}" ] && [ -z "${fixup}" ] && [ -z "${msg}" ] && [ -z "${ticket}" ] && [ -z "${_split_skip}" ]; then
|
|
8303
8445
|
try_offer_commit_split "$split" "$_split_auto_yes"
|
|
8304
8446
|
_split_rc=$?
|
|
8305
|
-
if [ -n "$split" ]; then
|
|
8447
|
+
if [ -n "$split" ] && [ "$_split_rc" -ne 3 ]; then
|
|
8306
8448
|
if [ "$_split_rc" -ge 2 ]; then
|
|
8307
8449
|
exit 1
|
|
8308
8450
|
fi
|
|
@@ -9174,7 +9316,7 @@ function branch_script {
|
|
|
9174
9316
|
"$main_branch"|"$current_branch"|master|main|develop) continue ;;
|
|
9175
9317
|
esac
|
|
9176
9318
|
merged_to_delete+=("$_mb")
|
|
9177
|
-
done < <(git branch --merged --format='%(refname:short)')
|
|
9319
|
+
done < <(git branch --merged HEAD --format='%(refname:short)')
|
|
9178
9320
|
for branch_to_delete in "${merged_to_delete[@]}"; do
|
|
9179
9321
|
delete_output=$(git branch -d "$branch_to_delete" 2>&1)
|
|
9180
9322
|
delete_code=$?
|
|
@@ -15479,7 +15621,7 @@ _gitb_sub_sync="push p merge m mergep mp pm dry d dr help h"
|
|
|
15479
15621
|
_gitb_sub_wip="up u down d help h"
|
|
15480
15622
|
_gitb_sub_branch="list l remote r re main def m new n c newd nd cd delete del d prev p - recent rc gone g tag t help h"
|
|
15481
15623
|
_gitb_sub_tag="annotated a an commit c co cm all al push ps ph p push-all pa delete del d delete-all da list log l remote re r fetch help h"
|
|
15482
|
-
_gitb_sub_config="default def d b main separator sep editor ed e ticket jira ti t scopes scope sc s ai llm key provider prov model m proxy prx p history hist diff payload push-size pushsize ps delete unset del user name email u auto completion comp help h"
|
|
15624
|
+
_gitb_sub_config="default def d b main separator sep editor ed e ticket jira ti t scopes scope sc s ai llm key provider prov model m proxy prx p history hist diff payload push-size pushsize ps fast-split fastsplit fs delete unset del user name email u auto completion comp help h"
|
|
15483
15625
|
_gitb_sub_undo="commit c amend a merge m rebase r stash s help h"
|
|
15484
15626
|
_gitb_sub_reset="soft s undo u interactive i ref r help h"
|
|
15485
15627
|
_gitb_sub_stash="select sel all list l pop p show s drop d apply a help h"
|
|
@@ -15828,7 +15970,7 @@ _gitb() {
|
|
|
15828
15970
|
_values 'tag mode' 'annotated[create annotated tag]' 'commit[tag a commit]' 'all[tag everything]' 'push[push tag]' 'push-all[push all tags]' 'delete[delete tag]' 'delete-all[delete all]' 'list[list tags]' 'remote[remote tags]' 'help[show help]'
|
|
15829
15971
|
;;
|
|
15830
15972
|
config|cf|cfg|conf)
|
|
15831
|
-
_values 'config key' 'default[default branch]' 'separator[separator char]' 'editor[editor]' 'ticket[ticket prefix]' 'scopes[scope list]' 'ai[AI setup wizard]' 'key[AI API key]' 'provider[AI provider]' 'model[AI model]' 'proxy[AI proxy]' 'history[AI history]' 'diff[AI diff payload]' 'push-size[warn on large pushes]' 'delete[unset a key]' 'user[user name/email]' 'auto[manage tab completion]' 'help[show help]'
|
|
15973
|
+
_values 'config key' 'default[default branch]' 'separator[separator char]' 'editor[editor]' 'ticket[ticket prefix]' 'scopes[scope list]' 'ai[AI setup wizard]' 'key[AI API key]' 'provider[AI provider]' 'model[AI model]' 'proxy[AI proxy]' 'history[AI history]' 'diff[AI diff payload]' 'push-size[warn on large pushes]' 'fast-split[split in fast commit modes]' 'delete[unset a key]' 'user[user name/email]' 'auto[manage tab completion]' 'help[show help]'
|
|
15832
15974
|
;;
|
|
15833
15975
|
undo|un)
|
|
15834
15976
|
_values 'undo target' 'commit[undo last commit]' 'amend[undo amend]' 'merge[undo merge]' 'rebase[undo rebase]' 'stash[undo stash]' 'help[show help]'
|
|
@@ -16030,7 +16172,7 @@ complete -c gitb -n "$__gitb_branch" -a "list remote main new newd delete prev r
|
|
|
16030
16172
|
set -l __gitb_tag "__gitb_using_cmd tag t tg; and __gitb_at_position 2"
|
|
16031
16173
|
complete -c gitb -n "$__gitb_tag" -a "annotated commit all push push-all delete delete-all list remote help"
|
|
16032
16174
|
set -l __gitb_config "__gitb_using_cmd config cf cfg conf; and __gitb_at_position 2"
|
|
16033
|
-
complete -c gitb -n "$__gitb_config" -a "default separator editor ticket scopes ai key provider model proxy history diff push-size delete user auto help"
|
|
16175
|
+
complete -c gitb -n "$__gitb_config" -a "default separator editor ticket scopes ai key provider model proxy history diff push-size fast-split delete user auto help"
|
|
16034
16176
|
set -l __gitb_undo "__gitb_using_cmd undo un; and __gitb_at_position 2"
|
|
16035
16177
|
complete -c gitb -n "$__gitb_undo" -a "commit amend merge rebase stash help"
|
|
16036
16178
|
set -l __gitb_reset "__gitb_using_cmd reset res; and __gitb_at_position 2"
|