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