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