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