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