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