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