1- #! /usr/bin/env bash
1+ #! /bin/sh
2+ # shellcheck disable=SC2059
23# git-fixup (https://github.com/keis/git-fixup)
34# We cannot set -u, because included git libraries don't support it.
45set -e
@@ -29,10 +30,13 @@ SUBDIRECTORY_OK=yes
2930grok_diff=' /^--- .*/p ;
3031 s/^@@ -\([0-9]*\),\([0-9]*\).*/\1 \2/p'
3132
33+ # EOL in the POSIX compatible way
34+ NL=" $( printf ' \nx' ) " ; NL=" ${NL% x} "
35+
3236# Produce suggestion of commits by finding the sections of files with changes
3337# staged (U1 to diff is used to give some context for when adding items to
3438# lists etc) and looking up the previous commits touching those sections.
35- function fixup_candidates_lines () {
39+ fixup_candidates_lines () {
3640 git diff --cached -U1 --no-prefix | sed -n " $grok_diff " | (
3741 file=' '
3842 while read -r offs len ; do
@@ -51,7 +55,7 @@ function fixup_candidates_lines () {
5155
5256# Produce suggestion of commits by taking the latest commit to each file with
5357# staged changes
54- function fixup_candidates_files () {
58+ fixup_candidates_files () {
5559 git diff --cached --name-only | (
5660 while read -r file; do
5761 git rev-list -n 1 -E --invert-grep --grep=' ^(fixup|squash)' " $rev_range " -- " $file "
@@ -60,35 +64,36 @@ function fixup_candidates_files () {
6064}
6165
6266# Produce suggestion of all commits in $rev_range
63- function fixup_candidates_all_commits () {
67+ fixup_candidates_all_commits () {
6468 git rev-list " $rev_range " | sed ' s/^/F /g'
6569}
6670
6771# Pretty print details of a commit
68- function print_sha () {
69- local sha=$1
70- local type=$2
72+ print_sha () {
73+ sha=$1
74+ type=$2
7175
7276 git --no-pager log --format=" %H [$type ] %s <%ae>" -n 1 " $sha "
7377}
7478
7579# Call git commit
76- function call_commit() {
77- local flag=$op
78- local target=$1
80+ call_commit () {
81+ set -x
82+ flag=$op
83+ target=$1
7984
8085 if [ " $op " = " amend" ] ; then
8186 flag=fixup
8287 target=" amend:$target "
8388 fi
8489
8590 # shellcheck disable=SC2086
86- git commit " ${git_commit_args[@]} " " --$flag =$target " || die
91+ git commit ${git_commit_args} " --$flag =$target " || die
8792}
8893
8994# Call git rebase
90- function call_rebase() {
91- local target=$1
95+ call_rebase () {
96+ target=$1
9297
9398 # If our target-commit has a parent, we call a rebase with that
9499 # shellcheck disable=SC1083
@@ -102,42 +107,53 @@ function call_rebase() {
102107}
103108
104109# Print list of fixup/squash candidates
105- function print_candidates() {
110+ print_candidates () {
106111 (
107112 if [ " $show_all " = " false" ] ; then
108113 fixup_candidates_lines
109114 fixup_candidates_files
110115 else
111116 fixup_candidates_all_commits
112117 fi
113- ) | sort -uk2 | while read -r type sha; do
118+ ) | sort -uk2 | while read -r type sha ; do
114119 if [ -n " $sha " ] ; then
115120 print_sha " $sha " " $type "
116121 fi
117122 done
118123}
119124
120- function fallback_menu() {
125+ fallback_menu () {
121126 (
122- IFS=$' \n '
123- read -d ' ' -ra options
124- PS3=" Which commit should I $op ? "
125- select line in " ${options[@]} " ; do
126- if [ -z " $line " ] ; then
127- declare -a args=(" $REPLY " )
128- case ${args[0]} in
127+ IFS=" $NL "
128+ counter=0
129+ TMPINPUT=" $( mktemp --tmpdir gitfixup-menu-XXXX) "
130+ trap ' rm -f "$TMPINPUT"' EXIT
131+ cat > " $TMPINPUT "
132+
133+ while read -r line ; do
134+ counter=$(( counter + 1 ))
135+ printf " %d) %s\n" $counter " $line " >&2
136+ done < " $TMPINPUT "
137+ printf " Which commit should I fixup? " >&2
138+ while read -r REPLY ; do
139+ if ( printf " %s\n" " $REPLY " | grep -q " ^[0-9]\+$" ) && [ " $REPLY " -le " $counter " ] ; then
140+ printf " %s\n" " $( sed -n -e " ${REPLY} p" " $TMPINPUT " ) "
141+ break
142+ else
143+ args=" ${REPLY%% * } "
144+ case ${args} in
129145 quit|q)
130146 echo " Alright, no action taken." >&2
131147 break
132148 ;;
133149 show|s)
134- idx=$(( args[ 1 ] - 1 ))
150+ idx=" ${REPLY # " $ args" * } "
135151 if [ " $idx " -ge 0 ] ; then
136- git show " ${options[$ idx] %% * } " >&2
152+ git show " $( awk ' FNR == ' " ${ idx} " ' {print $1} ' " $TMPINPUT " ) " >&2
137153 fi
138154 ;;
139155 help|h)
140- local fmt=" %s\n %s\n"
156+ fmt=" %s\n %s\n"
141157 # shellcheck disable=SC2059
142158 printf " $fmt " " <n>" " $op the <n>-th commit from the list" >&2
143159 # shellcheck disable=SC2059
@@ -148,9 +164,6 @@ function fallback_menu() {
148164 printf " $fmt " " h[elp]" " show this help message" >&2
149165 ;;
150166 esac
151- else
152- echo " $line "
153- break
154167 fi
155168 done < /dev/tty
156169 )
@@ -164,7 +177,7 @@ show_menu () {
164177 fi
165178}
166179
167- git_commit_args=()
180+ git_commit_args=" "
168181target=
169182op=${GITFIXUPACTION:- $(git config --default=fixup fixup.action)}
170183rebase=${GITFIXUPREBASE:- $(git config --default=false fixup.rebase)}
@@ -197,7 +210,7 @@ while [ $# -gt 0 ] ; do
197210 rebase=false
198211 ;;
199212 -n|--no-verify)
200- git_commit_args+=( " $1 " )
213+ git_commit_args= " $git_commit_args $1 "
201214 ;;
202215 -b|--base)
203216 shift
0 commit comments