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