rebase -i: invoke post-rewrite hook
Aside from the same issue that rebase also has (remembering the original commit across a conflict resolution), rebase -i brings an extra twist: We need to defer writing the rewritten list in the case of {squash,fixup} because their rewritten result should be the last commit in the squashed group. Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
96e19488f1
commit
b079feed64
@ -96,6 +96,13 @@ AUTHOR_SCRIPT="$DOTEST"/author-script
|
||||
# command is processed, this file is deleted.
|
||||
AMEND="$DOTEST"/amend
|
||||
|
||||
# For the post-rewrite hook, we make a list of rewritten commits and
|
||||
# their new sha1s. The rewritten-pending list keeps the sha1s of
|
||||
# commits that have been processed, but not committed yet,
|
||||
# e.g. because they are waiting for a 'squash' command.
|
||||
REWRITTEN_LIST="$DOTEST"/rewritten-list
|
||||
REWRITTEN_PENDING="$DOTEST"/rewritten-pending
|
||||
|
||||
PRESERVE_MERGES=
|
||||
STRATEGY=
|
||||
ONTO=
|
||||
@ -198,6 +205,7 @@ make_patch () {
|
||||
}
|
||||
|
||||
die_with_patch () {
|
||||
echo "$1" > "$DOTEST"/stopped-sha
|
||||
make_patch "$1"
|
||||
git rerere
|
||||
die "$2"
|
||||
@ -348,6 +356,7 @@ pick_one_preserving_merges () {
|
||||
printf "%s\n" "$msg" > "$GIT_DIR"/MERGE_MSG
|
||||
die_with_patch $sha1 "Error redoing merge $sha1"
|
||||
fi
|
||||
echo "$sha1 $(git rev-parse HEAD^0)" >> "$REWRITTEN_LIST"
|
||||
;;
|
||||
*)
|
||||
output git cherry-pick "$@" ||
|
||||
@ -425,6 +434,26 @@ die_failed_squash() {
|
||||
die_with_patch $1 ""
|
||||
}
|
||||
|
||||
flush_rewritten_pending() {
|
||||
test -s "$REWRITTEN_PENDING" || return
|
||||
newsha1="$(git rev-parse HEAD^0)"
|
||||
sed "s/$/ $newsha1/" < "$REWRITTEN_PENDING" >> "$REWRITTEN_LIST"
|
||||
rm -f "$REWRITTEN_PENDING"
|
||||
}
|
||||
|
||||
record_in_rewritten() {
|
||||
oldsha1="$(git rev-parse $1)"
|
||||
echo "$oldsha1" >> "$REWRITTEN_PENDING"
|
||||
|
||||
case "$(peek_next_command)" in
|
||||
squash|s|fixup|f)
|
||||
;;
|
||||
*)
|
||||
flush_rewritten_pending
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
do_next () {
|
||||
rm -f "$MSG" "$AUTHOR_SCRIPT" "$AMEND" || exit
|
||||
read command sha1 rest < "$TODO"
|
||||
@ -438,6 +467,7 @@ do_next () {
|
||||
mark_action_done
|
||||
pick_one $sha1 ||
|
||||
die_with_patch $sha1 "Could not apply $sha1... $rest"
|
||||
record_in_rewritten $sha1
|
||||
;;
|
||||
reword|r)
|
||||
comment_for_reflog reword
|
||||
@ -446,6 +476,7 @@ do_next () {
|
||||
pick_one $sha1 ||
|
||||
die_with_patch $sha1 "Could not apply $sha1... $rest"
|
||||
git commit --amend --no-post-rewrite
|
||||
record_in_rewritten $sha1
|
||||
;;
|
||||
edit|e)
|
||||
comment_for_reflog edit
|
||||
@ -453,6 +484,7 @@ do_next () {
|
||||
mark_action_done
|
||||
pick_one $sha1 ||
|
||||
die_with_patch $sha1 "Could not apply $sha1... $rest"
|
||||
echo "$1" > "$DOTEST"/stopped-sha
|
||||
make_patch $sha1
|
||||
git rev-parse --verify HEAD > "$AMEND"
|
||||
warn "Stopped at $sha1... $rest"
|
||||
@ -509,6 +541,7 @@ do_next () {
|
||||
rm -f "$SQUASH_MSG" "$FIXUP_MSG"
|
||||
;;
|
||||
esac
|
||||
record_in_rewritten $sha1
|
||||
;;
|
||||
*)
|
||||
warn "Unknown command: $command $sha1 $rest"
|
||||
@ -537,6 +570,11 @@ do_next () {
|
||||
test ! -f "$DOTEST"/verbose ||
|
||||
git diff-tree --stat $(cat "$DOTEST"/head)..HEAD
|
||||
} &&
|
||||
if test -x "$GIT_DIR"/hooks/post-rewrite &&
|
||||
test -s "$REWRITTEN_LIST"; then
|
||||
"$GIT_DIR"/hooks/post-rewrite rebase < "$REWRITTEN_LIST"
|
||||
true # we don't care if this hook failed
|
||||
fi &&
|
||||
rm -rf "$DOTEST" &&
|
||||
git gc --auto &&
|
||||
warn "Successfully rebased and updated $HEADNAME."
|
||||
@ -571,7 +609,12 @@ skip_unnecessary_picks () {
|
||||
esac
|
||||
echo "$command${sha1:+ }$sha1${rest:+ }$rest" >&$fd
|
||||
done <"$TODO" >"$TODO.new" 3>>"$DONE" &&
|
||||
mv -f "$TODO".new "$TODO" ||
|
||||
mv -f "$TODO".new "$TODO" &&
|
||||
case "$(peek_next_command)" in
|
||||
squash|s|fixup|f)
|
||||
record_in_rewritten "$ONTO"
|
||||
;;
|
||||
esac ||
|
||||
die "Could not skip unnecessary pick commands"
|
||||
}
|
||||
|
||||
@ -685,6 +728,7 @@ first and then run 'git rebase --continue' again."
|
||||
test -n "$amend" && git reset --soft $amend
|
||||
die "Could not commit staged changes."
|
||||
}
|
||||
record_in_rewritten "$(cat "$DOTEST"/stopped-sha)"
|
||||
fi
|
||||
|
||||
require_clean_work_tree
|
||||
|
@ -79,4 +79,105 @@ EOF
|
||||
verify_hook_input
|
||||
'
|
||||
|
||||
test_expect_success 'git rebase -m' '
|
||||
git reset --hard D &&
|
||||
clear_hook_input &&
|
||||
test_must_fail git rebase -m --onto A B &&
|
||||
echo C > foo &&
|
||||
git add foo &&
|
||||
git rebase --continue &&
|
||||
echo rebase >expected.args &&
|
||||
cat >expected.data <<EOF &&
|
||||
$(git rev-parse C) $(git rev-parse HEAD^)
|
||||
$(git rev-parse D) $(git rev-parse HEAD)
|
||||
EOF
|
||||
verify_hook_input
|
||||
'
|
||||
|
||||
test_expect_success 'git rebase -m --skip' '
|
||||
git reset --hard D &&
|
||||
clear_hook_input &&
|
||||
test_must_fail git rebase --onto A B &&
|
||||
test_must_fail git rebase --skip &&
|
||||
echo D > foo &&
|
||||
git add foo &&
|
||||
git rebase --continue &&
|
||||
echo rebase >expected.args &&
|
||||
cat >expected.data <<EOF &&
|
||||
$(git rev-parse D) $(git rev-parse HEAD)
|
||||
EOF
|
||||
verify_hook_input
|
||||
'
|
||||
|
||||
. "$TEST_DIRECTORY"/lib-rebase.sh
|
||||
|
||||
set_fake_editor
|
||||
|
||||
# Helper to work around the lack of one-shot exporting for
|
||||
# test_must_fail (as it is a shell function)
|
||||
test_fail_interactive_rebase () {
|
||||
(
|
||||
FAKE_LINES="$1" &&
|
||||
shift &&
|
||||
export FAKE_LINES &&
|
||||
test_must_fail git rebase -i "$@"
|
||||
)
|
||||
}
|
||||
|
||||
test_expect_success 'git rebase -i (unchanged)' '
|
||||
git reset --hard D &&
|
||||
clear_hook_input &&
|
||||
test_fail_interactive_rebase "1 2" --onto A B &&
|
||||
echo C > foo &&
|
||||
git add foo &&
|
||||
git rebase --continue &&
|
||||
echo rebase >expected.args &&
|
||||
cat >expected.data <<EOF &&
|
||||
$(git rev-parse C) $(git rev-parse HEAD^)
|
||||
$(git rev-parse D) $(git rev-parse HEAD)
|
||||
EOF
|
||||
verify_hook_input
|
||||
'
|
||||
|
||||
test_expect_success 'git rebase -i (skip)' '
|
||||
git reset --hard D &&
|
||||
clear_hook_input &&
|
||||
test_fail_interactive_rebase "2" --onto A B &&
|
||||
echo D > foo &&
|
||||
git add foo &&
|
||||
git rebase --continue &&
|
||||
echo rebase >expected.args &&
|
||||
cat >expected.data <<EOF &&
|
||||
$(git rev-parse D) $(git rev-parse HEAD)
|
||||
EOF
|
||||
verify_hook_input
|
||||
'
|
||||
|
||||
test_expect_success 'git rebase -i (squash)' '
|
||||
git reset --hard D &&
|
||||
clear_hook_input &&
|
||||
test_fail_interactive_rebase "1 squash 2" --onto A B &&
|
||||
echo C > foo &&
|
||||
git add foo &&
|
||||
git rebase --continue &&
|
||||
echo rebase >expected.args &&
|
||||
cat >expected.data <<EOF &&
|
||||
$(git rev-parse C) $(git rev-parse HEAD)
|
||||
$(git rev-parse D) $(git rev-parse HEAD)
|
||||
EOF
|
||||
verify_hook_input
|
||||
'
|
||||
|
||||
test_expect_success 'git rebase -i (fixup without conflict)' '
|
||||
git reset --hard D &&
|
||||
clear_hook_input &&
|
||||
FAKE_LINES="1 fixup 2" git rebase -i B &&
|
||||
echo rebase >expected.args &&
|
||||
cat >expected.data <<EOF &&
|
||||
$(git rev-parse C) $(git rev-parse HEAD)
|
||||
$(git rev-parse D) $(git rev-parse HEAD)
|
||||
EOF
|
||||
verify_hook_input
|
||||
'
|
||||
|
||||
test_done
|
||||
|
Loading…
Reference in New Issue
Block a user