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