1#!/bin/sh 2# 3# Copyright (c) 2005 Junio C Hamano. 4# 5 6USAGE='[--interactive | -i] [-v] [--force-rebase | -f] [--no-ff] [--onto <newbase>] (<upstream>|--root) [<branch>] [--quiet | -q]' 7LONG_USAGE='git-rebase replaces <branch> with a new branch of the 8same name. When the --onto option is provided the new branch starts 9out with a HEAD equal to <newbase>, otherwise it is equal to <upstream> 10It then attempts to create a new commit for each commit from the original 11<branch> that does not exist in the <upstream> branch. 12 13It is possible that a merge failure will prevent this process from being 14completely automatic. You will have to resolve any such merge failure 15and run git rebase --continue. Another option is to bypass the commit 16that caused the merge failure with git rebase --skip. To restore the 17original <branch> and remove the .git/rebase-apply working files, use the 18command git rebase --abort instead. 19 20Note that if <branch> is not specified on the command line, the 21currently checked out branch is used. 22 23Example: git-rebase master~1 topic 24 25 A---B---C topic A'\''--B'\''--C'\'' topic 26 / --> / 27 D---E---F---G master D---E---F---G master 28' 29 30SUBDIRECTORY_OK=Yes 31OPTIONS_SPEC= 32. git-sh-setup 33set_reflog_action rebase 34require_work_tree 35cd_to_toplevel 36 37LF=' 38' 39OK_TO_SKIP_PRE_REBASE= 40RESOLVEMSG=" 41When you have resolved this problem run\"git rebase --continue\". 42If you would prefer to skip this patch, instead run\"git rebase --skip\". 43To restore the original branch and stop rebasing run\"git rebase --abort\". 44" 45unset newbase 46strategy=recursive 47strategy_opts= 48do_merge= 49merge_dir="$GIT_DIR"/rebase-merge 50apply_dir="$GIT_DIR"/rebase-apply 51prec=4 52verbose= 53diffstat= 54test"$(git config --bool rebase.stat)"= true && diffstat=t 55git_am_opt= 56rebase_root= 57force_rebase= 58allow_rerere_autoupdate= 59 60read_state () { 61iftest -d"$merge_dir" 62then 63 state_dir="$merge_dir" 64 onto_name=$(cat "$merge_dir"/onto_name)&& 65 end=$(cat "$merge_dir"/end)&& 66 msgnum=$(cat "$merge_dir"/msgnum) 67else 68 state_dir="$apply_dir" 69fi&& 70 head_name=$(cat "$state_dir"/head-name)&& 71 onto=$(cat "$state_dir"/onto)&& 72 orig_head=$(cat "$state_dir"/orig-head)&& 73 GIT_QUIET=$(cat "$state_dir"/quiet) 74} 75 76continue_merge () { 77test -d"$merge_dir"|| die "$merge_dirdirectory does not exist" 78 79 unmerged=$(git ls-files -u) 80iftest -n"$unmerged" 81then 82echo"You still have unmerged paths in your index" 83echo"did you forget to use git add?" 84 die "$RESOLVEMSG" 85fi 86 87 cmt=`cat "$merge_dir/current"` 88if! git diff-index --quiet --ignore-submodules HEAD -- 89then 90if! git commit --no-verify -C"$cmt" 91then 92echo"Commit failed, please do not call\"git commit\"" 93echo"directly, but instead do one of the following: " 94 die "$RESOLVEMSG" 95fi 96iftest -z"$GIT_QUIET" 97then 98printf"Committed: %0${prec}d "$msgnum 99fi 100echo"$cmt$(git rev-parse HEAD^0)">>"$merge_dir/rewritten" 101else 102iftest -z"$GIT_QUIET" 103then 104printf"Already applied: %0${prec}d "$msgnum 105fi 106fi 107test -z"$GIT_QUIET"&& 108 GIT_PAGER='' git log --format=%s -1"$cmt" 109 110# onto the next patch: 111 msgnum=$(($msgnum + 1)) 112echo"$msgnum">"$merge_dir/msgnum" 113} 114 115call_merge () { 116 cmt="$(cat "$merge_dir/cmt.$1")" 117echo"$cmt">"$merge_dir/current" 118 hd=$(git rev-parse --verify HEAD) 119 cmt_name=$(git symbolic-ref HEAD 2> /dev/null || echo HEAD) 120 msgnum=$(cat "$merge_dir/msgnum") 121eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"' 122eval GITHEAD_$hd='$onto_name' 123export GITHEAD_$cmt GITHEAD_$hd 124iftest -n"$GIT_QUIET" 125then 126 GIT_MERGE_VERBOSITY=1&&export GIT_MERGE_VERBOSITY 127fi 128eval'git-merge-$strategy'$strategy_opts'"$cmt^" -- "$hd" "$cmt"' 129 rv=$? 130case"$rv"in 1310) 132unset GITHEAD_$cmt GITHEAD_$hd 133return 134;; 1351) 136 git rerere $allow_rerere_autoupdate 137 die "$RESOLVEMSG" 138;; 1392) 140echo"Strategy:$rv$strategyfailed, try another"1>&2 141 die "$RESOLVEMSG" 142;; 143*) 144 die "Unknown exit code ($rv) from command:" \ 145"git-merge-$strategy$cmt^ -- HEAD$cmt" 146;; 147esac 148} 149 150move_to_original_branch () { 151case"$head_name"in 152 refs/*) 153 message="rebase finished:$head_nameonto$onto" 154 git update-ref -m"$message" \ 155$head_name $(git rev-parse HEAD) $orig_head&& 156 git symbolic-ref HEAD $head_name|| 157 die "Could not move back to$head_name" 158;; 159esac 160} 161 162finish_rb_merge () { 163 move_to_original_branch 164 git notes copy --for-rewrite=rebase <"$merge_dir"/rewritten 165iftest -x"$GIT_DIR"/hooks/post-rewrite&& 166test -s"$merge_dir"/rewritten;then 167"$GIT_DIR"/hooks/post-rewrite rebase <"$merge_dir"/rewritten 168fi 169rm-r"$merge_dir" 170 say All done. 171} 172 173is_interactive () { 174whiletest$#!=0 175do 176case"$1"in 177-i|--interactive) 178 interactive_rebase=explicit 179break 180;; 181-p|--preserve-merges) 182 interactive_rebase=implied 183;; 184esac 185shift 186done 187 188if["$interactive_rebase"= implied ];then 189 GIT_EDITOR=: 190export GIT_EDITOR 191fi 192 193test -n"$interactive_rebase"||test -f"$merge_dir"/interactive 194} 195 196run_pre_rebase_hook () { 197iftest -z"$OK_TO_SKIP_PRE_REBASE"&& 198test -x"$GIT_DIR/hooks/pre-rebase" 199then 200"$GIT_DIR/hooks/pre-rebase"${1+"$@"}|| 201 die "The pre-rebase hook refused to rebase." 202fi 203} 204 205test -f"$apply_dir"/applying && 206 die 'It looks like git-am is in progress. Cannot rebase.' 207 208is_interactive "$@"&&exec git-rebase--interactive"$@" 209 210whiletest$#!=0 211do 212case"$1"in 213--no-verify) 214 OK_TO_SKIP_PRE_REBASE=yes 215;; 216--verify) 217 OK_TO_SKIP_PRE_REBASE= 218;; 219--continue) 220test -d"$merge_dir"-o -d"$apply_dir"|| 221 die "No rebase in progress?" 222 223 git update-index --ignore-submodules --refresh&& 224 git diff-files --quiet --ignore-submodules|| { 225echo"You must edit all merge conflicts and then" 226echo"mark them as resolved using git add" 227exit1 228} 229 read_state 230iftest -d"$merge_dir" 231then 232 continue_merge 233whiletest"$msgnum"-le"$end" 234do 235 call_merge "$msgnum" 236 continue_merge 237done 238 finish_rb_merge 239exit 240fi 241 git am --resolved --3way --resolvemsg="$RESOLVEMSG"&& 242 move_to_original_branch 243exit 244;; 245--skip) 246test -d"$merge_dir"-o -d"$apply_dir"|| 247 die "No rebase in progress?" 248 249 git reset--hard HEAD ||exit $? 250 read_state 251iftest -d"$merge_dir" 252then 253 git rerere clear 254 msgnum=$(($msgnum + 1)) 255whiletest"$msgnum"-le"$end" 256do 257 call_merge "$msgnum" 258 continue_merge 259done 260 finish_rb_merge 261exit 262fi 263 git am -3 --skip --resolvemsg="$RESOLVEMSG"&& 264 move_to_original_branch 265exit 266;; 267--abort) 268test -d"$merge_dir"-o -d"$apply_dir"|| 269 die "No rebase in progress?" 270 271 git rerere clear 272 read_state 273case"$head_name"in 274 refs/*) 275 git symbolic-ref HEAD $head_name|| 276 die "Could not move back to$head_name" 277;; 278esac 279 git reset--hard$orig_head 280rm-r"$state_dir" 281exit 282;; 283--onto) 284test2-le"$#"|| usage 285 newbase="$2" 286shift 287;; 288-M|-m|--m|--me|--mer|--merg|--merge) 289 do_merge=t 290;; 291-X*|--strategy-option*) 292case"$#,$1"in 2931,-X|1,--strategy-option) 294 usage ;; 295*,-X|*,--strategy-option) 296 newopt="$2" 297shift;; 298*,--strategy-option=*) 299 newopt="$(expr " $1" : ' --strategy-option=\(.*\)')";; 300*,-X*) 301 newopt="$(expr " $1" : ' -X\(.*\)')";; 3021,*) 303 usage ;; 304esac 305 strategy_opts="$strategy_opts$(git rev-parse --sq-quote "--$newopt")" 306 do_merge=t 307;; 308-s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\ 309--strateg=*|--strategy=*|\ 310-s|--s|--st|--str|--stra|--strat|--strate|--strateg|--strategy) 311case"$#,$1"in 312*,*=*) 313 strategy=`expr "z$1" : 'z-[^=]*=\(.*\)'`;; 3141,*) 315 usage ;; 316*) 317 strategy="$2" 318shift;; 319esac 320 do_merge=t 321;; 322-n|--no-stat) 323 diffstat= 324;; 325--stat) 326 diffstat=t 327;; 328-v|--verbose) 329 verbose=t 330 diffstat=t 331 GIT_QUIET= 332;; 333-q|--quiet) 334 GIT_QUIET=t 335 git_am_opt="$git_am_opt-q" 336 verbose= 337 diffstat= 338;; 339--whitespace=*) 340 git_am_opt="$git_am_opt$1" 341case"$1"in 342--whitespace=fix|--whitespace=strip) 343 force_rebase=t 344;; 345esac 346;; 347--ignore-whitespace) 348 git_am_opt="$git_am_opt$1" 349;; 350--committer-date-is-author-date|--ignore-date) 351 git_am_opt="$git_am_opt$1" 352 force_rebase=t 353;; 354-C*) 355 git_am_opt="$git_am_opt$1" 356;; 357--root) 358 rebase_root=t 359;; 360-f|--f|--fo|--for|--forc|--force|--force-r|--force-re|--force-reb|--force-reba|--force-rebas|--force-rebase|--no-ff) 361 force_rebase=t 362;; 363--rerere-autoupdate|--no-rerere-autoupdate) 364 allow_rerere_autoupdate="$1" 365;; 366-*) 367 usage 368;; 369*) 370break 371;; 372esac 373shift 374done 375test$#-gt2&& usage 376 377iftest$#-eq0&&test -z"$rebase_root" 378then 379test -d"$merge_dir"-o -d"$apply_dir"|| usage 380test -d"$merge_dir"-o -f"$apply_dir"/rebasing && 381 die 'A rebase is in progress, try --continue, --skip or --abort.' 382fi 383 384# Make sure we do not have $apply_dir or $merge_dir 385iftest -z"$do_merge" 386then 387ifmkdir"$apply_dir"2>/dev/null 388then 389rmdir"$apply_dir" 390else 391echo>&2' 392It seems that I cannot create a rebase-apply directory, and 393I wonder if you are in the middle of patch application or another 394rebase. If that is not the case, please 395 rm -fr '"$apply_dir"' 396and run me again. I am stopping in case you still have something 397valuable there.' 398exit1 399fi 400else 401iftest -d"$merge_dir" 402then 403 die "previous rebase directory$merge_dirstill exists." \ 404'Try git rebase (--continue | --abort | --skip)' 405fi 406fi 407 408require_clean_work_tree "rebase""Please commit or stash them." 409 410iftest -z"$rebase_root" 411then 412# The upstream head must be given. Make sure it is valid. 413 upstream_name="$1" 414shift 415 upstream=`git rev-parse --verify "${upstream_name}^0"`|| 416 die "invalid upstream$upstream_name" 417unset root_flag 418 upstream_arg="$upstream_name" 419else 420test -z"$newbase"&& die "--root must be used with --onto" 421unset upstream_name 422unset upstream 423 root_flag="--root" 424 upstream_arg="$root_flag" 425fi 426 427# Make sure the branch to rebase onto is valid. 428onto_name=${newbase-"$upstream_name"} 429case"$onto_name"in 430*...*) 431if left=${onto_name%...*} right=${onto_name#*...}&& 432 onto=$(git merge-base --all ${left:-HEAD} ${right:-HEAD}) 433then 434case"$onto"in 435 ?*"$LF"?*) 436 die "$onto_name: there are more than one merge bases" 437;; 438'') 439 die "$onto_name: there is no merge base" 440;; 441esac 442else 443 die "$onto_name: there is no merge base" 444fi 445;; 446*) 447 onto=$(git rev-parse --verify "${onto_name}^0")||exit 448;; 449esac 450 451# If a hook exists, give it a chance to interrupt 452run_pre_rebase_hook "$upstream_arg""$@" 453 454# If the branch to rebase is given, that is the branch we will rebase 455# $branch_name -- branch being rebased, or HEAD (already detached) 456# $orig_head -- commit object name of tip of the branch before rebasing 457# $head_name -- refs/heads/<that-branch> or "detached HEAD" 458switch_to= 459case"$#"in 4601) 461# Is it "rebase other $branchname" or "rebase other $commit"? 462 branch_name="$1" 463 switch_to="$1" 464 465if git show-ref --verify --quiet --"refs/heads/$1"&& 466 branch=$(git rev-parse -q --verify "refs/heads/$1") 467then 468 head_name="refs/heads/$1" 469elif branch=$(git rev-parse -q --verify "$1") 470then 471 head_name="detached HEAD" 472else 473echo>&2"fatal: no such branch:$1" 474 usage 475fi 476;; 477*) 478# Do not need to switch branches, we are already on it. 479if branch_name=`git symbolic-ref -q HEAD` 480then 481 head_name=$branch_name 482 branch_name=`expr "z$branch_name" : 'zrefs/heads/\(.*\)'` 483else 484 head_name="detached HEAD" 485 branch_name=HEAD ;# detached 486fi 487 branch=$(git rev-parse --verify "${branch_name}^0")||exit 488;; 489esac 490orig_head=$branch 491 492# Now we are rebasing commits $upstream..$branch (or with --root, 493# everything leading up to $branch) on top of $onto 494 495# Check if we are already based on $onto with linear history, 496# but this should be done only when upstream and onto are the same. 497mb=$(git merge-base "$onto" "$branch") 498iftest"$upstream"="$onto"&&test"$mb"="$onto"&& 499# linear history? 500! (git rev-list --parents"$onto".."$branch"| sane_grep " .* ") > /dev/null 501then 502iftest -z"$force_rebase" 503then 504# Lazily switch to the target branch if needed... 505test -z"$switch_to"|| git checkout "$switch_to"-- 506 say "Current branch$branch_nameis up to date." 507exit0 508else 509 say "Current branch$branch_nameis up to date, rebase forced." 510fi 511fi 512 513# Detach HEAD and reset the tree 514say "First, rewinding head to replay your work on top of it..." 515git checkout -q"$onto^0"|| die "could not detach HEAD" 516git update-ref ORIG_HEAD $branch 517 518iftest -n"$diffstat" 519then 520iftest -n"$verbose" 521then 522echo"Changes from$mbto$onto:" 523fi 524# We want color (if set), but no pager 525 GIT_PAGER='' git diff--stat --summary"$mb""$onto" 526fi 527 528# If the $onto is a proper descendant of the tip of the branch, then 529# we just fast-forwarded. 530iftest"$mb"="$branch" 531then 532 say "Fast-forwarded$branch_nameto$onto_name." 533 move_to_original_branch 534exit0 535fi 536 537iftest -n"$rebase_root" 538then 539 revisions="$onto..$orig_head" 540else 541 revisions="$upstream..$orig_head" 542fi 543 544iftest -z"$do_merge" 545then 546 git format-patch -k --stdout --full-index --ignore-if-in-upstream \ 547--src-prefix=a/--dst-prefix=b/ \ 548--no-renames$root_flag"$revisions"| 549 git am $git_am_opt--rebasing --resolvemsg="$RESOLVEMSG"&& 550 move_to_original_branch 551 ret=$? 552test0!=$ret-a -d"$apply_dir"&& 553echo$head_name>"$apply_dir/head-name"&& 554echo$onto>"$apply_dir/onto"&& 555echo$orig_head>"$apply_dir/orig-head"&& 556echo"$GIT_QUIET">"$apply_dir/quiet" 557exit$ret 558fi 559 560# start doing a rebase with git-merge 561# this is rename-aware if the recursive (default) strategy is used 562 563mkdir-p"$merge_dir" 564echo"$onto_name">"$merge_dir/onto_name" 565echo"$head_name">"$merge_dir/head-name" 566echo"$onto">"$merge_dir/onto" 567echo"$orig_head">"$merge_dir/orig-head" 568echo"$GIT_QUIET">"$merge_dir/quiet" 569 570msgnum=0 571for cmt in`git rev-list --reverse --no-merges "$revisions"` 572do 573 msgnum=$(($msgnum + 1)) 574echo"$cmt">"$merge_dir/cmt.$msgnum" 575done 576 577echo1>"$merge_dir/msgnum" 578echo$msgnum>"$merge_dir/end" 579 580end=$msgnum 581msgnum=1 582 583whiletest"$msgnum"-le"$end" 584do 585 call_merge "$msgnum" 586 continue_merge 587done 588 589finish_rb_merge