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