gitbasher 5.2.1 → 5.3.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/CHANGELOG.md +12 -0
- package/README.md +6 -2
- package/dist/gitb +159 -18
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
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.0](https://github.com/maxbolgarin/gitbasher/compare/v5.2.1...v5.3.0) (2026-09-30)
|
|
6
|
+
|
|
7
|
+
### 🚀 Features
|
|
8
|
+
|
|
9
|
+
* **config:** add `gitb cfg fast-split` to toggle split in fast modes ([c56e173](https://github.com/maxbolgarin/gitbasher/commit/c56e1735efeaea8c71f83e5d983cd24ff26fcd2b))
|
|
10
|
+
* **commit:** ask before splitting, add undo split and fast-split setting ([1de1fcd](https://github.com/maxbolgarin/gitbasher/commit/1de1fcd523b5080da0c8248347558a421c8d72bb))
|
|
11
|
+
* **commit:** show undo-split hint in the split type menu ([520e66a](https://github.com/maxbolgarin/gitbasher/commit/520e66aec25b43b7fb83b27f863cc6af4a0ab0e2))
|
|
12
|
+
|
|
13
|
+
### 🐛 Bug Fixes
|
|
14
|
+
|
|
15
|
+
* **branch:** pass HEAD to --merged when deleting merged branches ([2cdaf58](https://github.com/maxbolgarin/gitbasher/commit/2cdaf58c3a92e9f26eba47bd180b582cb9676d04))
|
|
16
|
+
|
|
5
17
|
## [5.2.1](https://github.com/maxbolgarin/gitbasher/compare/v5.2.0...v5.2.1) (2026-07-11)
|
|
6
18
|
|
|
7
19
|
### 🐛 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.0"
|
|
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
|
|
@@ -3691,6 +3704,40 @@ function configure_push_warn_size {
|
|
|
3691
3704
|
yes_no_choice "\nSet push size warning globally" "true"
|
|
3692
3705
|
git config --global gitbasher.push-warn-size "$limit_input"
|
|
3693
3706
|
}
|
|
3707
|
+
function configure_fast_split {
|
|
3708
|
+
echo -e "${YELLOW}Configure Fast Mode Split${ENDCOLOR}"
|
|
3709
|
+
echo
|
|
3710
|
+
if [ "$(get_fast_split)" = "true" ]; then
|
|
3711
|
+
echo -e "Current: ${GREEN}auto${ENDCOLOR} (fast modes split without asking)"
|
|
3712
|
+
else
|
|
3713
|
+
echo -e "Current: ${YELLOW}off${ENDCOLOR} (fast asks first, ff commits everything as one)"
|
|
3714
|
+
fi
|
|
3715
|
+
echo
|
|
3716
|
+
echo -e "When staged changes span several scopes, fast commit modes (${BLUE}fast${ENDCOLOR}, ${BLUE}ff${ENDCOLOR}, ...)"
|
|
3717
|
+
echo -e "split them into atomic commits without asking. Turn it off to have ${BLUE}fast${ENDCOLOR}"
|
|
3718
|
+
echo -e "ask first (like a regular commit) and ${BLUE}ff${ENDCOLOR} make a single commit."
|
|
3719
|
+
echo
|
|
3720
|
+
echo -e "1. ${GREEN}auto${ENDCOLOR}:\tsplit automatically in fast modes"
|
|
3721
|
+
echo -e "2. ${YELLOW}off${ENDCOLOR}:\tdon't split by default in fast modes"
|
|
3722
|
+
echo -e "0. Exit without changes"
|
|
3723
|
+
local choice value label
|
|
3724
|
+
while true; do
|
|
3725
|
+
read_key choice || exit
|
|
3726
|
+
case "$choice" in
|
|
3727
|
+
1) value="true"; label="auto"; break ;;
|
|
3728
|
+
2) value="false"; label="off"; break ;;
|
|
3729
|
+
0) exit ;;
|
|
3730
|
+
esac
|
|
3731
|
+
done
|
|
3732
|
+
echo
|
|
3733
|
+
set_fast_split "$value" >/dev/null
|
|
3734
|
+
echo -e "${GREEN}✓ Set fast mode split to ${label} for '${project_name}'${ENDCOLOR}"
|
|
3735
|
+
echo
|
|
3736
|
+
[ "$GITBASHER_NO_REPO" = "true" ] && exit
|
|
3737
|
+
echo -e "Do you want to set it ${YELLOW}globally${ENDCOLOR} for all projects (Y/n)?"
|
|
3738
|
+
yes_no_choice "\nSet fast mode split globally" "true"
|
|
3739
|
+
set_config_value gitbasher.commit-fast-split "$value" "true" >/dev/null
|
|
3740
|
+
}
|
|
3694
3741
|
function configure_ai_diff {
|
|
3695
3742
|
echo -e "${YELLOW}Configure AI Diff Payload Size${ENDCOLOR}"
|
|
3696
3743
|
echo
|
|
@@ -3852,6 +3899,8 @@ function delete_global {
|
|
|
3852
3899
|
_delete_global_add "gitbasher.ai-commit-history-limit" "AI commit history limit" "$global_ai_history" "$GREEN"
|
|
3853
3900
|
local global_push_warn=$(git config --global --get gitbasher.push-warn-size)
|
|
3854
3901
|
_delete_global_add "gitbasher.push-warn-size" "Push size warning" "${global_push_warn:+${global_push_warn} MB}" "$GREEN"
|
|
3902
|
+
local global_fast_split=$(git config --global --get gitbasher.commit-fast-split)
|
|
3903
|
+
_delete_global_add "gitbasher.commit-fast-split" "Fast mode split" "$global_fast_split" "$GREEN"
|
|
3855
3904
|
local global_ai_diff_lines=$(git config --global --get gitbasher.ai-diff-limit)
|
|
3856
3905
|
local global_ai_diff_chars=$(git config --global --get gitbasher.ai-diff-max-chars)
|
|
3857
3906
|
if [ -n "$global_ai_diff_lines" ] || [ -n "$global_ai_diff_chars" ]; then
|
|
@@ -3949,6 +3998,7 @@ function config_script {
|
|
|
3949
3998
|
history|hist) set_ai_history_cfg="true";;
|
|
3950
3999
|
diff|payload) set_ai_diff_cfg="true";;
|
|
3951
4000
|
push-size|pushsize|ps) set_push_warn_cfg="true";;
|
|
4001
|
+
fast-split|fastsplit|fs) set_fast_split_cfg="true";;
|
|
3952
4002
|
delete|unset|del) delete_cfg="true";;
|
|
3953
4003
|
user|name|email|u) set_user_cfg="true";;
|
|
3954
4004
|
auto|completion|comp) auto_cfg="true";;
|
|
@@ -3982,6 +4032,8 @@ function config_script {
|
|
|
3982
4032
|
header="$header AI DIFF PAYLOAD"
|
|
3983
4033
|
elif [ -n "${set_push_warn_cfg}" ]; then
|
|
3984
4034
|
header="$header PUSH SIZE WARNING"
|
|
4035
|
+
elif [ -n "${set_fast_split_cfg}" ]; then
|
|
4036
|
+
header="$header FAST MODE SPLIT"
|
|
3985
4037
|
elif [ -n "${delete_cfg}" ]; then
|
|
3986
4038
|
header="$header UNSET GLOBAL CONFIG"
|
|
3987
4039
|
elif [ -n "${set_user_cfg}" ]; then
|
|
@@ -4055,6 +4107,10 @@ function config_script {
|
|
|
4055
4107
|
configure_push_warn_size
|
|
4056
4108
|
exit
|
|
4057
4109
|
fi
|
|
4110
|
+
if [ "$set_fast_split_cfg" == "true" ]; then
|
|
4111
|
+
configure_fast_split
|
|
4112
|
+
exit
|
|
4113
|
+
fi
|
|
4058
4114
|
if [ "$delete_cfg" == "true" ]; then
|
|
4059
4115
|
delete_global
|
|
4060
4116
|
exit
|
|
@@ -4083,6 +4139,7 @@ function config_script {
|
|
|
4083
4139
|
print_help_row $PAD "history" "hist" "Set how many recent commits to include in AI prompts"
|
|
4084
4140
|
print_help_row $PAD "diff" "payload" "Set the diff payload size (lines and char cap) sent to AI"
|
|
4085
4141
|
print_help_row $PAD "push-size" "ps, pushsize" "Warn before pushing more than N MB (0 disables)"
|
|
4142
|
+
print_help_row $PAD "fast-split" "fs, fastsplit" "Split automatically in fast commit modes (on/off)"
|
|
4086
4143
|
print_help_row $PAD "auto" "completion, comp" "Install/remove tab completion for bash, zsh, or fish"
|
|
4087
4144
|
print_help_row $PAD "delete" "unset, del" "Unset a global gitbasher configuration value"
|
|
4088
4145
|
print_help_row $PAD "help" "h" "Show this help"
|
|
@@ -7295,11 +7352,35 @@ function _restore_split_snapshot {
|
|
|
7295
7352
|
done < "$snapshot"
|
|
7296
7353
|
rm -f "$snapshot"
|
|
7297
7354
|
}
|
|
7355
|
+
function _undo_commit_split {
|
|
7356
|
+
local start_head="$1"
|
|
7357
|
+
local orig_tree="$2"
|
|
7358
|
+
local snapshot="$3"
|
|
7359
|
+
local made="$4"
|
|
7360
|
+
if [ "${made:-0}" -gt 0 ]; then
|
|
7361
|
+
if [ -n "$start_head" ]; then
|
|
7362
|
+
git reset -q --soft "$start_head" >/dev/null 2>&1
|
|
7363
|
+
else
|
|
7364
|
+
git update-ref -d HEAD >/dev/null 2>&1
|
|
7365
|
+
fi
|
|
7366
|
+
fi
|
|
7367
|
+
if [ -n "$orig_tree" ] && git read-tree "$orig_tree" >/dev/null 2>&1; then
|
|
7368
|
+
rm -f "$snapshot"
|
|
7369
|
+
else
|
|
7370
|
+
_restore_split_snapshot "$snapshot"
|
|
7371
|
+
fi
|
|
7372
|
+
}
|
|
7298
7373
|
function print_split_type_menu {
|
|
7299
7374
|
local scope="$1"
|
|
7300
7375
|
local ai_available="$2"
|
|
7376
|
+
local made="${3:-0}"
|
|
7301
7377
|
echo -e "${YELLOW}What type of changes for ${BLUE}${BOLD}${scope}${ENDCOLOR}${YELLOW}?${ENDCOLOR}"
|
|
7302
7378
|
echo -e "Final message will be ${YELLOW}<type>${ENDCOLOR}(${BLUE}<scope>${ENDCOLOR}): ${BLUE}<summary>${ENDCOLOR}"
|
|
7379
|
+
if [ "$made" -gt 0 ]; then
|
|
7380
|
+
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}"
|
|
7381
|
+
else
|
|
7382
|
+
echo -e "${GRAY}Changes were split into groups — press ${ENDCOLOR}${BOLD}u${NORMAL}${GRAY} to undo the split and commit everything at once.${ENDCOLOR}"
|
|
7383
|
+
fi
|
|
7303
7384
|
echo -e "1. ${BOLD}feat${ENDCOLOR}:\tnew feature, logic change or performance improvement"
|
|
7304
7385
|
echo -e "2. ${BOLD}fix${ENDCOLOR}:\t\tsmall changes, eg. bug fix"
|
|
7305
7386
|
echo -e "3. ${BOLD}refactor${ENDCOLOR}:\tcode change that neither fixes a bug nor adds a feature, style changes"
|
|
@@ -7313,6 +7394,7 @@ function print_split_type_menu {
|
|
|
7313
7394
|
echo -e "g. ${GREEN}${BOLD}ai${ENDCOLOR}:\t\tgenerate commit message using AI"
|
|
7314
7395
|
fi
|
|
7315
7396
|
echo -e "s. ${YELLOW}${BOLD}skip${ENDCOLOR}:\tSkip this group and leave its files unstaged"
|
|
7397
|
+
echo -e "u. ${CYAN}${BOLD}undo${ENDCOLOR}:\tUndo split and commit all changes as a single commit"
|
|
7316
7398
|
echo -e "0. ${RED}${BOLD}abort${ENDCOLOR}:\tAbort split and restore original staging"
|
|
7317
7399
|
echo
|
|
7318
7400
|
}
|
|
@@ -7386,7 +7468,7 @@ function run_split_ai_for_scope {
|
|
|
7386
7468
|
echo
|
|
7387
7469
|
echo -e "${GREEN}AI suggestion:${ENDCOLOR} ${BOLD}$ai_msg${ENDCOLOR}"
|
|
7388
7470
|
echo
|
|
7389
|
-
read_key choice "Use it? (y/e to edit/r to regenerate/s to skip group/0 to abort) " || choice="0"
|
|
7471
|
+
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
7472
|
echo
|
|
7391
7473
|
normalize_key "$choice"
|
|
7392
7474
|
while [ "$normalized_key" = "r" ]; do
|
|
@@ -7406,7 +7488,7 @@ ${ai_msg}"
|
|
|
7406
7488
|
echo
|
|
7407
7489
|
echo -e "${GREEN}AI suggestion:${ENDCOLOR} ${BOLD}$ai_msg${ENDCOLOR}"
|
|
7408
7490
|
echo
|
|
7409
|
-
read_key choice "Use it? (y/e to edit/r to regenerate/s to skip group/0 to abort) " || choice="0"
|
|
7491
|
+
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
7492
|
echo
|
|
7411
7493
|
normalize_key "$choice"
|
|
7412
7494
|
done
|
|
@@ -7423,6 +7505,8 @@ ${ai_msg}"
|
|
|
7423
7505
|
[ -n "$f" ] && git restore --staged -- ":(top,literal)$f" >/dev/null 2>&1
|
|
7424
7506
|
done <<< "$_files_str"
|
|
7425
7507
|
return 2
|
|
7508
|
+
elif [ "$normalized_key" = "u" ]; then
|
|
7509
|
+
return 4
|
|
7426
7510
|
elif [ "$choice" = "0" ]; then
|
|
7427
7511
|
return 3
|
|
7428
7512
|
fi
|
|
@@ -7436,6 +7520,9 @@ function perform_commit_split {
|
|
|
7436
7520
|
return 1
|
|
7437
7521
|
fi
|
|
7438
7522
|
_capture_split_statuses
|
|
7523
|
+
local start_head orig_tree
|
|
7524
|
+
start_head=$(git rev-parse -q --verify HEAD 2>/dev/null)
|
|
7525
|
+
orig_tree=$(git write-tree 2>/dev/null)
|
|
7439
7526
|
local snapshot_file
|
|
7440
7527
|
snapshot_file=$(mktemp "${TMPDIR:-/tmp}/gitb-split-snapshot.XXXXXX")
|
|
7441
7528
|
chmod 600 "$snapshot_file" 2>/dev/null || true
|
|
@@ -7458,6 +7545,10 @@ function perform_commit_split {
|
|
|
7458
7545
|
fi
|
|
7459
7546
|
local scope files_str msg ai_msg choice scope_for_msg prefix manual_input
|
|
7460
7547
|
local -a files_array
|
|
7548
|
+
if [ -z "$auto_accept" ] && [ -n "$llm" ] && [ "$ai_ok" = "true" ]; then
|
|
7549
|
+
echo
|
|
7550
|
+
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}"
|
|
7551
|
+
fi
|
|
7461
7552
|
for scope in "${split_group_keys[@]}"; do
|
|
7462
7553
|
idx=$((idx + 1))
|
|
7463
7554
|
echo
|
|
@@ -7506,6 +7597,13 @@ function perform_commit_split {
|
|
|
7506
7597
|
run_split_ai_for_scope "$scope" "$scope_for_msg" "$files_str"
|
|
7507
7598
|
case $? in
|
|
7508
7599
|
2) continue ;;
|
|
7600
|
+
4)
|
|
7601
|
+
_undo_commit_split "$start_head" "$orig_tree" "$snapshot_file" "$commit_count"
|
|
7602
|
+
trap - INT TERM
|
|
7603
|
+
echo
|
|
7604
|
+
echo -e "${YELLOW}Split undone, continuing with a single commit.${ENDCOLOR}"
|
|
7605
|
+
return 3
|
|
7606
|
+
;;
|
|
7509
7607
|
3)
|
|
7510
7608
|
_restore_split_snapshot "$snapshot_file"
|
|
7511
7609
|
trap - INT TERM
|
|
@@ -7526,11 +7624,11 @@ function perform_commit_split {
|
|
|
7526
7624
|
local commit_type=""
|
|
7527
7625
|
local is_empty_msg=""
|
|
7528
7626
|
echo
|
|
7529
|
-
print_split_type_menu "$scope" "$ai_ok"
|
|
7627
|
+
print_split_type_menu "$scope" "$ai_ok" "$commit_count"
|
|
7530
7628
|
local tchoice
|
|
7531
7629
|
while true; do
|
|
7532
7630
|
read_key tchoice || tchoice="0"
|
|
7533
|
-
if ! sanitize_choice_input "$tchoice" "^[0-
|
|
7631
|
+
if ! sanitize_choice_input "$tchoice" "^[0-9sgu]$"; then
|
|
7534
7632
|
continue
|
|
7535
7633
|
fi
|
|
7536
7634
|
tchoice="$sanitized_choice"
|
|
@@ -7552,6 +7650,13 @@ function perform_commit_split {
|
|
|
7552
7650
|
case $? in
|
|
7553
7651
|
0) break ;;
|
|
7554
7652
|
2) continue 2 ;;
|
|
7653
|
+
4)
|
|
7654
|
+
_undo_commit_split "$start_head" "$orig_tree" "$snapshot_file" "$commit_count"
|
|
7655
|
+
trap - INT TERM
|
|
7656
|
+
echo
|
|
7657
|
+
echo -e "${YELLOW}Split undone, continuing with a single commit.${ENDCOLOR}"
|
|
7658
|
+
return 3
|
|
7659
|
+
;;
|
|
7555
7660
|
3)
|
|
7556
7661
|
_restore_split_snapshot "$snapshot_file"
|
|
7557
7662
|
trap - INT TERM
|
|
@@ -7561,10 +7666,17 @@ function perform_commit_split {
|
|
|
7561
7666
|
;;
|
|
7562
7667
|
*)
|
|
7563
7668
|
echo
|
|
7564
|
-
print_split_type_menu "$scope" "$ai_ok"
|
|
7669
|
+
print_split_type_menu "$scope" "$ai_ok" "$commit_count"
|
|
7565
7670
|
;;
|
|
7566
7671
|
esac
|
|
7567
7672
|
;;
|
|
7673
|
+
u)
|
|
7674
|
+
_undo_commit_split "$start_head" "$orig_tree" "$snapshot_file" "$commit_count"
|
|
7675
|
+
trap - INT TERM
|
|
7676
|
+
echo
|
|
7677
|
+
echo -e "${YELLOW}Split undone, continuing with a single commit.${ENDCOLOR}"
|
|
7678
|
+
return 3
|
|
7679
|
+
;;
|
|
7568
7680
|
s)
|
|
7569
7681
|
echo -e "${YELLOW}Skipping scope '${scope}' (files left unstaged)${ENDCOLOR}"
|
|
7570
7682
|
while IFS= read -r f; do
|
|
@@ -7661,6 +7773,24 @@ function try_offer_commit_split {
|
|
|
7661
7773
|
if [ -n "$llm" ] && should_attempt_ai_grouping "${#split_group_keys[@]}" "$ai_grouping"; then
|
|
7662
7774
|
should_use_ai="true"
|
|
7663
7775
|
fi
|
|
7776
|
+
if [ ${#split_group_keys[@]} -lt 2 ] && [ "$should_use_ai" != "true" ]; then
|
|
7777
|
+
if [ -n "$force_split" ]; then
|
|
7778
|
+
echo -e "${YELLOW}Cannot split: all changes look like a single feature.${ENDCOLOR}"
|
|
7779
|
+
fi
|
|
7780
|
+
return 1
|
|
7781
|
+
fi
|
|
7782
|
+
local choice
|
|
7783
|
+
if [ -z "$force_split" ] && [ -z "$auto_yes" ] && [ "$auto_split" != "always" ]; then
|
|
7784
|
+
echo
|
|
7785
|
+
if [ ${#split_group_keys[@]} -ge 2 ]; then
|
|
7786
|
+
echo -e "${YELLOW}Staged changes span ${#split_group_keys[@]} scopes:${ENDCOLOR} ${BLUE}${split_group_keys[*]}${ENDCOLOR}"
|
|
7787
|
+
fi
|
|
7788
|
+
read_key choice "Try to split them into atomic commits? (y/N) " || choice=""
|
|
7789
|
+
echo
|
|
7790
|
+
if [ -z "$choice" ] || ! is_yes "$choice"; then
|
|
7791
|
+
return 1
|
|
7792
|
+
fi
|
|
7793
|
+
fi
|
|
7664
7794
|
if [ "$should_use_ai" = "true" ] && check_ai_available 2>/dev/null; then
|
|
7665
7795
|
echo
|
|
7666
7796
|
echo -e "${YELLOW}Grouping changes by feature with AI...${ENDCOLOR}"
|
|
@@ -7682,7 +7812,6 @@ function try_offer_commit_split {
|
|
|
7682
7812
|
echo
|
|
7683
7813
|
print_split_groups_preview
|
|
7684
7814
|
echo
|
|
7685
|
-
local choice
|
|
7686
7815
|
if [ -n "$force_split" ] || [ -n "$auto_yes" ] || [ "$auto_split" = "always" ]; then
|
|
7687
7816
|
choice="y"
|
|
7688
7817
|
else
|
|
@@ -7692,8 +7821,13 @@ function try_offer_commit_split {
|
|
|
7692
7821
|
if [ -z "$choice" ] || ! is_yes "$choice"; then
|
|
7693
7822
|
return 1
|
|
7694
7823
|
fi
|
|
7695
|
-
|
|
7696
|
-
|
|
7824
|
+
local split_rc=0
|
|
7825
|
+
perform_commit_split || split_rc=$?
|
|
7826
|
+
case "$split_rc" in
|
|
7827
|
+
0) return 0 ;;
|
|
7828
|
+
3) return 3 ;;
|
|
7829
|
+
*) return 2 ;;
|
|
7830
|
+
esac
|
|
7697
7831
|
}
|
|
7698
7832
|
function handle_ai_commit_generation {
|
|
7699
7833
|
local step="$1"
|
|
@@ -8122,7 +8256,7 @@ function commit_script {
|
|
|
8122
8256
|
print_help_row $FPAD "staged" "st" "Use already-staged files (skip the add step)"
|
|
8123
8257
|
print_help_row $FPAD "push" "p, pu" "Push after the commit succeeds"
|
|
8124
8258
|
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" "
|
|
8259
|
+
print_help_row $FPAD "no-split" "nos, nsp, nsl" "Don't offer to split this commit (fast modes split by default)"
|
|
8126
8260
|
print_help_row $FPAD "ai" "i, llm" "Generate the commit message with AI"
|
|
8127
8261
|
print_help_row $FPAD "msg" "m" "Open \$EDITOR for a multiline message body"
|
|
8128
8262
|
print_help_row $FPAD "ticket" "t, j, jira" "Append ticket info to the header"
|
|
@@ -8141,6 +8275,8 @@ function commit_script {
|
|
|
8141
8275
|
echo -e " ${BLUE}•${ENDCOLOR} Word order doesn't matter: ${GREEN}ai fast push${ENDCOLOR} == ${GREEN}push fast ai${ENDCOLOR} == ${GREEN}aifp${ENDCOLOR}"
|
|
8142
8276
|
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
8277
|
echo -e " ${BLUE}•${ENDCOLOR} ${BOLD}fast${NORMAL} and ${BOLD}staged${NORMAL} are mutually exclusive (one stages all, the other uses what's staged)"
|
|
8278
|
+
echo -e " ${BLUE}•${ENDCOLOR} Regular commits ask before splitting; fast modes split by default (toggle: ${GREEN}gitb cfg fast-split${ENDCOLOR})"
|
|
8279
|
+
echo -e " ${BLUE}•${ENDCOLOR} Press ${BOLD}u${NORMAL} at a split prompt to undo the split and commit everything as one"
|
|
8144
8280
|
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
8281
|
git config --unset gitbasher.cached-git-add 2>/dev/null || true
|
|
8146
8282
|
exit 0
|
|
@@ -8295,14 +8431,19 @@ function commit_script {
|
|
|
8295
8431
|
else
|
|
8296
8432
|
staged_files_list="$(sed 's/^/\t/' <<< "$(git -c core.quotePath=false diff --no-renames --name-only --cached)")"
|
|
8297
8433
|
fi
|
|
8298
|
-
|
|
8299
|
-
|
|
8300
|
-
|
|
8434
|
+
_split_skip="${no_split}"
|
|
8435
|
+
_split_auto_yes=""
|
|
8436
|
+
if [ -z "$split" ] && { [ -n "$fast" ] || [ -n "$auto_accept" ]; }; then
|
|
8437
|
+
if [ "$(get_fast_split)" = "false" ]; then
|
|
8438
|
+
[ -n "$auto_accept" ] && _split_skip="true"
|
|
8439
|
+
else
|
|
8301
8440
|
_split_auto_yes="true"
|
|
8302
8441
|
fi
|
|
8442
|
+
fi
|
|
8443
|
+
if [ -z "${amend}" ] && [ -z "${fixup}" ] && [ -z "${msg}" ] && [ -z "${ticket}" ] && [ -z "${_split_skip}" ]; then
|
|
8303
8444
|
try_offer_commit_split "$split" "$_split_auto_yes"
|
|
8304
8445
|
_split_rc=$?
|
|
8305
|
-
if [ -n "$split" ]; then
|
|
8446
|
+
if [ -n "$split" ] && [ "$_split_rc" -ne 3 ]; then
|
|
8306
8447
|
if [ "$_split_rc" -ge 2 ]; then
|
|
8307
8448
|
exit 1
|
|
8308
8449
|
fi
|
|
@@ -9174,7 +9315,7 @@ function branch_script {
|
|
|
9174
9315
|
"$main_branch"|"$current_branch"|master|main|develop) continue ;;
|
|
9175
9316
|
esac
|
|
9176
9317
|
merged_to_delete+=("$_mb")
|
|
9177
|
-
done < <(git branch --merged --format='%(refname:short)')
|
|
9318
|
+
done < <(git branch --merged HEAD --format='%(refname:short)')
|
|
9178
9319
|
for branch_to_delete in "${merged_to_delete[@]}"; do
|
|
9179
9320
|
delete_output=$(git branch -d "$branch_to_delete" 2>&1)
|
|
9180
9321
|
delete_code=$?
|
|
@@ -15479,7 +15620,7 @@ _gitb_sub_sync="push p merge m mergep mp pm dry d dr help h"
|
|
|
15479
15620
|
_gitb_sub_wip="up u down d help h"
|
|
15480
15621
|
_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
15622
|
_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"
|
|
15623
|
+
_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
15624
|
_gitb_sub_undo="commit c amend a merge m rebase r stash s help h"
|
|
15484
15625
|
_gitb_sub_reset="soft s undo u interactive i ref r help h"
|
|
15485
15626
|
_gitb_sub_stash="select sel all list l pop p show s drop d apply a help h"
|
|
@@ -15828,7 +15969,7 @@ _gitb() {
|
|
|
15828
15969
|
_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
15970
|
;;
|
|
15830
15971
|
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]'
|
|
15972
|
+
_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
15973
|
;;
|
|
15833
15974
|
undo|un)
|
|
15834
15975
|
_values 'undo target' 'commit[undo last commit]' 'amend[undo amend]' 'merge[undo merge]' 'rebase[undo rebase]' 'stash[undo stash]' 'help[show help]'
|
|
@@ -16030,7 +16171,7 @@ complete -c gitb -n "$__gitb_branch" -a "list remote main new newd delete prev r
|
|
|
16030
16171
|
set -l __gitb_tag "__gitb_using_cmd tag t tg; and __gitb_at_position 2"
|
|
16031
16172
|
complete -c gitb -n "$__gitb_tag" -a "annotated commit all push push-all delete delete-all list remote help"
|
|
16032
16173
|
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"
|
|
16174
|
+
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
16175
|
set -l __gitb_undo "__gitb_using_cmd undo un; and __gitb_at_position 2"
|
|
16035
16176
|
complete -c gitb -n "$__gitb_undo" -a "commit amend merge rebase stash help"
|
|
16036
16177
|
set -l __gitb_reset "__gitb_using_cmd reset res; and __gitb_at_position 2"
|