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

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>

Junio C Hamano committed Mar 15, 2008 at 13:17 UTC 0cb06644a569d92ea8b3b6e81bc8bd786d98920e
1 file changed +32 -20
git-rebase.sh
+32 -20
@@ -309,22 +309,42 @@ then
309 }
310 fi
311
312 -# If the branch to rebase is given, first switch to it.
312 +# If the branch to rebase is given, that is the branch we will rebase
313 +# $branch_name -- branch being rebased, or HEAD (already detached)
314 +# $orig_head -- commit object name of tip of the branch before rebasing
315 +# $head_name -- refs/heads/<that-branch> or "detached HEAD"
316 +switch_to=
317 case "$#" in
318 2)
319 + # Is it "rebase other $branchname" or "rebase other $commit"?
320 branch_name="$2"
316 - git-checkout "$2" || usage
321 + switch_to="$2"
322 +
323 + if git show-ref --verify --quiet -- "refs/heads/$2" &&
324 + branch=$(git rev-parse --verify "refs/heads/$2" 2>/dev/null)
325 + then
326 + head_name="refs/heads/$2"
327 + elif branch=$(git rev-parse --verify "$2" 2>/dev/null)
328 + then
329 + head_name="detached HEAD"
330 + else
331 + usage
332 + fi
333 ;;
334 *)
335 + # Do not need to switch branches, we are already on it.
336 if branch_name=`git symbolic-ref -q HEAD`
337 then
338 + head_name=$branch_name
339 branch_name=`expr "z$branch_name" : 'zrefs/heads/\(.*\)'`
340 else
341 + head_name="detached HEAD"
342 branch_name=HEAD ;# detached
343 fi
344 + branch=$(git rev-parse --verify "${branch_name}^0") || exit
345 ;;
346 esac
327 -branch=$(git rev-parse --verify "${branch_name}^0") || exit
347 +orig_head=$branch
348
349 # Now we are rebasing commits $upstream..$branch on top of $onto
350
@@ -335,6 +355,8 @@ if test "$upstream" = "$onto" && test "$mb" = "$onto" &&
355 # linear history?
356 ! git rev-list --parents "$onto".."$branch" | grep " .* " > /dev/null
357 then
358 + # Lazily switch to the target branch if needed...
359 + test -z "$switch_to" || git checkout "$switch_to"
360 echo >&2 "Current branch $branch_name is up to date."
361 exit 0
362 fi
@@ -346,22 +368,11 @@ then
368 GIT_PAGER='' git diff --stat --summary "$mb" "$onto"
369 fi
370
349 -# move to a detached HEAD
350 -orig_head=$(git rev-parse HEAD^0)
351 -head_name=$(git symbolic-ref HEAD 2> /dev/null)
352 -case "$head_name" in
353 -'')
354 - head_name="detached HEAD"
355 - ;;
356 -*)
357 - git checkout "$orig_head" > /dev/null 2>&1 ||
358 - die "could not detach HEAD"
359 - ;;
360 -esac
361 -
362 -# Rewind the head to "$onto"; this saves our current head in ORIG_HEAD.
371 +# Detach HEAD and reset the tree
372 echo "First, rewinding head to replay your work on top of it..."
364 -git-reset --hard "$onto"
373 +git checkout "$onto^0" >/dev/null 2>&1 ||
374 + die "could not detach HEAD"
375 +# git reset --hard "$onto^0"
376
377 # If the $onto is a proper descendant of the tip of the branch, then
378 # we just fast forwarded.
@@ -374,7 +385,8 @@ fi
385
386 if test -z "$do_merge"
387 then
377 - git format-patch -k --stdout --full-index --ignore-if-in-upstream "$upstream"..ORIG_HEAD |
388 + git format-patch -k --stdout --full-index --ignore-if-in-upstream \
389 + "$upstream..$orig_head" |
390 git am $git_am_opt --rebasing --resolvemsg="$RESOLVEMSG" &&
391 move_to_original_branch
392 ret=$?
@@ -397,7 +409,7 @@ echo "$orig_head" > "$dotest/orig-head"
409 echo "$head_name" > "$dotest/head-name"
410
411 msgnum=0
400 -for cmt in `git rev-list --reverse --no-merges "$upstream"..ORIG_HEAD`
412 +for cmt in `git rev-list --reverse --no-merges "$upstream..$orig_head"`
413 do
414 msgnum=$(($msgnum + 1))
415 echo "$cmt" > "$dotest/cmt.$msgnum"