Browse Source

rebase [--onto O] A B: omit needless checkout

This teaches "git rebase [--onto O] A B" to omit an unnecessary checkout
of branch B before it goes on.

"git-rebase" originally was about rebasing the current branch to somewhere
else, and when the extra parameter to name which branch to rebase was
added, it defined the semantics to the safest but stupid "first switch to
the named branch and then operate exactly the same way as if we were
already on that branch".

But the first thing the real part of "rebase" does is to reset the work
tree and the index to the "onto" commit.  Which means the "rebase that
branch" form switched the work tree to the tip of the branch only to
immediately switch again to another commit.  This was wasteful.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
maint
Junio C Hamano 17 years ago
parent
commit
0cb06644a5
  1. 52
      git-rebase.sh

52
git-rebase.sh

@ -309,22 +309,42 @@ then
} }
fi fi


# If the branch to rebase is given, first switch to it. # If the branch to rebase is given, that is the branch we will rebase
# $branch_name -- branch being rebased, or HEAD (already detached)
# $orig_head -- commit object name of tip of the branch before rebasing
# $head_name -- refs/heads/<that-branch> or "detached HEAD"
switch_to=
case "$#" in case "$#" in
2) 2)
# Is it "rebase other $branchname" or "rebase other $commit"?
branch_name="$2" branch_name="$2"
git-checkout "$2" || usage switch_to="$2"

if git show-ref --verify --quiet -- "refs/heads/$2" &&
branch=$(git rev-parse --verify "refs/heads/$2" 2>/dev/null)
then
head_name="refs/heads/$2"
elif branch=$(git rev-parse --verify "$2" 2>/dev/null)
then
head_name="detached HEAD"
else
usage
fi
;; ;;
*) *)
# Do not need to switch branches, we are already on it.
if branch_name=`git symbolic-ref -q HEAD` if branch_name=`git symbolic-ref -q HEAD`
then then
head_name=$branch_name
branch_name=`expr "z$branch_name" : 'zrefs/heads/\(.*\)'` branch_name=`expr "z$branch_name" : 'zrefs/heads/\(.*\)'`
else else
head_name="detached HEAD"
branch_name=HEAD ;# detached branch_name=HEAD ;# detached
fi fi
branch=$(git rev-parse --verify "${branch_name}^0") || exit
;; ;;
esac esac
branch=$(git rev-parse --verify "${branch_name}^0") || exit orig_head=$branch


# Now we are rebasing commits $upstream..$branch on top of $onto # Now we are rebasing commits $upstream..$branch on top of $onto


@ -335,6 +355,8 @@ if test "$upstream" = "$onto" && test "$mb" = "$onto" &&
# linear history? # linear history?
! git rev-list --parents "$onto".."$branch" | grep " .* " > /dev/null ! git rev-list --parents "$onto".."$branch" | grep " .* " > /dev/null
then then
# Lazily switch to the target branch if needed...
test -z "$switch_to" || git checkout "$switch_to"
echo >&2 "Current branch $branch_name is up to date." echo >&2 "Current branch $branch_name is up to date."
exit 0 exit 0
fi fi
@ -346,22 +368,11 @@ then
GIT_PAGER='' git diff --stat --summary "$mb" "$onto" GIT_PAGER='' git diff --stat --summary "$mb" "$onto"
fi fi


# move to a detached HEAD # Detach HEAD and reset the tree
orig_head=$(git rev-parse HEAD^0)
head_name=$(git symbolic-ref HEAD 2> /dev/null)
case "$head_name" in
'')
head_name="detached HEAD"
;;
*)
git checkout "$orig_head" > /dev/null 2>&1 ||
die "could not detach HEAD"
;;
esac

# Rewind the head to "$onto"; this saves our current head in ORIG_HEAD.
echo "First, rewinding head to replay your work on top of it..." echo "First, rewinding head to replay your work on top of it..."
git-reset --hard "$onto" git checkout "$onto^0" >/dev/null 2>&1 ||
die "could not detach HEAD"
# git reset --hard "$onto^0"


# If the $onto is a proper descendant of the tip of the branch, then # If the $onto is a proper descendant of the tip of the branch, then
# we just fast forwarded. # we just fast forwarded.
@ -374,7 +385,8 @@ fi


if test -z "$do_merge" if test -z "$do_merge"
then then
git format-patch -k --stdout --full-index --ignore-if-in-upstream "$upstream"..ORIG_HEAD | git format-patch -k --stdout --full-index --ignore-if-in-upstream \
"$upstream..$orig_head" |
git am $git_am_opt --rebasing --resolvemsg="$RESOLVEMSG" && git am $git_am_opt --rebasing --resolvemsg="$RESOLVEMSG" &&
move_to_original_branch move_to_original_branch
ret=$? ret=$?
@ -397,7 +409,7 @@ echo "$orig_head" > "$dotest/orig-head"
echo "$head_name" > "$dotest/head-name" echo "$head_name" > "$dotest/head-name"


msgnum=0 msgnum=0
for cmt in `git rev-list --reverse --no-merges "$upstream"..ORIG_HEAD` for cmt in `git rev-list --reverse --no-merges "$upstream..$orig_head"`
do do
msgnum=$(($msgnum + 1)) msgnum=$(($msgnum + 1))
echo "$cmt" > "$dotest/cmt.$msgnum" echo "$cmt" > "$dotest/cmt.$msgnum"

Loading…
Cancel
Save