Skip to content

Commit 6368f3f

Browse files
dschogitster
authored andcommitted
rebase -i: call editor just once for a multi-squash
Sometimes you want to squash more than two commits. Before this patch, the editor was fired up for each squash command. Now the editor is started only with the last squash command. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent e1abc69 commit 6368f3f

File tree

2 files changed

+55
-10
lines changed

2 files changed

+55
-10
lines changed

git-rebase--interactive.sh

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ require_work_tree
1919
DOTEST="$GIT_DIR/.dotest-merge"
2020
TODO="$DOTEST"/todo
2121
DONE="$DOTEST"/done
22+
MSG="$DOTEST"/message
23+
SQUASH_MSG="$DOTEST"/message-squash
2224
REWRITTEN="$DOTEST"/rewritten
2325
PRESERVE_MERGES=
2426
STRATEGY=
@@ -158,6 +160,38 @@ pick_one_preserving_merges () {
158160
esac
159161
}
160162

163+
nth_string () {
164+
case "$1" in
165+
*1[0-9]|*[04-9]) echo "$1"th;;
166+
*1) echo "$1"st;;
167+
*2) echo "$1"nd;;
168+
*3) echo "$1"rd;;
169+
esac
170+
}
171+
172+
make_squash_message () {
173+
if [ -f "$SQUASH_MSG" ]; then
174+
COUNT=$(($(sed -n "s/^# This is [^0-9]*\([0-9]\+\).*/\1/p" \
175+
< "$SQUASH_MSG" | tail -n 1)+1))
176+
echo "# This is a combination of $COUNT commits."
177+
sed -n "2,\$p" < "$SQUASH_MSG"
178+
else
179+
COUNT=2
180+
echo "# This is a combination of two commits."
181+
echo "# The first commit's message is:"
182+
echo
183+
git cat-file commit HEAD | sed -e '1,/^$/d'
184+
echo
185+
fi
186+
echo "# This is the $(nth_string $COUNT) commit message:"
187+
echo
188+
git cat-file commit $1 | sed -e '1,/^$/d'
189+
}
190+
191+
peek_next_command () {
192+
sed -n "1s/ .*$//p" < "$TODO"
193+
}
194+
161195
do_next () {
162196
test -f "$DOTEST"/message && rm "$DOTEST"/message
163197
test -f "$DOTEST"/author-script && rm "$DOTEST"/author-script
@@ -194,17 +228,19 @@ do_next () {
194228
die "Cannot 'squash' without a previous commit"
195229

196230
mark_action_done
197-
MSG="$DOTEST"/message
198-
echo "# This is a combination of two commits." > "$MSG"
199-
echo "# The first commit's message is:" >> "$MSG"
200-
echo >> "$MSG"
201-
git cat-file commit HEAD | sed -e '1,/^$/d' >> "$MSG"
202-
echo >> "$MSG"
231+
make_squash_message $sha1 > "$MSG"
232+
case "$(peek_next_command)" in
233+
squash)
234+
EDIT_COMMIT=
235+
cp "$MSG" "$SQUASH_MSG"
236+
;;
237+
*)
238+
EDIT_COMMIT=-e
239+
test -f "$SQUASH_MSG" && rm "$SQUASH_MSG"
240+
esac
241+
203242
failed=f
204243
pick_one -n $sha1 || failed=t
205-
echo "# And this is the 2nd commit message:" >> "$MSG"
206-
echo >> "$MSG"
207-
git cat-file commit $sha1 | sed -e '1,/^$/d' >> "$MSG"
208244
git reset --soft HEAD^
209245
author_script=$(get_author_ident_from_commit $sha1)
210246
echo "$author_script" > "$DOTEST"/author-script
@@ -213,7 +249,7 @@ do_next () {
213249
# This is like --amend, but with a different message
214250
eval "$author_script"
215251
export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
216-
git commit -F "$MSG" -e
252+
git commit -F "$MSG" $EDIT_COMMIT
217253
;;
218254
t)
219255
cp "$MSG" "$GIT_DIR"/MERGE_MSG

t/t3404-rebase-interactive.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ cat > fake-editor.sh << EOF
6565
#!/bin/sh
6666
test "\$1" = .git/COMMIT_EDITMSG && {
6767
test -z "\$FAKE_COMMIT_MESSAGE" || echo "\$FAKE_COMMIT_MESSAGE" > "\$1"
68+
test -z "\$FAKE_COMMIT_AMEND" || echo "\$FAKE_COMMIT_AMEND" >> "\$1"
6869
exit
6970
}
7071
test -z "\$FAKE_LINES" && exit
@@ -212,4 +213,12 @@ test_expect_success 'verbose flag is heeded, even after --continue' '
212213
grep "^ file1 | 2 +-$" output
213214
'
214215

216+
test_expect_success 'multi-squash only fires up editor once' '
217+
base=$(git rev-parse HEAD~4) &&
218+
FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="1 squash 2 squash 3 squash 4" \
219+
git rebase -i $base &&
220+
test $base = $(git rev-parse HEAD^) &&
221+
test 1 = $(git show | grep ONCE | wc -l)
222+
'
223+
215224
test_done

0 commit comments

Comments
 (0)