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