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>
This commit is contained in:
Nguyễn Thái Ngọc Duy 2018-02-11 16:43:28 +07:00 коммит произвёл Junio C Hamano
Родитель 66335298a4
Коммит fbd7a23237
9 изменённых файлов: 25 добавлений и 6 удалений

Просмотреть файл

@ -252,7 +252,8 @@ leave out at most one of A and B, in which case it defaults to HEAD.
--show-current-patch:: --show-current-patch::
Show the current patch in an interactive rebase or when rebase 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:: -m::
--merge:: --merge::

Просмотреть файл

@ -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) if (mkdir(state->dir, 0777) < 0 && errno != EEXIST)
die_errno(_("failed to create directory '%s'"), state->dir); 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) { if (split_mail(state, patch_format, paths, keep_cr) < 0) {
am_destroy(state); am_destroy(state);
@ -1110,6 +1111,7 @@ static void am_next(struct am_state *state)
oidclr(&state->orig_commit); oidclr(&state->orig_commit);
unlink(am_path(state, "original-commit")); unlink(am_path(state, "original-commit"));
delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
if (!get_oid("HEAD", &head)) if (!get_oid("HEAD", &head))
write_state_text(state, "abort-safety", oid_to_hex(&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); oidcpy(&state->orig_commit, &commit_oid);
write_state_text(state, "original-commit", oid_to_hex(&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; return 0;
} }

Просмотреть файл

@ -439,7 +439,7 @@ __git_refs ()
track="" 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 case "$i" in
$match*) $match*)
if [ -e "$dir/$i" ]; then if [ -e "$dir/$i" ]; then

Просмотреть файл

@ -199,12 +199,14 @@ make_patch () {
die_with_patch () { die_with_patch () {
echo "$1" > "$state_dir"/stopped-sha echo "$1" > "$state_dir"/stopped-sha
git update-ref REBASE_HEAD "$1"
make_patch "$1" make_patch "$1"
die "$2" die "$2"
} }
exit_with_patch () { exit_with_patch () {
echo "$1" > "$state_dir"/stopped-sha echo "$1" > "$state_dir"/stopped-sha
git update-ref REBASE_HEAD "$1"
make_patch $1 make_patch $1
git rev-parse --verify HEAD > "$amend" git rev-parse --verify HEAD > "$amend"
gpg_sign_opt_quoted=${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} 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 exit
;; ;;
show-current-patch) show-current-patch)
exec git show "$(cat "$state_dir/stopped-sha")" -- exec git show REBASE_HEAD --
;; ;;
esac esac
@ -858,6 +860,7 @@ fi
orig_head=$(git rev-parse --verify HEAD) || die "$(gettext "No HEAD?")" orig_head=$(git rev-parse --verify HEAD) || die "$(gettext "No HEAD?")"
mkdir -p "$state_dir" || die "$(eval_gettext "Could not create temporary \$state_dir")" 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")" : > "$state_dir"/interactive || die "$(gettext "Could not mark as interactive")"
write_basic_state write_basic_state

Просмотреть файл

@ -57,6 +57,7 @@ call_merge () {
echo "$msgnum" >"$state_dir/msgnum" echo "$msgnum" >"$state_dir/msgnum"
cmt="$(cat "$state_dir/cmt.$msgnum")" cmt="$(cat "$state_dir/cmt.$msgnum")"
echo "$cmt" > "$state_dir/current" echo "$cmt" > "$state_dir/current"
git update-ref REBASE_HEAD "$cmt"
hd=$(git rev-parse --verify HEAD) hd=$(git rev-parse --verify HEAD)
cmt_name=$(git symbolic-ref HEAD 2> /dev/null || echo HEAD) cmt_name=$(git symbolic-ref HEAD 2> /dev/null || echo HEAD)
eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"' eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"'
@ -138,13 +139,14 @@ skip)
return return
;; ;;
show-current-patch) show-current-patch)
exec git show "$(cat "$state_dir/current")" -- exec git show REBASE_HEAD --
;; ;;
esac esac
mkdir -p "$state_dir" mkdir -p "$state_dir"
echo "$onto_name" > "$state_dir/onto_name" echo "$onto_name" > "$state_dir/onto_name"
write_basic_state write_basic_state
rm -f "$(git rev-parse --git-path REBASE_HEAD)"
msgnum=0 msgnum=0
for cmt in $(git rev-list --reverse --no-merges "$revisions") for cmt in $(git rev-list --reverse --no-merges "$revisions")

Просмотреть файл

@ -182,6 +182,7 @@ You can run "git stash pop" or "git stash drop" at any time.
} }
finish_rebase () { finish_rebase () {
rm -f "$(git rev-parse --git-path REBASE_HEAD)"
apply_autostash && apply_autostash &&
{ git gc --auto || true; } && { git gc --auto || true; } &&
rm -rf "$state_dir" rm -rf "$state_dir"

Просмотреть файл

@ -1792,6 +1792,9 @@ static int make_patch(struct commit *commit, struct replay_opts *opts)
p = short_commit_name(commit); p = short_commit_name(commit);
if (write_message(p, strlen(p), rebase_path_stopped_sha(), 1) < 0) if (write_message(p, strlen(p), rebase_path_stopped_sha(), 1) < 0)
return -1; 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)); strbuf_addf(&buf, "%s/patch", get_dir(opts));
memset(&log_tree_opt, 0, sizeof(log_tree_opt)); 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_author_script());
unlink(rebase_path_stopped_sha()); unlink(rebase_path_stopped_sha());
unlink(rebase_path_amend()); unlink(rebase_path_amend());
delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
} }
if (item->command <= TODO_SQUASH) { if (item->command <= TODO_SQUASH) {
if (is_rebase_i(opts)) if (is_rebase_i(opts))

Просмотреть файл

@ -306,7 +306,8 @@ test_expect_success 'rebase--merge.sh and --show-current-patch' '
test_must_fail git rebase --merge --onto init HEAD^ && test_must_fail git rebase --merge --onto init HEAD^ &&
git rebase --show-current-patch >actual.patch && git rebase --show-current-patch >actual.patch &&
GIT_TRACE=1 git rebase --show-current-patch >/dev/null 2>stderr && 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)"
) )
' '

Просмотреть файл

@ -227,7 +227,10 @@ test_expect_success 'stop on conflicting pick' '
test_expect_success 'show conflicted patch' ' test_expect_success 'show conflicted patch' '
GIT_TRACE=1 git rebase --show-current-patch >/dev/null 2>stderr && 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' ' test_expect_success 'abort' '