rebase: introduce and use pseudo-ref REBASE_HEAD
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>
Sun, 11 Feb 2018 09:43:28 +0000 (16:43 +0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 12 Feb 2018 22:07:59 +0000 (14:07 -0800)
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>
Documentation/git-rebase.txt
builtin/am.c
contrib/completion/git-completion.bash
git-rebase--interactive.sh
git-rebase--merge.sh
git-rebase.sh
sequencer.c
t/t3400-rebase.sh
t/t3404-rebase-interactive.sh
index 7ef95774726ddaefeede9474e8c66e27b98ddaa6..0b29e48221696ac41641bccd12c215a2a332a597 100644 (file)
@@ -252,7 +252,8 @@ leave out at most one of A and B, in which case it defaults to HEAD.
 
 --show-current-patch::
        Show the current patch in an interactive rebase or when rebase
-       is stopped because of conflicts.
+       is stopped because of conflicts. This is the equivalent of
+       `git show REBASE_HEAD`.
 
 -m::
 --merge::
index 37219fceb0a77a245c909a714c704a6b698852b5..21aedec41f0aa742af2b611fe059a59ff1c21621 100644 (file)
@@ -1011,6 +1011,7 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
 
        if (mkdir(state->dir, 0777) < 0 && errno != EEXIST)
                die_errno(_("failed to create directory '%s'"), state->dir);
+       delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
 
        if (split_mail(state, patch_format, paths, keep_cr) < 0) {
                am_destroy(state);
@@ -1110,6 +1111,7 @@ static void am_next(struct am_state *state)
 
        oidclr(&state->orig_commit);
        unlink(am_path(state, "original-commit"));
+       delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
 
        if (!get_oid("HEAD", &head))
                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)
 
        oidcpy(&state->orig_commit, &commit_oid);
        write_state_text(state, "original-commit", oid_to_hex(&commit_oid));
+       update_ref("am", "REBASE_HEAD", &commit_oid,
+                  NULL, REF_NO_DEREF, UPDATE_REFS_DIE_ON_ERR);
 
        return 0;
 }
index 2bd30d68cfc04b7b03965bbd6e3f833f7613f9dc..8777805c9fd64f5513462540b20464bfdaf9ca24 100644 (file)
@@ -439,7 +439,7 @@ __git_refs ()
                        track=""
                        ;;
                *)
-                       for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD; do
+                       for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD REBASE_HEAD; do
                                case "$i" in
                                $match*)
                                        if [ -e "$dir/$i" ]; then
index 0c0f8abbf9e569c8f074b98242cecfb56d45c046..a613156bcb65170d617c11f4dfe8a341c006108f 100644 (file)
@@ -199,12 +199,14 @@ make_patch () {
 
 die_with_patch () {
        echo "$1" > "$state_dir"/stopped-sha
+       git update-ref REBASE_HEAD "$1"
        make_patch "$1"
        die "$2"
 }
 
 exit_with_patch () {
        echo "$1" > "$state_dir"/stopped-sha
+       git update-ref REBASE_HEAD "$1"
        make_patch $1
        git rev-parse --verify HEAD > "$amend"
        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:
        exit
        ;;
 show-current-patch)
-       exec git show "$(cat "$state_dir/stopped-sha")" --
+       exec git show REBASE_HEAD --
        ;;
 esac
 
@@ -858,6 +860,7 @@ fi
 
 orig_head=$(git rev-parse --verify HEAD) || die "$(gettext "No HEAD?")"
 mkdir -p "$state_dir" || die "$(eval_gettext "Could not create temporary \$state_dir")"
+rm -f "$(git rev-parse --git-path REBASE_HEAD)"
 
 : > "$state_dir"/interactive || die "$(gettext "Could not mark as interactive")"
 write_basic_state
index 0a96dfae37126b90fdf518da01933ff68b82da7c..957688f236a6bc06622912ccbe48bd06ae3bc5df 100644 (file)
@@ -57,6 +57,7 @@ call_merge () {
        echo "$msgnum" >"$state_dir/msgnum"
        cmt="$(cat "$state_dir/cmt.$msgnum")"
        echo "$cmt" > "$state_dir/current"
+       git update-ref REBASE_HEAD "$cmt"
        hd=$(git rev-parse --verify HEAD)
        cmt_name=$(git symbolic-ref HEAD 2> /dev/null || echo HEAD)
        eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"'
@@ -138,13 +139,14 @@ skip)
        return
        ;;
 show-current-patch)
-       exec git show "$(cat "$state_dir/current")" --
+       exec git show REBASE_HEAD --
        ;;
 esac
 
 mkdir -p "$state_dir"
 echo "$onto_name" > "$state_dir/onto_name"
 write_basic_state
+rm -f "$(git rev-parse --git-path REBASE_HEAD)"
 
 msgnum=0
 for cmt in $(git rev-list --reverse --no-merges "$revisions")
index 41c915d18c2c4e160b4208dfc859f28ee54eb090..a13a581fe65438dcada8ff05226a808b71fed2ad 100755 (executable)
@@ -182,6 +182,7 @@ You can run "git stash pop" or "git stash drop" at any time.
 }
 
 finish_rebase () {
+       rm -f "$(git rev-parse --git-path REBASE_HEAD)"
        apply_autostash &&
        { git gc --auto || true; } &&
        rm -rf "$state_dir"
index 4d3f60594cbf0e9ddf2ea78e8c58eca312b4cac0..f69222199929399b37ce240e464282bb5e330b6c 100644 (file)
@@ -1792,6 +1792,9 @@ static int make_patch(struct commit *commit, struct replay_opts *opts)
        p = short_commit_name(commit);
        if (write_message(p, strlen(p), rebase_path_stopped_sha(), 1) < 0)
                return -1;
+       if (update_ref("rebase", "REBASE_HEAD", &commit->object.oid,
+                      NULL, REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR))
+               res |= error(_("could not update %s"), "REBASE_HEAD");
 
        strbuf_addf(&buf, "%s/patch", get_dir(opts));
        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)
                        unlink(rebase_path_author_script());
                        unlink(rebase_path_stopped_sha());
                        unlink(rebase_path_amend());
+                       delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
                }
                if (item->command <= TODO_SQUASH) {
                        if (is_rebase_i(opts))
index 09943d6a9bb4580bbdd8f892380fdeaa0d8972da..72d9564747adf2d37ea2e61a6d2e479096fe6508 100755 (executable)
@@ -306,7 +306,8 @@ test_expect_success 'rebase--merge.sh and --show-current-patch' '
                test_must_fail git rebase --merge --onto init HEAD^ &&
                git rebase --show-current-patch >actual.patch &&
                GIT_TRACE=1 git rebase --show-current-patch >/dev/null 2>stderr &&
-               grep "show.*$(git rev-parse two)" stderr
+               grep "show.*REBASE_HEAD" stderr &&
+               test "$(git rev-parse REBASE_HEAD)" = "$(git rev-parse two)"
        )
 '
 
index 3af6f149a96a55426473974b2e4281c76be46f15..23a54a4c497d9a70f3234fd24ba2403a05dc5f6e 100755 (executable)
@@ -227,7 +227,10 @@ test_expect_success 'stop on conflicting pick' '
 
 test_expect_success 'show conflicted patch' '
        GIT_TRACE=1 git rebase --show-current-patch >/dev/null 2>stderr &&
-       grep "show.*$(cat "$state_dir/stopped-sha")" stderr
+       grep "show.*REBASE_HEAD" stderr &&
+       # the original stopped-sha1 is abbreviated
+       stopped_sha1="$(git rev-parse $(cat ".git/rebase-merge/stopped-sha"))" &&
+       test "$(git rev-parse REBASE_HEAD)" = "$stopped_sha1"
 '
 
 test_expect_success 'abort' '