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.
|
# command is processed, this file is deleted.
|
||||||
AMEND="$DOTEST"/amend
|
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=
|
PRESERVE_MERGES=
|
||||||
STRATEGY=
|
STRATEGY=
|
||||||
ONTO=
|
ONTO=
|
||||||
@ -198,6 +205,7 @@ make_patch () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
die_with_patch () {
|
die_with_patch () {
|
||||||
|
echo "$1" > "$DOTEST"/stopped-sha
|
||||||
make_patch "$1"
|
make_patch "$1"
|
||||||
git rerere
|
git rerere
|
||||||
die "$2"
|
die "$2"
|
||||||
@ -348,6 +356,7 @@ pick_one_preserving_merges () {
|
|||||||
printf "%s\n" "$msg" > "$GIT_DIR"/MERGE_MSG
|
printf "%s\n" "$msg" > "$GIT_DIR"/MERGE_MSG
|
||||||
die_with_patch $sha1 "Error redoing merge $sha1"
|
die_with_patch $sha1 "Error redoing merge $sha1"
|
||||||
fi
|
fi
|
||||||
|
echo "$sha1 $(git rev-parse HEAD^0)" >> "$REWRITTEN_LIST"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
output git cherry-pick "$@" ||
|
output git cherry-pick "$@" ||
|
||||||
@ -425,6 +434,26 @@ die_failed_squash() {
|
|||||||
die_with_patch $1 ""
|
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 () {
|
do_next () {
|
||||||
rm -f "$MSG" "$AUTHOR_SCRIPT" "$AMEND" || exit
|
rm -f "$MSG" "$AUTHOR_SCRIPT" "$AMEND" || exit
|
||||||
read command sha1 rest < "$TODO"
|
read command sha1 rest < "$TODO"
|
||||||
@ -438,6 +467,7 @@ do_next () {
|
|||||||
mark_action_done
|
mark_action_done
|
||||||
pick_one $sha1 ||
|
pick_one $sha1 ||
|
||||||
die_with_patch $sha1 "Could not apply $sha1... $rest"
|
die_with_patch $sha1 "Could not apply $sha1... $rest"
|
||||||
|
record_in_rewritten $sha1
|
||||||
;;
|
;;
|
||||||
reword|r)
|
reword|r)
|
||||||
comment_for_reflog reword
|
comment_for_reflog reword
|
||||||
@ -446,6 +476,7 @@ do_next () {
|
|||||||
pick_one $sha1 ||
|
pick_one $sha1 ||
|
||||||
die_with_patch $sha1 "Could not apply $sha1... $rest"
|
die_with_patch $sha1 "Could not apply $sha1... $rest"
|
||||||
git commit --amend --no-post-rewrite
|
git commit --amend --no-post-rewrite
|
||||||
|
record_in_rewritten $sha1
|
||||||
;;
|
;;
|
||||||
edit|e)
|
edit|e)
|
||||||
comment_for_reflog edit
|
comment_for_reflog edit
|
||||||
@ -453,6 +484,7 @@ do_next () {
|
|||||||
mark_action_done
|
mark_action_done
|
||||||
pick_one $sha1 ||
|
pick_one $sha1 ||
|
||||||
die_with_patch $sha1 "Could not apply $sha1... $rest"
|
die_with_patch $sha1 "Could not apply $sha1... $rest"
|
||||||
|
echo "$1" > "$DOTEST"/stopped-sha
|
||||||
make_patch $sha1
|
make_patch $sha1
|
||||||
git rev-parse --verify HEAD > "$AMEND"
|
git rev-parse --verify HEAD > "$AMEND"
|
||||||
warn "Stopped at $sha1... $rest"
|
warn "Stopped at $sha1... $rest"
|
||||||
@ -509,6 +541,7 @@ do_next () {
|
|||||||
rm -f "$SQUASH_MSG" "$FIXUP_MSG"
|
rm -f "$SQUASH_MSG" "$FIXUP_MSG"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
record_in_rewritten $sha1
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
warn "Unknown command: $command $sha1 $rest"
|
warn "Unknown command: $command $sha1 $rest"
|
||||||
@ -537,6 +570,11 @@ do_next () {
|
|||||||
test ! -f "$DOTEST"/verbose ||
|
test ! -f "$DOTEST"/verbose ||
|
||||||
git diff-tree --stat $(cat "$DOTEST"/head)..HEAD
|
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" &&
|
rm -rf "$DOTEST" &&
|
||||||
git gc --auto &&
|
git gc --auto &&
|
||||||
warn "Successfully rebased and updated $HEADNAME."
|
warn "Successfully rebased and updated $HEADNAME."
|
||||||
@ -571,7 +609,12 @@ skip_unnecessary_picks () {
|
|||||||
esac
|
esac
|
||||||
echo "$command${sha1:+ }$sha1${rest:+ }$rest" >&$fd
|
echo "$command${sha1:+ }$sha1${rest:+ }$rest" >&$fd
|
||||||
done <"$TODO" >"$TODO.new" 3>>"$DONE" &&
|
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"
|
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
|
test -n "$amend" && git reset --soft $amend
|
||||||
die "Could not commit staged changes."
|
die "Could not commit staged changes."
|
||||||
}
|
}
|
||||||
|
record_in_rewritten "$(cat "$DOTEST"/stopped-sha)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
require_clean_work_tree
|
require_clean_work_tree
|
||||||
|
@ -79,4 +79,105 @@ EOF
|
|||||||
verify_hook_input
|
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
|
test_done
|
||||||
|
Loading…
Reference in New Issue
Block a user