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 303# start doing a rebase with git-merge 304# this is rename-aware if the recursive (default) strategy is used 305 306mkdir-p"$dotest" 307echo"$onto">"$dotest/onto" 308prev_head=`git-rev-parse HEAD^0` 309echo"$prev_head">"$dotest/prev_head" 310 311msgnum=0 312for cmt in`git-rev-list --no-merges "$upstream"..ORIG_HEAD \ 313 | perl -e 'print reverse <>'` 314do 315 msgnum=$(($msgnum + 1)) 316echo"$cmt">"$dotest/`printf "%0${prec}d"$msgnum`" 317done 318 319printf"%0${prec}d"1>"$dotest/msgnum" 320printf"%0${prec}d""$msgnum">"$dotest/end" 321 322end=$msgnum 323msgnum=1 324 325whiletest"$msgnum"-le"$end" 326do 327 call_merge "$msgnum" 328 continue_merge 329done 330 331finish_rb_merge