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