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