rebase -i: teach "--exec <cmd>"
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>
This commit is contained in:
parent
f623ca1cae
commit
c214538416
@ -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
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
-----------------
|
||||
|
||||
|
@ -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?
|
||||
@ -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
|
||||
|
@ -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>
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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=
|
||||
@ -220,6 +223,11 @@ do
|
||||
onto="$2"
|
||||
shift
|
||||
;;
|
||||
-x)
|
||||
test 2 -le "$#" || usage
|
||||
cmd="${cmd}exec $2${LF}"
|
||||
shift
|
||||
;;
|
||||
-i)
|
||||
interactive_rebase=explicit
|
||||
;;
|
||||
@ -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?"
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user