Skip to content

Commit

Permalink
rebase -i: teach "--exec <cmd>"
Browse files Browse the repository at this point in the history
During an interactive rebase session, it is sometimes desirable to
run tests on each commit in the resulting history.  This can be done
by adding "exec <test command>" when editing the insn sheet, but the
command used for testing is often the same for all resulting commits.

By passing "--exec <cmd>" from the command line, automatically add
these "exec" lines after each commit in the final history.  To work
well with the --autosquash option, these are added at the end of
each run of "fixup" and "squash".

Helped-by: Johannes Sixt <j6t@kdbg.org>
Signed-off-by: Lucien Kong <Lucien.Kong@ensimag.imag.fr>
Signed-off-by: Valentin Duperray <Valentin.Duperray@ensimag.imag.fr>
Signed-off-by: Franck Jonas <Franck.Jonas@ensimag.imag.fr>
Signed-off-by: Thomas Nguy <Thomas.Nguy@ensimag.imag.fr>
Signed-off-by: Huynh Khoi Nguyen Nguyen <Huynh-Khoi-Nguyen.Nguyen@ensimag.imag.fr>
Signed-off-by: Matthieu Moy <Matthieu.Moy@grenoble-inp.fr>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Lucien Kong authored and Junio C Hamano committed Jun 13, 2012
1 parent f623ca1 commit c214538
Show file tree
Hide file tree
Showing 4 changed files with 199 additions and 6 deletions.
45 changes: 42 additions & 3 deletions Documentation/git-rebase.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ git-rebase - Forward-port local commits to the updated upstream head
SYNOPSIS
--------
[verse]
'git rebase' [-i | --interactive] [options] [--onto <newbase>]
'git rebase' [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>]
[<upstream>] [<branch>]
'git rebase' [-i | --interactive] [options] --onto <newbase>
'git rebase' [-i | --interactive] [options] [--exec <cmd>] --onto <newbase>
--root [<branch>]
'git rebase' --continue | --skip | --abort

Expand Down Expand Up @@ -210,7 +210,7 @@ rebase.autosquash::

OPTIONS
-------
<newbase>::
--onto <newbase>::
Starting point at which to create the new commits. If the
--onto option is not specified, the starting point is
<upstream>. May be any valid commit, and not just an
Expand Down Expand Up @@ -344,6 +344,27 @@ This uses the `--interactive` machinery internally, but combining it
with the `--interactive` option explicitly is generally not a good
idea unless you know what you are doing (see BUGS below).

-x <cmd>::
--exec <cmd>::
Append "exec <cmd>" after each line creating a commit in the
final history. <cmd> will be interpreted as one or more shell
commands.
+
This option can only be used with the `--interactive` option
(see INTERACTIVE MODE below).
+
You may execute several commands by either using one instance of `--exec`
with several commands:
+
git rebase -i --exec "cmd1 && cmd2 && ..."
+
or by giving more than one `--exec`:
+
git rebase -i --exec "cmd1" --exec "cmd2" --exec ...
+
If `--autosquash` is used, "exec" lines will not be appended for
the intermediate commits, and will only appear at the end of each
squash/fixup series.

--root::
Rebase all commits reachable from <branch>, instead of
Expand Down Expand Up @@ -521,6 +542,24 @@ in `$SHELL`, or the default shell if `$SHELL` is not set), so you can
use shell features (like "cd", ">", ";" ...). The command is run from
the root of the working tree.

----------------------------------
$ git rebase -i --exec "make test"
----------------------------------

This command lets you check that intermediate commits are compilable.
The todo list becomes like that:

--------------------
pick 5928aea one
exec make test
pick 04d0fda two
exec make test
pick ba46169 three
exec make test
pick f4593f9 four
exec make test
--------------------

SPLITTING COMMITS
-----------------

Expand Down
23 changes: 23 additions & 0 deletions git-rebase--interactive.sh
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,27 @@ rearrange_squash () {
rm -f "$1.sq" "$1.rearranged"
}

# Add commands after a pick or after a squash/fixup serie
# in the todo list.
add_exec_commands () {
{
first=t
while read -r insn rest
do
case $insn in
pick)
test -n "$first" ||
printf "%s" "$cmd"
;;
esac
printf "%s %s\n" "$insn" "$rest"
first=
done
printf "%s" "$cmd"
} <"$1" >"$1.new" &&
mv "$1.new" "$1"
}

case "$action" in
continue)
# do we have anything to commit?
Expand Down Expand Up @@ -857,6 +878,8 @@ fi

test -s "$todo" || echo noop >> "$todo"
test -n "$autosquash" && rearrange_squash "$todo"
test -n "$cmd" && add_exec_commands "$todo"

cat >> "$todo" << EOF
# Rebase $shortrevisions onto $shortonto
Expand Down
20 changes: 17 additions & 3 deletions git-rebase.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
# Copyright (c) 2005 Junio C Hamano.
#

USAGE='[--interactive | -i] [-v] [--force-rebase | -f] [--no-ff] [--onto <newbase>] [<upstream>|--root] [<branch>] [--quiet | -q]'
USAGE='[--interactive | -i] [--exec | -x <cmd>] [-v] [--force-rebase | -f]
[--no-ff] [--onto <newbase>] [<upstream>|--root] [<branch>] [--quiet | -q]'
LONG_USAGE='git-rebase replaces <branch> with a new branch of the
same name. When the --onto option is provided the new branch starts
out with a HEAD equal to <newbase>, otherwise it is equal to <upstream>
Expand All @@ -30,8 +31,8 @@ Example: git-rebase master~1 topic
SUBDIRECTORY_OK=Yes
OPTIONS_KEEPDASHDASH=
OPTIONS_SPEC="\
git rebase [-i] [options] [--onto <newbase>] [<upstream>] [<branch>]
git rebase [-i] [options] --onto <newbase> --root [<branch>]
git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] [<upstream>] [<branch>]
git rebase [-i] [options] [--exec <cmd>] --onto <newbase> --root [<branch>]
git-rebase [-i] --continue | --abort | --skip
--
Available options are
Expand All @@ -43,6 +44,7 @@ s,strategy=! use the given merge strategy
no-ff! cherry-pick all commits, even if unchanged
m,merge! use merging strategies to rebase
i,interactive! let the user edit the list of commits to rebase
x,exec=! add exec lines after each commit of the editable list
k,keep-empty preserve empty commits during rebase
f,force-rebase! force rebase even if branch is up to date
X,strategy-option=! pass the argument through to the merge strategy
Expand Down Expand Up @@ -76,6 +78,7 @@ If you would prefer to skip this patch, instead run \"git rebase --skip\".
To check out the original branch and stop rebasing run \"git rebase --abort\".
"
unset onto
cmd=
strategy=
strategy_opts=
do_merge=
Expand Down Expand Up @@ -220,6 +223,11 @@ do
onto="$2"
shift
;;
-x)
test 2 -le "$#" || usage
cmd="${cmd}exec $2${LF}"
shift
;;
-i)
interactive_rebase=explicit
;;
Expand Down Expand Up @@ -305,6 +313,12 @@ do
done
test $# -gt 2 && usage

if test -n "$cmd" &&
test "$interactive_rebase" != explicit
then
die "--exec option must be used with --interactive option"
fi

if test -n "$action"
then
test -z "$in_progress" && die "No rebase in progress?"
Expand Down
117 changes: 117 additions & 0 deletions t/t3404-rebase-interactive.sh
Original file line number Diff line number Diff line change
Expand Up @@ -755,4 +755,121 @@ test_expect_success 'rebase-i history with funny messages' '
test_cmp expect actual
'


test_expect_success 'prepare for rebase -i --exec' '
git checkout master &&
git checkout -b execute &&
test_commit one_exec main.txt one_exec &&
test_commit two_exec main.txt two_exec &&
test_commit three_exec main.txt three_exec
'


test_expect_success 'running "git rebase -i --exec git show HEAD"' '
git rebase -i --exec "git show HEAD" HEAD~2 >actual &&
(
FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
export FAKE_LINES &&
git rebase -i HEAD~2 >expect
) &&
sed -e "1,9d" expect >expected &&
test_cmp expected actual
'


test_expect_success 'running "git rebase --exec git show HEAD -i"' '
git reset --hard execute &&
git rebase --exec "git show HEAD" -i HEAD~2 >actual &&
(
FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
export FAKE_LINES &&
git rebase -i HEAD~2 >expect
) &&
sed -e "1,9d" expect >expected &&
test_cmp expected actual
'


test_expect_success 'running "git rebase -ix git show HEAD"' '
git reset --hard execute &&
git rebase -ix "git show HEAD" HEAD~2 >actual &&
(
FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
export FAKE_LINES &&
git rebase -i HEAD~2 >expect
) &&
sed -e "1,9d" expect >expected &&
test_cmp expected actual
'


test_expect_success 'rebase -ix with several <CMD>' '
git reset --hard execute &&
git rebase -ix "git show HEAD; pwd" HEAD~2 >actual &&
(
FAKE_LINES="1 exec_git_show_HEAD;_pwd 2 exec_git_show_HEAD;_pwd" &&
export FAKE_LINES &&
git rebase -i HEAD~2 >expect
) &&
sed -e "1,9d" expect >expected &&
test_cmp expected actual
'


test_expect_success 'rebase -ix with several instances of --exec' '
git reset --hard execute &&
git rebase -i --exec "git show HEAD" --exec "pwd" HEAD~2 >actual &&
(
FAKE_LINES="1 exec_git_show_HEAD exec_pwd 2
exec_git_show_HEAD exec_pwd" &&
export FAKE_LINES &&
git rebase -i HEAD~2 >expect
) &&
sed -e "1,11d" expect >expected &&
test_cmp expected actual
'


test_expect_success 'rebase -ix with --autosquash' '
git reset --hard execute &&
git checkout -b autosquash &&
echo second >second.txt &&
git add second.txt &&
git commit -m "fixup! two_exec" &&
echo bis >bis.txt &&
git add bis.txt &&
git commit -m "fixup! two_exec" &&
(
git checkout -b autosquash_actual &&
git rebase -i --exec "git show HEAD" --autosquash HEAD~4 >actual
) &&
git checkout autosquash &&
(
git checkout -b autosquash_expected &&
FAKE_LINES="1 fixup 3 fixup 4 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
export FAKE_LINES &&
git rebase -i HEAD~4 >expect
) &&
sed -e "1,13d" expect >expected &&
test_cmp expected actual
'


test_expect_success 'rebase --exec without -i shows error message' '
git reset --hard execute &&
test_must_fail git rebase --exec "git show HEAD" HEAD~2 2>actual &&
echo "--exec option must be used with --interactive option" >expected &&
test_i18ncmp expected actual
'


test_expect_success 'rebase -i --exec without <CMD>' '
git reset --hard execute &&
test_must_fail git rebase -i --exec 2>tmp &&
sed -e "1d" tmp >actual &&
test_must_fail git rebase -h >expected &&
test_cmp expected actual &&
git checkout master
'

test_done

0 comments on commit c214538

Please sign in to comment.