1#!/bin/sh 2# 3# Copyright (c) 2005 Junio C Hamano. 4# 5 6USAGE='[-v] [--onto <newbase>] <upstream> [<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 .dotest working files, use the command 18git rebase --abort instead. 19 20Note that if <branch> is not specified on the command line, the 21currently checked out branch is used. You must be in the top 22directory of your project to start (or continue) a rebase. 23 24Example: git-rebase master~1 topic 25 26 A---B---C topic A'\''--B'\''--C'\'' topic 27 / --> / 28 D---E---F---G master D---E---F---G master 29' 30 31SUBDIRECTORY_OK=Yes 32. git-sh-setup 33set_reflog_action rebase 34require_work_tree 35cd_to_toplevel 36 37RESOLVEMSG=" 38When you have resolved this problem run\"git rebase --continue\". 39If you would prefer to skip this patch, instead run\"git rebase --skip\". 40To restore the original branch and stop rebasing run\"git rebase --abort\". 41" 42unset newbase 43strategy=recursive 44do_merge= 45dotest=$GIT_DIR/.dotest-merge 46prec=4 47verbose= 48git_am_opt= 49 50continue_merge () { 51test -n"$prev_head"|| die "prev_head must be defined" 52test -d"$dotest"|| die "$dotestdirectory does not exist" 53 54 unmerged=$(git-ls-files -u) 55iftest -n"$unmerged" 56then 57echo"You still have unmerged paths in your index" 58echo"did you forget update-index?" 59 die "$RESOLVEMSG" 60fi 61 62iftest -n"`git-diff-index HEAD`" 63then 64if! git-commit -C"`cat$dotest/current`" 65then 66echo"Commit failed, please do not call\"git commit\"" 67echo"directly, but instead do one of the following: " 68 die "$RESOLVEMSG" 69fi 70printf"Committed: %0${prec}d"$msgnum 71else 72printf"Already applied: %0${prec}d"$msgnum 73fi 74echo' '`git-rev-list --pretty=oneline -1 HEAD | \ 75 sed 's/^[a-f0-9]\+ //'` 76 77 prev_head=`git-rev-parse HEAD^0` 78# save the resulting commit so we can read-tree on it later 79echo"$prev_head">"$dotest/prev_head" 80 81# onto the next patch: 82 msgnum=$(($msgnum + 1)) 83echo"$msgnum">"$dotest/msgnum" 84} 85 86call_merge () { 87 cmt="$(cat $dotest/cmt.$1)" 88echo"$cmt">"$dotest/current" 89 hd=$(git-rev-parse --verify HEAD) 90 cmt_name=$(git-symbolic-ref HEAD) 91 msgnum=$(cat $dotest/msgnum) 92 end=$(cat $dotest/end) 93eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"' 94eval GITHEAD_$hd='"$(cat $dotest/onto_name)"' 95export GITHEAD_$cmt GITHEAD_$hd 96 git-merge-$strategy"$cmt^"--"$hd""$cmt" 97 rv=$? 98case"$rv"in 990) 100unset GITHEAD_$cmt GITHEAD_$hd 101return 102;; 1031) 104test -d"$GIT_DIR/rr-cache"&& git-rerere 105 die "$RESOLVEMSG" 106;; 1072) 108echo"Strategy:$rv$strategyfailed, try another"1>&2 109 die "$RESOLVEMSG" 110;; 111*) 112 die "Unknown exit code ($rv) from command:" \ 113"git-merge-$strategy$cmt^ -- HEAD$cmt" 114;; 115esac 116} 117 118finish_rb_merge () { 119rm-r"$dotest" 120echo"All done." 121} 122 123while case"$#"in0)break;;esac 124do 125case"$1"in 126--continue) 127diff=$(git-diff-files) 128case"$diff"in 129 ?*)echo"You must edit all merge conflicts and then" 130echo"mark them as resolved using git update-index" 131exit1 132;; 133esac 134iftest -d"$dotest" 135then 136 prev_head="`cat$dotest/prev_head`" 137 end="`cat$dotest/end`" 138 msgnum="`cat$dotest/msgnum`" 139 onto="`cat$dotest/onto`" 140 continue_merge 141whiletest"$msgnum"-le"$end" 142do 143 call_merge "$msgnum" 144 continue_merge 145done 146 finish_rb_merge 147exit 148fi 149 git am --resolved --3way --resolvemsg="$RESOLVEMSG" 150exit 151;; 152--skip) 153iftest -d"$dotest" 154then 155iftest -d"$GIT_DIR/rr-cache" 156then 157 git-rerereclear 158fi 159 prev_head="`cat$dotest/prev_head`" 160 end="`cat$dotest/end`" 161 msgnum="`cat$dotest/msgnum`" 162 msgnum=$(($msgnum + 1)) 163 onto="`cat$dotest/onto`" 164whiletest"$msgnum"-le"$end" 165do 166 call_merge "$msgnum" 167 continue_merge 168done 169 finish_rb_merge 170exit 171fi 172 git am -3 --skip --resolvemsg="$RESOLVEMSG" 173exit 174;; 175--abort) 176iftest -d"$GIT_DIR/rr-cache" 177then 178 git-rerereclear 179fi 180iftest -d"$dotest" 181then 182rm-r"$dotest" 183eliftest -d .dotest 184then 185rm-r .dotest 186else 187 die "No rebase in progress?" 188fi 189 git reset--hard ORIG_HEAD 190exit 191;; 192--onto) 193test2-le"$#"|| usage 194 newbase="$2" 195shift 196;; 197-M|-m|--m|--me|--mer|--merg|--merge) 198 do_merge=t 199;; 200-s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\ 201--strateg=*|--strategy=*|\ 202-s|--s|--st|--str|--stra|--strat|--strate|--strateg|--strategy) 203case"$#,$1"in 204*,*=*) 205 strategy=`expr "z$1" : 'z-[^=]*=\(.*\)'`;; 2061,*) 207 usage ;; 208*) 209 strategy="$2" 210shift;; 211esac 212 do_merge=t 213;; 214-v|--verbose) 215 verbose=t 216;; 217-C*) 218 git_am_opt=$1 219shift 220;; 221-*) 222 usage 223;; 224*) 225break 226;; 227esac 228shift 229done 230 231# Make sure we do not have .dotest 232iftest -z"$do_merge" 233then 234ifmkdir .dotest 235then 236rmdir .dotest 237else 238echo>&2' 239It seems that I cannot create a .dotest directory, and I wonder if you 240are in the middle of patch application or another rebase. If that is not 241the case, please rm -fr .dotest and run me again. I am stopping in case 242you still have something valuable there.' 243exit1 244fi 245else 246iftest -d"$dotest" 247then 248 die "previous dotest directory$doteststill exists." \ 249'try git-rebase < --continue | --abort >' 250fi 251fi 252 253# The tree must be really really clean. 254git-update-index --refresh||exit 255diff=$(git-diff-index --cached --name-status -r HEAD) 256case"$diff"in 257?*)echo"cannot rebase: your index is not up-to-date" 258echo"$diff" 259exit1 260;; 261esac 262 263# The upstream head must be given. Make sure it is valid. 264upstream_name="$1" 265upstream=`git rev-parse --verify "${upstream_name}^0"`|| 266 die "invalid upstream$upstream_name" 267 268# If a hook exists, give it a chance to interrupt 269iftest -x"$GIT_DIR/hooks/pre-rebase" 270then 271"$GIT_DIR/hooks/pre-rebase"${1+"$@"}|| { 272echo>&2"The pre-rebase hook refused to rebase." 273exit1 274} 275fi 276 277# If the branch to rebase is given, first switch to it. 278case"$#"in 2792) 280 branch_name="$2" 281 git-checkout"$2"|| usage 282;; 283*) 284if branch_name=`git symbolic-ref -q HEAD` 285then 286 branch_name=`expr "z$branch_name" : 'zrefs/heads/\(.*\)'` 287else 288 branch_name=HEAD ;# detached 289fi 290;; 291esac 292branch=$(git-rev-parse --verify "${branch_name}^0")||exit 293 294# Make sure the branch to rebase onto is valid. 295onto_name=${newbase-"$upstream_name"} 296onto=$(git-rev-parse --verify "${onto_name}^0")||exit 297 298# Now we are rebasing commits $upstream..$branch on top of $onto 299 300# Check if we are already based on $onto, but this should be 301# done only when upstream and onto are the same. 302mb=$(git-merge-base "$onto" "$branch") 303iftest"$upstream"="$onto"&&test"$mb"="$onto" 304then 305echo>&2"Current branch$branch_nameis up to date." 306exit0 307fi 308 309iftest -n"$verbose" 310then 311echo"Changes from$mbto$onto:" 312 git-diff-tree --stat --summary"$mb""$onto" 313fi 314 315# Rewind the head to "$onto"; this saves our current head in ORIG_HEAD. 316echo"First, rewinding head to replay your work on top of it..." 317git-reset --hard"$onto" 318 319# If the $onto is a proper descendant of the tip of the branch, then 320# we just fast forwarded. 321iftest"$mb"="$branch" 322then 323echo>&2"Fast-forwarded$branch_nameto$onto_name." 324exit0 325fi 326 327iftest -z"$do_merge" 328then 329 git-format-patch -k --stdout --full-index --ignore-if-in-upstream"$upstream"..ORIG_HEAD | 330 git am $git_am_opt--binary -3 -k --resolvemsg="$RESOLVEMSG" 331exit $? 332fi 333 334# start doing a rebase with git-merge 335# this is rename-aware if the recursive (default) strategy is used 336 337mkdir-p"$dotest" 338echo"$onto">"$dotest/onto" 339echo"$onto_name">"$dotest/onto_name" 340prev_head=`git-rev-parse HEAD^0` 341echo"$prev_head">"$dotest/prev_head" 342 343msgnum=0 344for cmt in`git-rev-list --no-merges "$upstream"..ORIG_HEAD \ 345 | @@PERL@@ -e 'print reverse <>'` 346do 347 msgnum=$(($msgnum + 1)) 348echo"$cmt">"$dotest/cmt.$msgnum" 349done 350 351echo1>"$dotest/msgnum" 352echo$msgnum>"$dotest/end" 353 354end=$msgnum 355msgnum=1 356 357whiletest"$msgnum"-le"$end" 358do 359 call_merge "$msgnum" 360 continue_merge 361done 362 363finish_rb_merge