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