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/cmt.$msgnum.result" 71echo"$prev_head">"$dotest/prev_head" 72 73# onto the next patch: 74 msgnum=$(($msgnum + 1)) 75echo"$msgnum">"$dotest/msgnum" 76} 77 78call_merge () { 79 cmt="$(cat $dotest/cmt.$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 git-read-tree`cat "$dotest/cmt.$msgnum.result"` 112 git-checkout-index -q -f -u -a 113 git-commit -C"`cat$dotest/cmt.$msgnum`" 114 115printf"Committed %0${prec}d"$msgnum 116echo' '`git-rev-list --pretty=oneline -1 HEAD | \ 117 sed 's/^[a-f0-9]\+ //'` 118 msgnum=$(($msgnum + 1)) 119done 120rm-r"$dotest" 121echo"All done." 122} 123 124while case"$#"in0)break;;esac 125do 126case"$1"in 127--continue) 128diff=$(git-diff-files) 129case"$diff"in 130 ?*)echo"You must edit all merge conflicts and then" 131echo"mark them as resolved using git update-index" 132exit1 133;; 134esac 135iftest -d"$dotest" 136then 137 prev_head="`cat$dotest/prev_head`" 138 end="`cat$dotest/end`" 139 msgnum="`cat$dotest/msgnum`" 140 onto="`cat$dotest/onto`" 141 continue_merge 142whiletest"$msgnum"-le"$end" 143do 144 call_merge "$msgnum" 145 continue_merge 146done 147 finish_rb_merge 148exit 149fi 150 git am --resolved --3way --resolvemsg="$RESOLVEMSG" 151exit 152;; 153--skip) 154iftest -d"$dotest" 155then 156 die "--skip is not supported when using --merge" 157fi 158 git am -3 --skip --resolvemsg="$RESOLVEMSG" 159exit 160;; 161--abort) 162iftest -d"$dotest" 163then 164rm-r"$dotest" 165eliftest -d .dotest 166then 167rm-r .dotest 168else 169 die "No rebase in progress?" 170fi 171 git reset--hard ORIG_HEAD 172exit 173;; 174--onto) 175test2-le"$#"|| usage 176 newbase="$2" 177shift 178;; 179-M|-m|--m|--me|--mer|--merg|--merge) 180 do_merge=t 181;; 182-s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\ 183--strateg=*|--strategy=*|\ 184-s|--s|--st|--str|--stra|--strat|--strate|--strateg|--strategy) 185case"$#,$1"in 186*,*=*) 187 strategy=`expr "$1" : '-[^=]*=\(.*\)'`;; 1881,*) 189 usage ;; 190*) 191 strategy="$2" 192shift;; 193esac 194 do_merge=t 195;; 196-*) 197 usage 198;; 199*) 200break 201;; 202esac 203shift 204done 205 206# Make sure we do not have .dotest 207iftest -z"$do_merge" 208then 209ifmkdir .dotest 210then 211rmdir .dotest 212else 213echo>&2' 214It seems that I cannot create a .dotest directory, and I wonder if you 215are in the middle of patch application or another rebase. If that is not 216the case, please rm -fr .dotest and run me again. I am stopping in case 217you still have something valuable there.' 218exit1 219fi 220else 221iftest -d"$dotest" 222then 223 die "previous dotest directory$doteststill exists." \ 224'try git-rebase < --continue | --abort >' 225fi 226fi 227 228# The tree must be really really clean. 229git-update-index --refresh||exit 230diff=$(git-diff-index --cached --name-status -r HEAD) 231case"$diff"in 232?*)echo"$diff" 233exit1 234;; 235esac 236 237# The upstream head must be given. Make sure it is valid. 238upstream_name="$1" 239upstream=`git rev-parse --verify "${upstream_name}^0"`|| 240 die "invalid upstream$upstream_name" 241 242# If a hook exists, give it a chance to interrupt 243iftest -x"$GIT_DIR/hooks/pre-rebase" 244then 245"$GIT_DIR/hooks/pre-rebase"${1+"$@"}|| { 246echo>&2"The pre-rebase hook refused to rebase." 247exit1 248} 249fi 250 251# If the branch to rebase is given, first switch to it. 252case"$#"in 2532) 254 branch_name="$2" 255 git-checkout"$2"|| usage 256;; 257*) 258 branch_name=`git symbolic-ref HEAD`|| die "No current branch" 259 branch_name=`expr "z$branch_name" : 'zrefs/heads/\(.*\)'` 260;; 261esac 262branch=$(git-rev-parse --verify "${branch_name}^0")||exit 263 264# Make sure the branch to rebase onto is valid. 265onto_name=${newbase-"$upstream_name"} 266onto=$(git-rev-parse --verify "${onto_name}^0")||exit 267 268# Now we are rebasing commits $upstream..$branch on top of $onto 269 270# Check if we are already based on $onto, but this should be 271# done only when upstream and onto are the same. 272iftest"$upstream"="$onto" 273then 274 mb=$(git-merge-base "$onto" "$branch") 275iftest"$mb"="$onto" 276then 277echo>&2"Current branch$branch_nameis up to date." 278exit0 279fi 280fi 281 282# Rewind the head to "$onto"; this saves our current head in ORIG_HEAD. 283git-reset --hard"$onto" 284 285# If the $onto is a proper descendant of the tip of the branch, then 286# we just fast forwarded. 287iftest"$mb"="$onto" 288then 289echo>&2"Fast-forwarded$branchto$newbase." 290exit0 291fi 292 293iftest -z"$do_merge" 294then 295 git-format-patch -k --stdout --full-index"$upstream"..ORIG_HEAD | 296 git am --binary -3 -k --resolvemsg="$RESOLVEMSG" 297exit $? 298fi 299 300iftest"@@NO_PYTHON@@"&&test"$strategy"="recursive" 301then 302 die 'The recursive merge strategy currently relies on Python, 303which this installation of git was not configured with. Please consider 304a different merge strategy (e.g. octopus, resolve, stupid, ours) 305or install Python and git with Python support.' 306 307fi 308 309# start doing a rebase with git-merge 310# this is rename-aware if the recursive (default) strategy is used 311 312mkdir-p"$dotest" 313echo"$onto">"$dotest/onto" 314prev_head=`git-rev-parse HEAD^0` 315echo"$prev_head">"$dotest/prev_head" 316 317msgnum=0 318for cmt in`git-rev-list --no-merges "$upstream"..ORIG_HEAD \ 319 | perl -e 'print reverse <>'` 320do 321 msgnum=$(($msgnum + 1)) 322echo"$cmt">"$dotest/cmt.$msgnum" 323done 324 325echo1>"$dotest/msgnum" 326echo$msgnum>"$dotest/end" 327 328end=$msgnum 329msgnum=1 330 331whiletest"$msgnum"-le"$end" 332do 333 call_merge "$msgnum" 334 continue_merge 335done 336 337finish_rb_merge