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. 335if! git update-index --ignore-submodules --refresh;then 336echo>&2"cannot rebase: you have unstaged changes" 337exit1 338fi 339diff=$(git diff-index --cached --name-status -r --ignore-submodules HEAD --) 340case"$diff"in 341?*)echo>&2"cannot rebase: your index contains uncommitted changes" 342echo>&2"$diff" 343exit1 344;; 345esac 346 347# The upstream head must be given. Make sure it is valid. 348upstream_name="$1" 349upstream=`git rev-parse --verify "${upstream_name}^0"`|| 350 die "invalid upstream$upstream_name" 351 352# Make sure the branch to rebase onto is valid. 353onto_name=${newbase-"$upstream_name"} 354onto=$(git rev-parse --verify "${onto_name}^0")||exit 355 356# If a hook exists, give it a chance to interrupt 357run_pre_rebase_hook ${1+"$@"} 358 359# If the branch to rebase is given, that is the branch we will rebase 360# $branch_name -- branch being rebased, or HEAD (already detached) 361# $orig_head -- commit object name of tip of the branch before rebasing 362# $head_name -- refs/heads/<that-branch> or "detached HEAD" 363switch_to= 364case"$#"in 3652) 366# Is it "rebase other $branchname" or "rebase other $commit"? 367 branch_name="$2" 368 switch_to="$2" 369 370if git show-ref --verify --quiet --"refs/heads/$2"&& 371 branch=$(git rev-parse -q --verify "refs/heads/$2") 372then 373 head_name="refs/heads/$2" 374elif branch=$(git rev-parse -q --verify "$2") 375then 376 head_name="detached HEAD" 377else 378 usage 379fi 380;; 381*) 382# Do not need to switch branches, we are already on it. 383if branch_name=`git symbolic-ref -q HEAD` 384then 385 head_name=$branch_name 386 branch_name=`expr "z$branch_name" : 'zrefs/heads/\(.*\)'` 387else 388 head_name="detached HEAD" 389 branch_name=HEAD ;# detached 390fi 391 branch=$(git rev-parse --verify "${branch_name}^0")||exit 392;; 393esac 394orig_head=$branch 395 396# Now we are rebasing commits $upstream..$branch on top of $onto 397 398# Check if we are already based on $onto with linear history, 399# but this should be done only when upstream and onto are the same. 400mb=$(git merge-base "$onto" "$branch") 401iftest"$upstream"="$onto"&&test"$mb"="$onto"&& 402# linear history? 403! (git rev-list --parents"$onto".."$branch"|grep" .* ") > /dev/null 404then 405# Lazily switch to the target branch if needed... 406test -z"$switch_to"|| git checkout "$switch_to" 407echo>&2"Current branch$branch_nameis up to date." 408exit0 409fi 410 411iftest -n"$verbose" 412then 413echo"Changes from$mbto$onto:" 414# We want color (if set), but no pager 415 GIT_PAGER='' git diff--stat --summary"$mb""$onto" 416fi 417 418# Detach HEAD and reset the tree 419echo"First, rewinding head to replay your work on top of it..." 420git checkout -q"$onto^0"|| die "could not detach HEAD" 421git update-ref ORIG_HEAD $branch 422 423# If the $onto is a proper descendant of the tip of the branch, then 424# we just fast forwarded. 425iftest"$mb"="$branch" 426then 427echo>&2"Fast-forwarded$branch_nameto$onto_name." 428 move_to_original_branch 429exit0 430fi 431 432iftest -z"$do_merge" 433then 434 git format-patch -k --stdout --full-index --ignore-if-in-upstream \ 435"$upstream..$orig_head"| 436 git am $git_am_opt--rebasing --resolvemsg="$RESOLVEMSG"&& 437 move_to_original_branch 438 ret=$? 439test0!=$ret-a -d"$GIT_DIR"/rebase-apply&& 440echo$head_name>"$GIT_DIR"/rebase-apply/head-name&& 441echo$onto>"$GIT_DIR"/rebase-apply/onto && 442echo$orig_head>"$GIT_DIR"/rebase-apply/orig-head 443exit$ret 444fi 445 446# start doing a rebase with git-merge 447# this is rename-aware if the recursive (default) strategy is used 448 449mkdir-p"$dotest" 450echo"$onto">"$dotest/onto" 451echo"$onto_name">"$dotest/onto_name" 452prev_head=$orig_head 453echo"$prev_head">"$dotest/prev_head" 454echo"$orig_head">"$dotest/orig-head" 455echo"$head_name">"$dotest/head-name" 456 457msgnum=0 458for cmt in`git rev-list --reverse --no-merges "$upstream..$orig_head"` 459do 460 msgnum=$(($msgnum + 1)) 461echo"$cmt">"$dotest/cmt.$msgnum" 462done 463 464echo1>"$dotest/msgnum" 465echo$msgnum>"$dotest/end" 466 467end=$msgnum 468msgnum=1 469 470whiletest"$msgnum"-le"$end" 471do 472 call_merge "$msgnum" 473 continue_merge 474done 475 476finish_rb_merge