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