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