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