1#!/bin/sh 2# 3# Copyright (c) 2005 Junio C Hamano. 4# 5 6USAGE='[--interactive | -i] [-v] [--force-rebase | -f] [--no-ff] [--onto <newbase>] (<upstream>|--root) [<branch>] [--quiet | -q]' 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 37LF=' 38' 39ok_to_skip_pre_rebase= 40resolvemsg=" 41When you have resolved this problem run\"git rebase --continue\". 42If you would prefer to skip this patch, instead run\"git rebase --skip\". 43To restore the original branch and stop rebasing run\"git rebase --abort\". 44" 45unset onto 46strategy= 47strategy_opts= 48do_merge= 49merge_dir="$GIT_DIR"/rebase-merge 50apply_dir="$GIT_DIR"/rebase-apply 51verbose= 52diffstat= 53test"$(git config --bool rebase.stat)"= true && diffstat=t 54git_am_opt= 55rebase_root= 56force_rebase= 57allow_rerere_autoupdate= 58# Non-empty if a rebase was in progress when 'git rebase' was invoked 59in_progress= 60# One of {am, merge, interactive} 61type= 62# One of {"$GIT_DIR"/rebase-apply, "$GIT_DIR"/rebase-merge} 63state_dir= 64# One of {'', continue, skip, abort}, as parsed from command line 65action= 66preserve_merges= 67autosquash= 68test"$(git config --bool rebase.autosquash)"="true"&& autosquash=t 69 70read_basic_state () { 71 head_name=$(cat "$state_dir"/head-name)&& 72 onto=$(cat "$state_dir"/onto)&& 73iftest"$type"= interactive 74then 75 orig_head=$(cat "$state_dir"/head) 76else 77 orig_head=$(cat "$state_dir"/orig-head) 78fi&& 79 GIT_QUIET=$(cat "$state_dir"/quiet) 80} 81 82output () { 83case"$verbose"in 84'') 85 output=$("$@" 2>&1 ) 86 status=$? 87test$status!=0&&printf"%s\n""$output" 88return$status 89;; 90*) 91"$@" 92;; 93esac 94} 95 96move_to_original_branch () { 97case"$head_name"in 98 refs/*) 99 message="rebase finished:$head_nameonto$onto" 100 git update-ref -m"$message" \ 101$head_name $(git rev-parse HEAD) $orig_head&& 102 git symbolic-ref HEAD $head_name|| 103 die "Could not move back to$head_name" 104;; 105esac 106} 107 108run_specific_rebase () { 109if["$interactive_rebase"= implied ];then 110 GIT_EDITOR=: 111export GIT_EDITOR 112fi 113 . git-rebase--$type 114} 115 116run_pre_rebase_hook () { 117iftest -z"$ok_to_skip_pre_rebase"&& 118test -x"$GIT_DIR/hooks/pre-rebase" 119then 120"$GIT_DIR/hooks/pre-rebase"${1+"$@"}|| 121 die "The pre-rebase hook refused to rebase." 122fi 123} 124 125test -f"$apply_dir"/applying && 126 die 'It looks like git-am is in progress. Cannot rebase.' 127 128iftest -d"$apply_dir" 129then 130type=am 131 state_dir="$apply_dir" 132eliftest -d"$merge_dir" 133then 134iftest -f"$merge_dir"/interactive 135then 136type=interactive 137 interactive_rebase=explicit 138else 139type=merge 140fi 141 state_dir="$merge_dir" 142fi 143test -n"$type"&& in_progress=t 144 145total_argc=$# 146whiletest$#!=0 147do 148case"$1"in 149--no-verify) 150 ok_to_skip_pre_rebase=yes 151;; 152--verify) 153 ok_to_skip_pre_rebase= 154;; 155--continue|--skip|--abort) 156test$total_argc-eq1|| usage 157 action=${1##--} 158;; 159--onto) 160test2-le"$#"|| usage 161 onto="$2" 162shift 163;; 164-i|--interactive) 165 interactive_rebase=explicit 166;; 167-p|--preserve-merges) 168 preserve_merges=t 169test -z"$interactive_rebase"&& interactive_rebase=implied 170;; 171--autosquash) 172 autosquash=t 173;; 174--no-autosquash) 175 autosquash= 176;; 177-M|-m|--m|--me|--mer|--merg|--merge) 178 do_merge=t 179;; 180-X*|--strategy-option*) 181case"$#,$1"in 1821,-X|1,--strategy-option) 183 usage ;; 184*,-X|*,--strategy-option) 185 newopt="$2" 186shift;; 187*,--strategy-option=*) 188 newopt="$(expr " $1" : ' --strategy-option=\(.*\)')";; 189*,-X*) 190 newopt="$(expr " $1" : ' -X\(.*\)')";; 1911,*) 192 usage ;; 193esac 194 strategy_opts="$strategy_opts$(git rev-parse --sq-quote "--$newopt")" 195 do_merge=t 196test -z"$strategy"&& strategy=recursive 197;; 198-s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\ 199--strateg=*|--strategy=*|\ 200-s|--s|--st|--str|--stra|--strat|--strate|--strateg|--strategy) 201case"$#,$1"in 202*,*=*) 203 strategy=`expr "z$1" : 'z-[^=]*=\(.*\)'`;; 2041,*) 205 usage ;; 206*) 207 strategy="$2" 208shift;; 209esac 210 do_merge=t 211;; 212-n|--no-stat) 213 diffstat= 214;; 215--stat) 216 diffstat=t 217;; 218-v|--verbose) 219 verbose=t 220 diffstat=t 221 GIT_QUIET= 222;; 223-q|--quiet) 224 GIT_QUIET=t 225 git_am_opt="$git_am_opt-q" 226 verbose= 227 diffstat= 228;; 229--whitespace=*) 230 git_am_opt="$git_am_opt$1" 231case"$1"in 232--whitespace=fix|--whitespace=strip) 233 force_rebase=t 234;; 235esac 236;; 237--ignore-whitespace) 238 git_am_opt="$git_am_opt$1" 239;; 240--committer-date-is-author-date|--ignore-date) 241 git_am_opt="$git_am_opt$1" 242 force_rebase=t 243;; 244-C*) 245 git_am_opt="$git_am_opt$1" 246;; 247--root) 248 rebase_root=t 249;; 250-f|--f|--fo|--for|--forc|--force|--force-r|--force-re|--force-reb|--force-reba|--force-rebas|--force-rebase|--no-ff) 251 force_rebase=t 252;; 253--rerere-autoupdate|--no-rerere-autoupdate) 254 allow_rerere_autoupdate="$1" 255;; 256-*) 257 usage 258;; 259*) 260break 261;; 262esac 263shift 264done 265test$#-gt2&& usage 266 267iftest -n"$action" 268then 269test -z"$in_progress"&& die "No rebase in progress?" 270# Only interactive rebase uses detailed reflog messages 271iftest"$type"= interactive &&test"$GIT_REFLOG_ACTION"= rebase 272then 273 GIT_REFLOG_ACTION="rebase -i ($action)" 274export GIT_REFLOG_ACTION 275fi 276fi 277 278case"$action"in 279continue) 280# Sanity check 281 git rev-parse --verify HEAD >/dev/null || 282 die "Cannot read HEAD" 283 git update-index --ignore-submodules --refresh&& 284 git diff-files --quiet --ignore-submodules|| { 285echo"You must edit all merge conflicts and then" 286echo"mark them as resolved using git add" 287exit1 288} 289 read_basic_state 290 run_specific_rebase 291;; 292skip) 293 output git reset--hard HEAD ||exit $? 294 read_basic_state 295 run_specific_rebase 296;; 297abort) 298 git rerere clear 299 read_basic_state 300case"$head_name"in 301 refs/*) 302 git symbolic-ref HEAD $head_name|| 303 die "Could not move back to$head_name" 304;; 305esac 306 output git reset--hard$orig_head 307rm-r"$state_dir" 308exit 309;; 310esac 311 312# Make sure no rebase is in progress 313iftest -n"$in_progress" 314then 315 die ' 316It seems that there is already a '"${state_dir##*/}"' directory, and 317I wonder if you are in the middle of another rebase. If that is the 318case, please try 319 git rebase (--continue | --abort | --skip) 320If that is not the case, please 321 rm -fr '"$state_dir"' 322and run me again. I am stopping in case you still have something 323valuable there.' 324fi 325 326test$#-eq0&&test -z"$rebase_root"&& usage 327 328iftest -n"$interactive_rebase" 329then 330type=interactive 331 state_dir="$merge_dir" 332eliftest -n"$do_merge" 333then 334type=merge 335 state_dir="$merge_dir" 336else 337type=am 338 state_dir="$apply_dir" 339fi 340 341iftest -z"$rebase_root" 342then 343# The upstream head must be given. Make sure it is valid. 344 upstream_name="$1" 345shift 346 upstream=`git rev-parse --verify "${upstream_name}^0"`|| 347 die "invalid upstream$upstream_name" 348 upstream_arg="$upstream_name" 349else 350test -z"$onto"&& die "You must specify --onto when using --root" 351unset upstream_name 352unset upstream 353 upstream_arg=--root 354fi 355 356# Make sure the branch to rebase onto is valid. 357onto_name=${onto-"$upstream_name"} 358case"$onto_name"in 359*...*) 360if left=${onto_name%...*} right=${onto_name#*...}&& 361 onto=$(git merge-base --all ${left:-HEAD} ${right:-HEAD}) 362then 363case"$onto"in 364 ?*"$LF"?*) 365 die "$onto_name: there are more than one merge bases" 366;; 367'') 368 die "$onto_name: there is no merge base" 369;; 370esac 371else 372 die "$onto_name: there is no merge base" 373fi 374;; 375*) 376 onto=$(git rev-parse --verify "${onto_name}^0")|| 377 die "Does not point to a valid commit:$1" 378;; 379esac 380 381# If the branch to rebase is given, that is the branch we will rebase 382# $branch_name -- branch being rebased, or HEAD (already detached) 383# $orig_head -- commit object name of tip of the branch before rebasing 384# $head_name -- refs/heads/<that-branch> or "detached HEAD" 385switch_to= 386case"$#"in 3871) 388# Is it "rebase other $branchname" or "rebase other $commit"? 389 branch_name="$1" 390 switch_to="$1" 391 392if git show-ref --verify --quiet --"refs/heads/$1"&& 393 orig_head=$(git rev-parse -q --verify "refs/heads/$1") 394then 395 head_name="refs/heads/$1" 396elif orig_head=$(git rev-parse -q --verify "$1") 397then 398 head_name="detached HEAD" 399else 400echo>&2"fatal: no such branch:$1" 401 usage 402fi 403;; 404*) 405# Do not need to switch branches, we are already on it. 406if branch_name=`git symbolic-ref -q HEAD` 407then 408 head_name=$branch_name 409 branch_name=`expr "z$branch_name" : 'zrefs/heads/\(.*\)'` 410else 411 head_name="detached HEAD" 412 branch_name=HEAD ;# detached 413fi 414 orig_head=$(git rev-parse --verify "${branch_name}^0")||exit 415;; 416esac 417 418require_clean_work_tree "rebase""Please commit or stash them." 419 420# Now we are rebasing commits $upstream..$orig_head (or with --root, 421# everything leading up to $orig_head) on top of $onto 422 423# Check if we are already based on $onto with linear history, 424# but this should be done only when upstream and onto are the same 425# and if this is not an interactive rebase. 426mb=$(git merge-base "$onto" "$orig_head") 427iftest"$type"!= interactive &&test"$upstream"="$onto"&& 428test"$mb"="$onto"&& 429# linear history? 430! (git rev-list --parents"$onto".."$orig_head"| sane_grep " .* ") > /dev/null 431then 432iftest -z"$force_rebase" 433then 434# Lazily switch to the target branch if needed... 435test -z"$switch_to"|| git checkout "$switch_to"-- 436 say "Current branch$branch_nameis up to date." 437exit0 438else 439 say "Current branch$branch_nameis up to date, rebase forced." 440fi 441fi 442 443# If a hook exists, give it a chance to interrupt 444run_pre_rebase_hook "$upstream_arg""$@" 445 446iftest -n"$diffstat" 447then 448iftest -n"$verbose" 449then 450echo"Changes from$mbto$onto:" 451fi 452# We want color (if set), but no pager 453 GIT_PAGER='' git diff--stat --summary"$mb""$onto" 454fi 455 456test"$type"= interactive && run_specific_rebase 457 458# Detach HEAD and reset the tree 459say "First, rewinding head to replay your work on top of it..." 460git checkout -q"$onto^0"|| die "could not detach HEAD" 461git update-ref ORIG_HEAD $orig_head 462 463# If the $onto is a proper descendant of the tip of the branch, then 464# we just fast-forwarded. 465iftest"$mb"="$orig_head" 466then 467 say "Fast-forwarded$branch_nameto$onto_name." 468 move_to_original_branch 469exit0 470fi 471 472iftest -n"$rebase_root" 473then 474 revisions="$onto..$orig_head" 475else 476 revisions="$upstream..$orig_head" 477fi 478 479run_specific_rebase