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 prev_head="`cat$dotest/prev_head`" 141 end="`cat$dotest/end`" 142 msgnum="`cat$dotest/msgnum`" 143 msgnum=$(($msgnum + 1)) 144 onto="`cat$dotest/onto`" 145whiletest"$msgnum"-le"$end" 146do 147 call_merge "$msgnum" 148 continue_merge 149done 150 finish_rb_merge 151exit 152fi 153 git am -3 --skip --resolvemsg="$RESOLVEMSG" 154exit 155;; 156--abort) 157iftest -d"$dotest" 158then 159rm-r"$dotest" 160eliftest -d .dotest 161then 162rm-r .dotest 163else 164 die "No rebase in progress?" 165fi 166 git reset--hard ORIG_HEAD 167exit 168;; 169--onto) 170test2-le"$#"|| usage 171 newbase="$2" 172shift 173;; 174-M|-m|--m|--me|--mer|--merg|--merge) 175 do_merge=t 176;; 177-s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\ 178--strateg=*|--strategy=*|\ 179-s|--s|--st|--str|--stra|--strat|--strate|--strateg|--strategy) 180case"$#,$1"in 181*,*=*) 182 strategy=`expr "z$1" : 'z-[^=]*=\(.*\)'`;; 1831,*) 184 usage ;; 185*) 186 strategy="$2" 187shift;; 188esac 189 do_merge=t 190;; 191-*) 192 usage 193;; 194*) 195break 196;; 197esac 198shift 199done 200 201# Make sure we do not have .dotest 202iftest -z"$do_merge" 203then 204ifmkdir .dotest 205then 206rmdir .dotest 207else 208echo>&2' 209It seems that I cannot create a .dotest directory, and I wonder if you 210are in the middle of patch application or another rebase. If that is not 211the case, please rm -fr .dotest and run me again. I am stopping in case 212you still have something valuable there.' 213exit1 214fi 215else 216iftest -d"$dotest" 217then 218 die "previous dotest directory$doteststill exists." \ 219'try git-rebase < --continue | --abort >' 220fi 221fi 222 223# The tree must be really really clean. 224git-update-index --refresh||exit 225diff=$(git-diff-index --cached --name-status -r HEAD) 226case"$diff"in 227?*)echo"$diff" 228exit1 229;; 230esac 231 232# The upstream head must be given. Make sure it is valid. 233upstream_name="$1" 234upstream=`git rev-parse --verify "${upstream_name}^0"`|| 235 die "invalid upstream$upstream_name" 236 237# If a hook exists, give it a chance to interrupt 238iftest -x"$GIT_DIR/hooks/pre-rebase" 239then 240"$GIT_DIR/hooks/pre-rebase"${1+"$@"}|| { 241echo>&2"The pre-rebase hook refused to rebase." 242exit1 243} 244fi 245 246# If the branch to rebase is given, first switch to it. 247case"$#"in 2482) 249 branch_name="$2" 250 git-checkout"$2"|| usage 251;; 252*) 253 branch_name=`git symbolic-ref HEAD`|| die "No current branch" 254 branch_name=`expr "z$branch_name" : 'zrefs/heads/\(.*\)'` 255;; 256esac 257branch=$(git-rev-parse --verify "${branch_name}^0")||exit 258 259# Make sure the branch to rebase onto is valid. 260onto_name=${newbase-"$upstream_name"} 261onto=$(git-rev-parse --verify "${onto_name}^0")||exit 262 263# Now we are rebasing commits $upstream..$branch on top of $onto 264 265# Check if we are already based on $onto, but this should be 266# done only when upstream and onto are the same. 267iftest"$upstream"="$onto" 268then 269 mb=$(git-merge-base "$onto" "$branch") 270iftest"$mb"="$onto" 271then 272echo>&2"Current branch$branch_nameis up to date." 273exit0 274fi 275fi 276 277# Rewind the head to "$onto"; this saves our current head in ORIG_HEAD. 278git-reset --hard"$onto" 279 280# If the $onto is a proper descendant of the tip of the branch, then 281# we just fast forwarded. 282iftest"$mb"="$onto" 283then 284echo>&2"Fast-forwarded$branchto$newbase." 285exit0 286fi 287 288iftest -z"$do_merge" 289then 290 git-format-patch -k --stdout --full-index"$upstream"..ORIG_HEAD | 291 git am --binary -3 -k --resolvemsg="$RESOLVEMSG" 292exit $? 293fi 294 295iftest"@@NO_PYTHON@@"&&test"$strategy"="recursive" 296then 297 die 'The recursive merge strategy currently relies on Python, 298which this installation of git was not configured with. Please consider 299a different merge strategy (e.g. octopus, resolve, stupid, ours) 300or install Python and git with Python support.' 301 302fi 303 304# start doing a rebase with git-merge 305# this is rename-aware if the recursive (default) strategy is used 306 307mkdir-p"$dotest" 308echo"$onto">"$dotest/onto" 309prev_head=`git-rev-parse HEAD^0` 310echo"$prev_head">"$dotest/prev_head" 311 312msgnum=0 313for cmt in`git-rev-list --no-merges "$upstream"..ORIG_HEAD \ 314 | perl -e 'print reverse <>'` 315do 316 msgnum=$(($msgnum + 1)) 317echo"$cmt">"$dotest/cmt.$msgnum" 318done 319 320echo1>"$dotest/msgnum" 321echo$msgnum>"$dotest/end" 322 323end=$msgnum 324msgnum=1 325 326whiletest"$msgnum"-le"$end" 327do 328 call_merge "$msgnum" 329 continue_merge 330done 331 332finish_rb_merge