I have a feature branch with plenty of commits.
A---B---C master
\
\-B'---C'---D'...---Z' feature
I am working on feature
but another developer has created commits B
and C
. Now I want to rebase feature
on commit C
, but I and/or automerge introduced errors during the rebase. My project has very good test coverage and I can run the tests from console using ant rebuild test
, and now I want git to tell me which commit is the first commit that breaks my test so I can fix that commit. How can I do that?
While you are on branch feature
execute:
git rebase --interactive --exec "ant rebuild test" C
This will cause git to start again on commit C, replay your work on top and it will run your tests after each commit it applies during replay phase.
Hopefully your ant task will have a non-zero exit code if your tests fail. In this case git will stop as soon as the tests fail. You are immediately in the right position to amend you commit so that the tests will be happy again. After you have amended just execute git rebase --continue
as usual and git will continue to check all you commits.
Introduced in Git 2.9, you can now execute a command for each commit using the -x
option without having to also add --interactive
.
Instead of running git rebase -i --exec "cmd1 && cmd2 && ..."
, you can now run git rebase -x "cmd1 && cmd2 && ..."
.
To add to the OP yankee's excellent answer, Git 2.5+ will provide a more robust git rebase --interactive --exec
experience, especially in case of a failed exec.
Actually, see the new --reschedule-failed-exec
of Git 2.21 in the last part of this answer.
See commit b12d3e9 [22 May 2015], and commit 1d968ca [22 May 2015] by Matthieu Moy (moy
).
(Merged by Junio C Hamano -- gitster
-- in commit a6be52e, 01 Jun 2015)
The 'exec
' command is sending the current commit to stopped-sha
, which is supposed to contain the original commit (before rebase).
As a result, if an 'exec
' command fails, the next 'git rebase --continue
' will send the current commit as to the post-rewrite hook.
The full documentation:
rebase -i
: fix post-rewrite
hook with failed exec
command
Usually, when 'git rebase
' stops before completing the rebase, it is to give the user an opportunity to edit a commit (e.g. with the 'edit
'
command).
In such cases, 'git rebase
' leaves the sha1 of the commit being rewritten in "$state_dir"/stopped-sha
, and subsequent 'git rebase
--continue
' will call the post-rewrite
hook with this sha1 as <old-sha1>
argument to the post-rewrite
hook.
The case of 'git rebase
' stopping because of a failed 'exec
' command is different: it gives the opportunity to the user to examine or fix the
failure, but does not stop saying "here's a commit to edit, use
--continue
when you're done".
So, there's no reason to call the post-rewrite
hook for 'exec' commands.
If the user did rewrite the commit, it would be with 'git commit --amend
' which already called the post-rewrite
hook.
Fix the behavior to:
- leave no
stopped-sha
file in case of failed exec
command,
- and teach '
git rebase --continue
' to skip record_in_rewritten
if
no stopped-sha
file is found.
To facilitate managing failed exec directives associated to a rebase, Git 2.21 (Q1 2019) introduces --reschedule-failed-exec
, with "git rebase -i
", which learned to re-execute a command given with 'exec
' to run after it failed the last time.
See commit 81ef8ee, commit 969de3f, commit d421afa (10 Dec 2018) by Johannes Schindelin (dscho
).
(Merged by Junio C Hamano -- gitster
-- in commit d9d9ab0, 29 Jan 2019)
rebase
: introduce --reschedule-failed-exec
A common use case for the --exec
option is to verify that each commit
in a topic branch compiles cleanly, via git rebase -x make <base>
.
However, when an exec
in such a rebase fails, it is not re-scheduled, which in this instance is not particularly helpful.
Let's offer a flag to reschedule failed exec
commands.
Based on an idea by Paul Morelle.
The git rebase
man page now includes:
--reschedule-failed-exec::
--no-reschedule-failed-exec::
Automatically reschedule exec
commands that failed.
This only makes sense in interactive mode (or when an --exec
option was provided).
And:
rebase
: introduce a shortcut for --reschedule-failed-exec
It is a bit cumbersome to write out the --reschedule-failed-exec
option before -x <cmd>
all the time; let's introduce a convenient option to do both at the same time: -y <cmd>
.
Note: the first committed in reverted in See commit e11ff89 (06 Feb 2019), and commit 81ef8ee (10 Dec 2018) by Johannes Schindelin (dscho
).
(Merged by Junio C Hamano -- gitster
-- in commit b966813, 09 Feb 2019)
Revert "rebase: introduce a shortcut for --reschedule-failed-exec"
This patch was contributed only as a tentative "we could introduce a
convenient short option if we do not want to change the default behavior
in the long run" patch, opening the discussion whether other people
agree with deprecating the current behavior in favor of the rescheduling
behavior.
But the consensus on the Git mailing list was that it would make sense to show a warning in the near future, and flip the default rebase.rescheduleFailedExec
to reschedule failed exec
commands by default.
So let's back out that patch that added the -y
short option that we
agreed was not necessary or desirable.
Also in Git 2.21 (Feb. 2019): "git rebase -x $cmd
" did not reject multi-line command, even though the command is incapable of handling such a command.
It now is rejected upfront.
See commit c762aad (29 Jan 2019) by Phillip Wood (phillipwood
).
(Merged by Junio C Hamano -- gitster
-- in commit 96e6547, 07 Feb 2019)
rebase -x
: sanity check command
If the user gives an empty argument to --exec
then git creates a todo
list that it cannot parse. The rebase starts to run before erroring out
with:
error: missing arguments for exec
error: invalid line 2: exec
You can fix this with 'git rebase --edit-todo' and then run 'git rebase --continue'.
Or you can abort the rebase with 'git rebase --abort'.
Instead check for empty commands before starting the rebase.
Also check that the command does not contain any newlines as the todo-list format is unable to cope with multiline commands.
Note that this changes the behavior, before this change one could do:
git rebase --exec='echo one
exec echo two'
and it would insert two exec lines in the todo
list, now it will error out.