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