rebase: introduce and use pseudo-ref REBASE_HEAD

The new command `git rebase --show-current-patch` is useful for seeing the commit related to the current rebase state. Some however may find the "git show" command behind it too limiting. You may want to increase context lines, do a diff that ignores whitespaces... For these advanced use cases, the user can execute any command they want with the new pseudo ref REBASE_HEAD. This also helps show where the stopped commit is from, which is hard to see from the previous patch which implements --show-current-patch. Helped-by: Tim Landscheidt <tim@tim-landscheidt.de> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Nguyễn Thái Ngọc Duy committed Feb 11, 2018 at 16:43 UTC fbd7a23237094c3fb2e249bbcacbbf1e858e79c9
9 files changed +25 -6
Documentation/git-rebase.txt
+2 -1
@@ -252,7 +252,8 @@ leave out at most one of A and B, in which case it defaults to HEAD.
252
253 --show-current-patch::
254 Show the current patch in an interactive rebase or when rebase
255 - is stopped because of conflicts.
255 + is stopped because of conflicts. This is the equivalent of
256 + `git show REBASE_HEAD`.
257
258 -m::
259 --merge::
builtin/am.c
+4
@@ -1011,6 +1011,7 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
1011
1012 if (mkdir(state->dir, 0777) < 0 && errno != EEXIST)
1013 die_errno(_("failed to create directory '%s'"), state->dir);
1014 + delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
1015
1016 if (split_mail(state, patch_format, paths, keep_cr) < 0) {
1017 am_destroy(state);
@@ -1110,6 +1111,7 @@ static void am_next(struct am_state *state)
1111
1112 oidclr(&state->orig_commit);
1113 unlink(am_path(state, "original-commit"));
1114 + delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
1115
1116 if (!get_oid("HEAD", &head))
1117 write_state_text(state, "abort-safety", oid_to_hex(&head));
@@ -1441,6 +1443,8 @@ static int parse_mail_rebase(struct am_state *state, const char *mail)
1443
1444 oidcpy(&state->orig_commit, &commit_oid);
1445 write_state_text(state, "original-commit", oid_to_hex(&commit_oid));
1446 + update_ref("am", "REBASE_HEAD", &commit_oid,
1447 + NULL, REF_NO_DEREF, UPDATE_REFS_DIE_ON_ERR);
1448
1449 return 0;
1450 }
contrib/completion/git-completion.bash
+1 -1
@@ -439,7 +439,7 @@ __git_refs ()
439 track=""
440 ;;
441 *)
442 - for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD; do
442 + for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD REBASE_HEAD; do
443 case "$i" in
444 $match*)
445 if [ -e "$dir/$i" ]; then
git-rebase--interactive.sh
+4 -1
@@ -199,12 +199,14 @@ make_patch () {
199
200 die_with_patch () {
201 echo "$1" > "$state_dir"/stopped-sha
202 + git update-ref REBASE_HEAD "$1"
203 make_patch "$1"
204 die "$2"
205 }
206
207 exit_with_patch () {
208 echo "$1" > "$state_dir"/stopped-sha
209 + git update-ref REBASE_HEAD "$1"
210 make_patch $1
211 git rev-parse --verify HEAD > "$amend"
212 gpg_sign_opt_quoted=${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")}
@@ -841,7 +843,7 @@ To continue rebase after editing, run:
843 exit
844 ;;
845 show-current-patch)
844 - exec git show "$(cat "$state_dir/stopped-sha")" --
846 + exec git show REBASE_HEAD --
847 ;;
848 esac
849
@@ -858,6 +860,7 @@ fi
860
861 orig_head=$(git rev-parse --verify HEAD) || die "$(gettext "No HEAD?")"
862 mkdir -p "$state_dir" || die "$(eval_gettext "Could not create temporary \$state_dir")"
863 +rm -f "$(git rev-parse --git-path REBASE_HEAD)"
864
865 : > "$state_dir"/interactive || die "$(gettext "Could not mark as interactive")"
866 write_basic_state
git-rebase--merge.sh
+3 -1
@@ -57,6 +57,7 @@ call_merge () {
57 echo "$msgnum" >"$state_dir/msgnum"
58 cmt="$(cat "$state_dir/cmt.$msgnum")"
59 echo "$cmt" > "$state_dir/current"
60 + git update-ref REBASE_HEAD "$cmt"
61 hd=$(git rev-parse --verify HEAD)
62 cmt_name=$(git symbolic-ref HEAD 2> /dev/null || echo HEAD)
63 eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"'
@@ -138,13 +139,14 @@ skip)
139 return
140 ;;
141 show-current-patch)
141 - exec git show "$(cat "$state_dir/current")" --
142 + exec git show REBASE_HEAD --
143 ;;
144 esac
145
146 mkdir -p "$state_dir"
147 echo "$onto_name" > "$state_dir/onto_name"
148 write_basic_state
149 +rm -f "$(git rev-parse --git-path REBASE_HEAD)"
150
151 msgnum=0
152 for cmt in $(git rev-list --reverse --no-merges "$revisions")
git-rebase.sh
+1
@@ -182,6 +182,7 @@ You can run "git stash pop" or "git stash drop" at any time.
182 }
183
184 finish_rebase () {
185 + rm -f "$(git rev-parse --git-path REBASE_HEAD)"
186 apply_autostash &&
187 { git gc --auto || true; } &&
188 rm -rf "$state_dir"
sequencer.c
+4
@@ -1792,6 +1792,9 @@ static int make_patch(struct commit *commit, struct replay_opts *opts)
1792 p = short_commit_name(commit);
1793 if (write_message(p, strlen(p), rebase_path_stopped_sha(), 1) < 0)
1794 return -1;
1795 + if (update_ref("rebase", "REBASE_HEAD", &commit->object.oid,
1796 + NULL, REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR))
1797 + res |= error(_("could not update %s"), "REBASE_HEAD");
1798
1799 strbuf_addf(&buf, "%s/patch", get_dir(opts));
1800 memset(&log_tree_opt, 0, sizeof(log_tree_opt));
@@ -2043,6 +2046,7 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
2046 unlink(rebase_path_author_script());
2047 unlink(rebase_path_stopped_sha());
2048 unlink(rebase_path_amend());
2049 + delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
2050 }
2051 if (item->command <= TODO_SQUASH) {
2052 if (is_rebase_i(opts))
t/t3400-rebase.sh
+2 -1
@@ -306,7 +306,8 @@ test_expect_success 'rebase--merge.sh and --show-current-patch' '
306 test_must_fail git rebase --merge --onto init HEAD^ &&
307 git rebase --show-current-patch >actual.patch &&
308 GIT_TRACE=1 git rebase --show-current-patch >/dev/null 2>stderr &&
309 - grep "show.*$(git rev-parse two)" stderr
309 + grep "show.*REBASE_HEAD" stderr &&
310 + test "$(git rev-parse REBASE_HEAD)" = "$(git rev-parse two)"
311 )
312 '
313
t/t3404-rebase-interactive.sh
+4 -1
@@ -227,7 +227,10 @@ test_expect_success 'stop on conflicting pick' '
227
228 test_expect_success 'show conflicted patch' '
229 GIT_TRACE=1 git rebase --show-current-patch >/dev/null 2>stderr &&
230 - grep "show.*$(cat "$state_dir/stopped-sha")" stderr
230 + grep "show.*REBASE_HEAD" stderr &&
231 + # the original stopped-sha1 is abbreviated
232 + stopped_sha1="$(git rev-parse $(cat ".git/rebase-merge/stopped-sha"))" &&
233 + test "$(git rev-parse REBASE_HEAD)" = "$stopped_sha1"
234 '
235
236 test_expect_success 'abort' '