@matheusbsbs / matheus-bagliano / commits / b079feed64
Fork 0

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>

Thomas Rast committed Mar 12, 2010 at 18:04 UTC b079feed64238558fa24ba8ade892d84628a05ac
2 files changed +146 -1
git-rebase--interactive.sh
+45 -1
@@ -96,6 +96,13 @@ AUTHOR_SCRIPT="$DOTEST"/author-script
96 # command is processed, this file is deleted.
97 AMEND="$DOTEST"/amend
98
99 +# For the post-rewrite hook, we make a list of rewritten commits and
100 +# their new sha1s. The rewritten-pending list keeps the sha1s of
101 +# commits that have been processed, but not committed yet,
102 +# e.g. because they are waiting for a 'squash' command.
103 +REWRITTEN_LIST="$DOTEST"/rewritten-list
104 +REWRITTEN_PENDING="$DOTEST"/rewritten-pending
105 +
106 PRESERVE_MERGES=
107 STRATEGY=
108 ONTO=
@@ -198,6 +205,7 @@ make_patch () {
205 }
206
207 die_with_patch () {
208 + echo "$1" > "$DOTEST"/stopped-sha
209 make_patch "$1"
210 git rerere
211 die "$2"
@@ -348,6 +356,7 @@ pick_one_preserving_merges () {
356 printf "%s\n" "$msg" > "$GIT_DIR"/MERGE_MSG
357 die_with_patch $sha1 "Error redoing merge $sha1"
358 fi
359 + echo "$sha1 $(git rev-parse HEAD^0)" >> "$REWRITTEN_LIST"
360 ;;
361 *)
362 output git cherry-pick "$@" ||
@@ -425,6 +434,26 @@ die_failed_squash() {
434 die_with_patch $1 ""
435 }
436
437 +flush_rewritten_pending() {
438 + test -s "$REWRITTEN_PENDING" || return
439 + newsha1="$(git rev-parse HEAD^0)"
440 + sed "s/$/ $newsha1/" < "$REWRITTEN_PENDING" >> "$REWRITTEN_LIST"
441 + rm -f "$REWRITTEN_PENDING"
442 +}
443 +
444 +record_in_rewritten() {
445 + oldsha1="$(git rev-parse $1)"
446 + echo "$oldsha1" >> "$REWRITTEN_PENDING"
447 +
448 + case "$(peek_next_command)" in
449 + squash|s|fixup|f)
450 + ;;
451 + *)
452 + flush_rewritten_pending
453 + ;;
454 + esac
455 +}
456 +
457 do_next () {
458 rm -f "$MSG" "$AUTHOR_SCRIPT" "$AMEND" || exit
459 read command sha1 rest < "$TODO"
@@ -438,6 +467,7 @@ do_next () {
467 mark_action_done
468 pick_one $sha1 ||
469 die_with_patch $sha1 "Could not apply $sha1... $rest"
470 + record_in_rewritten $sha1
471 ;;
472 reword|r)
473 comment_for_reflog reword
@@ -446,6 +476,7 @@ do_next () {
476 pick_one $sha1 ||
477 die_with_patch $sha1 "Could not apply $sha1... $rest"
478 git commit --amend --no-post-rewrite
479 + record_in_rewritten $sha1
480 ;;
481 edit|e)
482 comment_for_reflog edit
@@ -453,6 +484,7 @@ do_next () {
484 mark_action_done
485 pick_one $sha1 ||
486 die_with_patch $sha1 "Could not apply $sha1... $rest"
487 + echo "$1" > "$DOTEST"/stopped-sha
488 make_patch $sha1
489 git rev-parse --verify HEAD > "$AMEND"
490 warn "Stopped at $sha1... $rest"
@@ -509,6 +541,7 @@ do_next () {
541 rm -f "$SQUASH_MSG" "$FIXUP_MSG"
542 ;;
543 esac
544 + record_in_rewritten $sha1
545 ;;
546 *)
547 warn "Unknown command: $command $sha1 $rest"
@@ -537,6 +570,11 @@ do_next () {
570 test ! -f "$DOTEST"/verbose ||
571 git diff-tree --stat $(cat "$DOTEST"/head)..HEAD
572 } &&
573 + if test -x "$GIT_DIR"/hooks/post-rewrite &&
574 + test -s "$REWRITTEN_LIST"; then
575 + "$GIT_DIR"/hooks/post-rewrite rebase < "$REWRITTEN_LIST"
576 + true # we don't care if this hook failed
577 + fi &&
578 rm -rf "$DOTEST" &&
579 git gc --auto &&
580 warn "Successfully rebased and updated $HEADNAME."
@@ -571,7 +609,12 @@ skip_unnecessary_picks () {
609 esac
610 echo "$command${sha1:+ }$sha1${rest:+ }$rest" >&$fd
611 done <"$TODO" >"$TODO.new" 3>>"$DONE" &&
574 - mv -f "$TODO".new "$TODO" ||
612 + mv -f "$TODO".new "$TODO" &&
613 + case "$(peek_next_command)" in
614 + squash|s|fixup|f)
615 + record_in_rewritten "$ONTO"
616 + ;;
617 + esac ||
618 die "Could not skip unnecessary pick commands"
619 }
620
@@ -685,6 +728,7 @@ first and then run 'git rebase --continue' again."
728 test -n "$amend" && git reset --soft $amend
729 die "Could not commit staged changes."
730 }
731 + record_in_rewritten "$(cat "$DOTEST"/stopped-sha)"
732 fi
733
734 require_clean_work_tree
t/t5407-post-rewrite-hook.sh
+101
@@ -79,4 +79,105 @@ EOF
79 verify_hook_input
80 '
81
82 +test_expect_success 'git rebase -m' '
83 + git reset --hard D &&
84 + clear_hook_input &&
85 + test_must_fail git rebase -m --onto A B &&
86 + echo C > foo &&
87 + git add foo &&
88 + git rebase --continue &&
89 + echo rebase >expected.args &&
90 + cat >expected.data <<EOF &&
91 +$(git rev-parse C) $(git rev-parse HEAD^)
92 +$(git rev-parse D) $(git rev-parse HEAD)
93 +EOF
94 + verify_hook_input
95 +'
96 +
97 +test_expect_success 'git rebase -m --skip' '
98 + git reset --hard D &&
99 + clear_hook_input &&
100 + test_must_fail git rebase --onto A B &&
101 + test_must_fail git rebase --skip &&
102 + echo D > foo &&
103 + git add foo &&
104 + git rebase --continue &&
105 + echo rebase >expected.args &&
106 + cat >expected.data <<EOF &&
107 +$(git rev-parse D) $(git rev-parse HEAD)
108 +EOF
109 + verify_hook_input
110 +'
111 +
112 +. "$TEST_DIRECTORY"/lib-rebase.sh
113 +
114 +set_fake_editor
115 +
116 +# Helper to work around the lack of one-shot exporting for
117 +# test_must_fail (as it is a shell function)
118 +test_fail_interactive_rebase () {
119 + (
120 + FAKE_LINES="$1" &&
121 + shift &&
122 + export FAKE_LINES &&
123 + test_must_fail git rebase -i "$@"
124 + )
125 +}
126 +
127 +test_expect_success 'git rebase -i (unchanged)' '
128 + git reset --hard D &&
129 + clear_hook_input &&
130 + test_fail_interactive_rebase "1 2" --onto A B &&
131 + echo C > foo &&
132 + git add foo &&
133 + git rebase --continue &&
134 + echo rebase >expected.args &&
135 + cat >expected.data <<EOF &&
136 +$(git rev-parse C) $(git rev-parse HEAD^)
137 +$(git rev-parse D) $(git rev-parse HEAD)
138 +EOF
139 + verify_hook_input
140 +'
141 +
142 +test_expect_success 'git rebase -i (skip)' '
143 + git reset --hard D &&
144 + clear_hook_input &&
145 + test_fail_interactive_rebase "2" --onto A B &&
146 + echo D > foo &&
147 + git add foo &&
148 + git rebase --continue &&
149 + echo rebase >expected.args &&
150 + cat >expected.data <<EOF &&
151 +$(git rev-parse D) $(git rev-parse HEAD)
152 +EOF
153 + verify_hook_input
154 +'
155 +
156 +test_expect_success 'git rebase -i (squash)' '
157 + git reset --hard D &&
158 + clear_hook_input &&
159 + test_fail_interactive_rebase "1 squash 2" --onto A B &&
160 + echo C > foo &&
161 + git add foo &&
162 + git rebase --continue &&
163 + echo rebase >expected.args &&
164 + cat >expected.data <<EOF &&
165 +$(git rev-parse C) $(git rev-parse HEAD)
166 +$(git rev-parse D) $(git rev-parse HEAD)
167 +EOF
168 + verify_hook_input
169 +'
170 +
171 +test_expect_success 'git rebase -i (fixup without conflict)' '
172 + git reset --hard D &&
173 + clear_hook_input &&
174 + FAKE_LINES="1 fixup 2" git rebase -i B &&
175 + echo rebase >expected.args &&
176 + cat >expected.data <<EOF &&
177 +$(git rev-parse C) $(git rev-parse HEAD)
178 +$(git rev-parse D) $(git rev-parse HEAD)
179 +EOF
180 + verify_hook_input
181 +'
182 +
183 test_done