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