1#!/bin/sh 2# 3# Copyright (c) 2005 Junio C Hamano. 4# 5 6USAGE='[--interactive | -i] [-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 .git/rebase-apply working files, use the 18command git rebase --abort instead. 19 20Note that if <branch> is not specified on the command line, the 21currently checked out branch is used. 22 23Example: git-rebase master~1 topic 24 25 A---B---C topic A'\''--B'\''--C'\'' topic 26 / --> / 27 D---E---F---G master D---E---F---G master 28' 29 30SUBDIRECTORY_OK=Yes 31OPTIONS_SPEC= 32. git-sh-setup 33set_reflog_action rebase 34require_work_tree 35cd_to_toplevel 36 37OK_TO_SKIP_PRE_REBASE= 38RESOLVEMSG=" 39When you have resolved this problem run\"git rebase --continue\". 40If you would prefer to skip this patch, instead run\"git rebase --skip\". 41To restore the original branch and stop rebasing run\"git rebase --abort\". 42" 43unset newbase 44strategy=recursive 45do_merge= 46dotest="$GIT_DIR"/rebase-merge 47prec=4 48verbose= 49git_am_opt= 50 51continue_merge () { 52test -n"$prev_head"|| die "prev_head must be defined" 53test -d"$dotest"|| die "$dotestdirectory does not exist" 54 55 unmerged=$(git ls-files -u) 56iftest -n"$unmerged" 57then 58echo"You still have unmerged paths in your index" 59echo"did you forget to use git add?" 60 die "$RESOLVEMSG" 61fi 62 63 cmt=`cat "$dotest/current"` 64if! git diff-index --quiet --ignore-submodules HEAD -- 65then 66if! git commit --no-verify -C"$cmt" 67then 68echo"Commit failed, please do not call\"git commit\"" 69echo"directly, but instead do one of the following: " 70 die "$RESOLVEMSG" 71fi 72printf"Committed: %0${prec}d "$msgnum 73else 74printf"Already applied: %0${prec}d "$msgnum 75fi 76 git rev-list --pretty=oneline -1"$cmt"|sed-e's/^[^ ]* //' 77 78 prev_head=`git rev-parse HEAD^0` 79# save the resulting commit so we can read-tree on it later 80echo"$prev_head">"$dotest/prev_head" 81 82# onto the next patch: 83 msgnum=$(($msgnum + 1)) 84echo"$msgnum">"$dotest/msgnum" 85} 86 87call_merge () { 88 cmt="$(cat "$dotest/cmt.$1")" 89echo"$cmt">"$dotest/current" 90 hd=$(git rev-parse --verify HEAD) 91 cmt_name=$(git symbolic-ref HEAD 2> /dev/null || echo HEAD) 92 msgnum=$(cat "$dotest/msgnum") 93 end=$(cat "$dotest/end") 94eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"' 95eval GITHEAD_$hd='$(cat "$dotest/onto_name")' 96export GITHEAD_$cmt GITHEAD_$hd 97 git-merge-$strategy"$cmt^"--"$hd""$cmt" 98 rv=$? 99case"$rv"in 1000) 101unset GITHEAD_$cmt GITHEAD_$hd 102return 103;; 1041) 105 git rerere 106 die "$RESOLVEMSG" 107;; 1082) 109echo"Strategy:$rv$strategyfailed, try another"1>&2 110 die "$RESOLVEMSG" 111;; 112*) 113 die "Unknown exit code ($rv) from command:" \ 114"git-merge-$strategy$cmt^ -- HEAD$cmt" 115;; 116esac 117} 118 119move_to_original_branch () { 120test -z"$head_name"&& 121 head_name="$(cat "$dotest"/head-name)"&& 122 onto="$(cat "$dotest"/onto)"&& 123 orig_head="$(cat "$dotest"/orig-head)" 124case"$head_name"in 125 refs/*) 126 message="rebase finished:$head_nameonto$onto" 127 git update-ref -m"$message" \ 128$head_name $(git rev-parse HEAD) $orig_head&& 129 git symbolic-ref HEAD $head_name|| 130 die "Could not move back to$head_name" 131;; 132esac 133} 134 135finish_rb_merge () { 136 move_to_original_branch 137rm-r"$dotest" 138echo"All done." 139} 140 141is_interactive () { 142whiletest$#!=0 143do 144case"$1"in 145-i|--interactive) 146 interactive_rebase=explicit 147break 148;; 149-p|--preserve-merges) 150 interactive_rebase=implied 151;; 152esac 153shift 154done 155 156if["$interactive_rebase"= implied ];then 157 GIT_EDITOR=: 158export GIT_EDITOR 159fi 160 161test -n"$interactive_rebase"||test -f"$dotest"/interactive 162} 163 164run_pre_rebase_hook () { 165iftest -z"$OK_TO_SKIP_PRE_REBASE"&& 166test -x"$GIT_DIR/hooks/pre-rebase" 167then 168"$GIT_DIR/hooks/pre-rebase"${1+"$@"}|| { 169echo>&2"The pre-rebase hook refused to rebase." 170exit1 171} 172fi 173} 174 175test -f"$GIT_DIR"/rebase-apply/applying && 176 die 'It looks like git-am is in progress. Cannot rebase.' 177 178is_interactive "$@"&&exec git-rebase--interactive"$@" 179 180iftest$#-eq0 181then 182test -d"$dotest"-o -d"$GIT_DIR"/rebase-apply|| usage 183test -d"$dotest"-o -f"$GIT_DIR"/rebase-apply/rebasing && 184 die 'A rebase is in progress, try --continue, --skip or --abort.' 185 die "No arguments given and$GIT_DIR/rebase-apply already exists." 186fi 187 188whiletest$#!=0 189do 190case"$1"in 191--no-verify) 192 OK_TO_SKIP_PRE_REBASE=yes 193;; 194--continue) 195test -d"$dotest"-o -d"$GIT_DIR"/rebase-apply|| 196 die "No rebase in progress?" 197 198 git diff-files --quiet --ignore-submodules|| { 199echo"You must edit all merge conflicts and then" 200echo"mark them as resolved using git add" 201exit1 202} 203iftest -d"$dotest" 204then 205 prev_head=$(cat "$dotest/prev_head") 206 end=$(cat "$dotest/end") 207 msgnum=$(cat "$dotest/msgnum") 208 onto=$(cat "$dotest/onto") 209 continue_merge 210whiletest"$msgnum"-le"$end" 211do 212 call_merge "$msgnum" 213 continue_merge 214done 215 finish_rb_merge 216exit 217fi 218 head_name=$(cat "$GIT_DIR"/rebase-apply/head-name)&& 219 onto=$(cat "$GIT_DIR"/rebase-apply/onto)&& 220 orig_head=$(cat "$GIT_DIR"/rebase-apply/orig-head)&& 221 git am --resolved --3way --resolvemsg="$RESOLVEMSG"&& 222 move_to_original_branch 223exit 224;; 225--skip) 226test -d"$dotest"-o -d"$GIT_DIR"/rebase-apply|| 227 die "No rebase in progress?" 228 229 git reset--hard HEAD ||exit $? 230iftest -d"$dotest" 231then 232 git rerere clear 233 prev_head=$(cat "$dotest/prev_head") 234 end=$(cat "$dotest/end") 235 msgnum=$(cat "$dotest/msgnum") 236 msgnum=$(($msgnum + 1)) 237 onto=$(cat "$dotest/onto") 238whiletest"$msgnum"-le"$end" 239do 240 call_merge "$msgnum" 241 continue_merge 242done 243 finish_rb_merge 244exit 245fi 246 head_name=$(cat "$GIT_DIR"/rebase-apply/head-name)&& 247 onto=$(cat "$GIT_DIR"/rebase-apply/onto)&& 248 orig_head=$(cat "$GIT_DIR"/rebase-apply/orig-head)&& 249 git am -3 --skip --resolvemsg="$RESOLVEMSG"&& 250 move_to_original_branch 251exit 252;; 253--abort) 254test -d"$dotest"-o -d"$GIT_DIR"/rebase-apply|| 255 die "No rebase in progress?" 256 257 git rerere clear 258iftest -d"$dotest" 259then 260 move_to_original_branch 261else 262 dotest="$GIT_DIR"/rebase-apply 263 move_to_original_branch 264fi 265 git reset--hard$(cat "$dotest/orig-head") 266rm-r"$dotest" 267exit 268;; 269--onto) 270test2-le"$#"|| usage 271 newbase="$2" 272shift 273;; 274-M|-m|--m|--me|--mer|--merg|--merge) 275 do_merge=t 276;; 277-s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\ 278--strateg=*|--strategy=*|\ 279-s|--s|--st|--str|--stra|--strat|--strate|--strateg|--strategy) 280case"$#,$1"in 281*,*=*) 282 strategy=`expr "z$1" : 'z-[^=]*=\(.*\)'`;; 2831,*) 284 usage ;; 285*) 286 strategy="$2" 287shift;; 288esac 289 do_merge=t 290;; 291-v|--verbose) 292 verbose=t 293;; 294--whitespace=*) 295 git_am_opt="$git_am_opt$1" 296;; 297-C*) 298 git_am_opt="$git_am_opt$1" 299;; 300-*) 301 usage 302;; 303*) 304break 305;; 306esac 307shift 308done 309 310# Make sure we do not have $GIT_DIR/rebase-apply 311iftest -z"$do_merge" 312then 313ifmkdir"$GIT_DIR"/rebase-apply2>/dev/null 314then 315rmdir"$GIT_DIR"/rebase-apply 316else 317echo>&2' 318It seems that I cannot create a rebase-apply directory, and 319I wonder if you are in the middle of patch application or another 320rebase. If that is not the case, please 321 rm -fr '"$GIT_DIR"'/rebase-apply 322and run me again. I am stopping in case you still have something 323valuable there.' 324exit1 325fi 326else 327iftest -d"$dotest" 328then 329 die "previous rebase directory$doteststill exists." \ 330'Try git rebase (--continue | --abort | --skip)' 331fi 332fi 333 334# The tree must be really really clean. 335git update-index --ignore-submodules --refresh||exit 336diff=$(git diff-index --cached --name-status -r --ignore-submodules HEAD --) 337case"$diff"in 338?*)echo"cannot rebase: your index is not up-to-date" 339echo"$diff" 340exit1 341;; 342esac 343 344# The upstream head must be given. Make sure it is valid. 345upstream_name="$1" 346upstream=`git rev-parse --verify "${upstream_name}^0"`|| 347 die "invalid upstream$upstream_name" 348 349# Make sure the branch to rebase onto is valid. 350onto_name=${newbase-"$upstream_name"} 351onto=$(git rev-parse --verify "${onto_name}^0")||exit 352 353# If a hook exists, give it a chance to interrupt 354run_pre_rebase_hook ${1+"$@"} 355 356# If the branch to rebase is given, that is the branch we will rebase 357# $branch_name -- branch being rebased, or HEAD (already detached) 358# $orig_head -- commit object name of tip of the branch before rebasing 359# $head_name -- refs/heads/<that-branch> or "detached HEAD" 360switch_to= 361case"$#"in 3622) 363# Is it "rebase other $branchname" or "rebase other $commit"? 364 branch_name="$2" 365 switch_to="$2" 366 367if git show-ref --verify --quiet --"refs/heads/$2"&& 368 branch=$(git rev-parse --verify "refs/heads/$2" 2>/dev/null) 369then 370 head_name="refs/heads/$2" 371elif branch=$(git rev-parse --verify "$2" 2>/dev/null) 372then 373 head_name="detached HEAD" 374else 375 usage 376fi 377;; 378*) 379# Do not need to switch branches, we are already on it. 380if branch_name=`git symbolic-ref -q HEAD` 381then 382 head_name=$branch_name 383 branch_name=`expr "z$branch_name" : 'zrefs/heads/\(.*\)'` 384else 385 head_name="detached HEAD" 386 branch_name=HEAD ;# detached 387fi 388 branch=$(git rev-parse --verify "${branch_name}^0")||exit 389;; 390esac 391orig_head=$branch 392 393# Now we are rebasing commits $upstream..$branch on top of $onto 394 395# Check if we are already based on $onto with linear history, 396# but this should be done only when upstream and onto are the same. 397mb=$(git merge-base "$onto" "$branch") 398iftest"$upstream"="$onto"&&test"$mb"="$onto"&& 399# linear history? 400! (git rev-list --parents"$onto".."$branch"|grep" .* ") > /dev/null 401then 402# Lazily switch to the target branch if needed... 403test -z"$switch_to"|| git checkout "$switch_to" 404echo>&2"Current branch$branch_nameis up to date." 405exit0 406fi 407 408iftest -n"$verbose" 409then 410echo"Changes from$mbto$onto:" 411# We want color (if set), but no pager 412 GIT_PAGER='' git diff--stat --summary"$mb""$onto" 413fi 414 415# Detach HEAD and reset the tree 416echo"First, rewinding head to replay your work on top of it..." 417git checkout -q"$onto^0"|| die "could not detach HEAD" 418git update-ref ORIG_HEAD $branch 419 420# If the $onto is a proper descendant of the tip of the branch, then 421# we just fast forwarded. 422iftest"$mb"="$branch" 423then 424echo>&2"Fast-forwarded$branch_nameto$onto_name." 425 move_to_original_branch 426exit0 427fi 428 429iftest -z"$do_merge" 430then 431 git format-patch -k --stdout --full-index --ignore-if-in-upstream \ 432"$upstream..$orig_head"| 433 git am $git_am_opt--rebasing --resolvemsg="$RESOLVEMSG"&& 434 move_to_original_branch 435 ret=$? 436test0!=$ret-a -d"$GIT_DIR"/rebase-apply&& 437echo$head_name>"$GIT_DIR"/rebase-apply/head-name&& 438echo$onto>"$GIT_DIR"/rebase-apply/onto && 439echo$orig_head>"$GIT_DIR"/rebase-apply/orig-head 440exit$ret 441fi 442 443# start doing a rebase with git-merge 444# this is rename-aware if the recursive (default) strategy is used 445 446mkdir-p"$dotest" 447echo"$onto">"$dotest/onto" 448echo"$onto_name">"$dotest/onto_name" 449prev_head=$orig_head 450echo"$prev_head">"$dotest/prev_head" 451echo"$orig_head">"$dotest/orig-head" 452echo"$head_name">"$dotest/head-name" 453 454msgnum=0 455for cmt in`git rev-list --reverse --no-merges "$upstream..$orig_head"` 456do 457 msgnum=$(($msgnum + 1)) 458echo"$cmt">"$dotest/cmt.$msgnum" 459done 460 461echo1>"$dotest/msgnum" 462echo$msgnum>"$dotest/end" 463 464end=$msgnum 465msgnum=1 466 467whiletest"$msgnum"-le"$end" 468do 469 call_merge "$msgnum" 470 continue_merge 471done 472 473finish_rb_merge