1#!/bin/sh 2# 3# Copyright (c) 2006 Johannes E. Schindelin 4 5# SHORT DESCRIPTION 6# 7# This script makes it easy to fix up commits in the middle of a series, 8# and rearrange commits. 9# 10# The original idea comes from Eric W. Biederman, in 11# http://article.gmane.org/gmane.comp.version-control.git/22407 12 13OPTIONS_KEEPDASHDASH= 14OPTIONS_SPEC="\ 15git-rebase [-i] [options] [--] <upstream> [<branch>] 16git-rebase [-i] (--continue | --abort | --skip) 17-- 18 Available options are 19v,verbose display a diffstat of what changed upstream 20onto= rebase onto given branch instead of upstream 21p,preserve-merges try to recreate merges instead of ignoring them 22s,strategy= use the given merge strategy 23no-ff cherry-pick all commits, even if unchanged 24m,merge always used (no-op) 25i,interactive always used (no-op) 26 Actions: 27continue continue rebasing process 28abort abort rebasing process and restore original branch 29skip skip current patch and continue rebasing process 30no-verify override pre-rebase hook from stopping the operation 31root rebase all reachable commmits up to the root(s) 32autosquash move commits that begin with squash!/fixup! under -i 33" 34 35. git-sh-setup 36require_work_tree 37 38DOTEST="$GIT_DIR/rebase-merge" 39 40# The file containing rebase commands, comments, and empty lines. 41# This file is created by "git rebase -i" then edited by the user. As 42# the lines are processed, they are removed from the front of this 43# file and written to the tail of $DONE. 44TODO="$DOTEST"/git-rebase-todo 45 46# The rebase command lines that have already been processed. A line 47# is moved here when it is first handled, before any associated user 48# actions. 49DONE="$DOTEST"/done 50 51# The commit message that is planned to be used for any changes that 52# need to be committed following a user interaction. 53MSG="$DOTEST"/message 54 55# The file into which is accumulated the suggested commit message for 56# squash/fixup commands. When the first of a series of squash/fixups 57# is seen, the file is created and the commit message from the 58# previous commit and from the first squash/fixup commit are written 59# to it. The commit message for each subsequent squash/fixup commit 60# is appended to the file as it is processed. 61# 62# The first line of the file is of the form 63# # This is a combination of $COUNT commits. 64# where $COUNT is the number of commits whose messages have been 65# written to the file so far (including the initial "pick" commit). 66# Each time that a commit message is processed, this line is read and 67# updated. It is deleted just before the combined commit is made. 68SQUASH_MSG="$DOTEST"/message-squash 69 70# If the current series of squash/fixups has not yet included a squash 71# command, then this file exists and holds the commit message of the 72# original "pick" commit. (If the series ends without a "squash" 73# command, then this can be used as the commit message of the combined 74# commit without opening the editor.) 75FIXUP_MSG="$DOTEST"/message-fixup 76 77# $REWRITTEN is the name of a directory containing files for each 78# commit that is reachable by at least one merge base of $HEAD and 79# $UPSTREAM. They are not necessarily rewritten, but their children 80# might be. This ensures that commits on merged, but otherwise 81# unrelated side branches are left alone. (Think "X" in the man page's 82# example.) 83REWRITTEN="$DOTEST"/rewritten 84 85DROPPED="$DOTEST"/dropped 86 87# A script to set the GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and 88# GIT_AUTHOR_DATE that will be used for the commit that is currently 89# being rebased. 90AUTHOR_SCRIPT="$DOTEST"/author-script 91 92# When an "edit" rebase command is being processed, the SHA1 of the 93# commit to be edited is recorded in this file. When "git rebase 94# --continue" is executed, if there are any staged changes then they 95# will be amended to the HEAD commit, but only provided the HEAD 96# commit is still the commit to be edited. When any other rebase 97# command is processed, this file is deleted. 98AMEND="$DOTEST"/amend 99 100# For the post-rewrite hook, we make a list of rewritten commits and 101# their new sha1s. The rewritten-pending list keeps the sha1s of 102# commits that have been processed, but not committed yet, 103# e.g. because they are waiting for a 'squash' command. 104REWRITTEN_LIST="$DOTEST"/rewritten-list 105REWRITTEN_PENDING="$DOTEST"/rewritten-pending 106 107PRESERVE_MERGES= 108STRATEGY= 109ONTO= 110VERBOSE= 111OK_TO_SKIP_PRE_REBASE= 112REBASE_ROOT= 113AUTOSQUASH= 114test"$(git config --bool rebase.autosquash)"="true"&& AUTOSQUASH=t 115NEVER_FF= 116 117GIT_CHERRY_PICK_HELP="\ 118hint: after resolving the conflicts, mark the corrected paths 119hint: with 'git add <paths>' and run 'git rebase --continue'" 120export GIT_CHERRY_PICK_HELP 121 122warn () { 123printf'%s\n'"$*">&2 124} 125 126output () { 127case"$VERBOSE"in 128'') 129 output=$("$@" 2>&1 ) 130 status=$? 131test$status!=0&&printf"%s\n""$output" 132return$status 133;; 134*) 135"$@" 136;; 137esac 138} 139 140# Output the commit message for the specified commit. 141commit_message () { 142 git cat-file commit "$1"|sed"1,/^$/d" 143} 144 145run_pre_rebase_hook () { 146iftest -z"$OK_TO_SKIP_PRE_REBASE"&& 147test -x"$GIT_DIR/hooks/pre-rebase" 148then 149"$GIT_DIR/hooks/pre-rebase"${1+"$@"}|| { 150echo>&2"The pre-rebase hook refused to rebase." 151exit1 152} 153fi 154} 155 156 157ORIG_REFLOG_ACTION="$GIT_REFLOG_ACTION" 158 159comment_for_reflog () { 160case"$ORIG_REFLOG_ACTION"in 161''|rebase*) 162 GIT_REFLOG_ACTION="rebase -i ($1)" 163export GIT_REFLOG_ACTION 164;; 165esac 166} 167 168last_count= 169mark_action_done () { 170sed-e1q <"$TODO">>"$DONE" 171sed-e1d <"$TODO">>"$TODO".new 172mv-f"$TODO".new "$TODO" 173 count=$(sane_grep -c '^[^#]' < "$DONE") 174 total=$(($count+$(sane_grep -c '^[^#]' < "$TODO"))) 175iftest"$last_count"!="$count" 176then 177 last_count=$count 178printf"Rebasing (%d/%d)\r"$count $total 179test -z"$VERBOSE"||echo 180fi 181} 182 183make_patch () { 184 sha1_and_parents="$(git rev-list --parents -1 "$1")" 185case"$sha1_and_parents"in 186 ?*' '?*' '?*) 187 git diff--cc$sha1_and_parents 188;; 189 ?*' '?*) 190 git diff-tree -p"$1^!" 191;; 192*) 193echo"Root commit" 194;; 195esac>"$DOTEST"/patch 196test -f"$MSG"|| 197 commit_message "$1">"$MSG" 198test -f"$AUTHOR_SCRIPT"|| 199 get_author_ident_from_commit "$1">"$AUTHOR_SCRIPT" 200} 201 202die_with_patch () { 203echo"$1">"$DOTEST"/stopped-sha 204 make_patch "$1" 205 git rerere 206 die "$2" 207} 208 209die_abort () { 210rm-rf"$DOTEST" 211 die "$1" 212} 213 214has_action () { 215 sane_grep '^[^#]'"$1">/dev/null 216} 217 218# Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and 219# GIT_AUTHOR_DATE exported from the current environment. 220do_with_author () { 221( 222export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE 223"$@" 224) 225} 226 227pick_one () { 228 ff=--ff 229case"$1"in-n) sha1=$2; ff= ;; *) sha1=$1;;esac 230case"$NEVER_FF"in'') ;; ?*) ff= ;;esac 231 output git rev-parse --verify$sha1|| die "Invalid commit name:$sha1" 232test -d"$REWRITTEN"&& 233 pick_one_preserving_merges "$@"&&return 234iftest -n"$REBASE_ROOT" 235then 236 output git cherry-pick"$@" 237return 238fi 239 output git cherry-pick$ff"$@" 240} 241 242pick_one_preserving_merges () { 243 fast_forward=t 244case"$1"in 245-n) 246 fast_forward=f 247 sha1=$2 248;; 249*) 250 sha1=$1 251;; 252esac 253 sha1=$(git rev-parse $sha1) 254 255iftest -f"$DOTEST"/current-commit 256then 257iftest"$fast_forward"= t 258then 259whileread current_commit 260do 261 git rev-parse HEAD >"$REWRITTEN"/$current_commit 262done<"$DOTEST"/current-commit 263rm"$DOTEST"/current-commit|| 264 die "Cannot write current commit's replacement sha1" 265fi 266fi 267 268echo$sha1>>"$DOTEST"/current-commit 269 270# rewrite parents; if none were rewritten, we can fast-forward. 271 new_parents= 272 pend="$(git rev-list --parents -1 $sha1 | cut -d' ' -s -f2-)" 273iftest"$pend"=" " 274then 275 pend=" root" 276fi 277while["$pend"!=""] 278do 279 p=$(expr "$pend" : ' \([^ ]*\)') 280 pend="${pend# $p}" 281 282 if test -f "$REWRITTEN"/$p 283 then 284 new_p=$(cat "$REWRITTEN"/$p) 285 286 # If the todo reordered commits, and our parent is marked for 287 # rewriting, but hasn't been gotten to yet, assume the user meant to 288# drop it on top of the current HEAD 289iftest -z"$new_p" 290then 291 new_p=$(git rev-parse HEAD) 292fi 293 294test$p!=$new_p&& fast_forward=f 295case"$new_parents"in 296*$new_p*) 297;;# do nothing; that parent is already there 298*) 299 new_parents="$new_parents$new_p" 300;; 301esac 302else 303iftest -f"$DROPPED"/$p 304then 305 fast_forward=f 306 replacement="$(cat "$DROPPED"/$p)" 307test -z"$replacement"&& replacement=root 308 pend="$replacement$pend" 309else 310 new_parents="$new_parents$p" 311fi 312fi 313done 314case$fast_forwardin 315 t) 316 output warn "Fast-forward to$sha1" 317 output git reset--hard$sha1|| 318 die "Cannot fast-forward to$sha1" 319;; 320 f) 321 first_parent=$(expr "$new_parents" : ' \([^ ]*\)') 322 323 if [ "$1" != "-n" ] 324 then 325 # detach HEAD to current parent 326 output git checkout$first_parent2> /dev/null || 327 die "Cannot move HEAD to$first_parent" 328 fi 329 330 case "$new_parents" in 331 ''*''*) 332 test "a$1" = a-n && die "Refusing to squash a merge:$sha1" 333 334 # redo merge 335 author_script=$(get_author_ident_from_commit $sha1) 336 eval "$author_script" 337 msg="$(commit_message $sha1)" 338 # No point in merging the first parent, that's HEAD 339 new_parents=${new_parents# $first_parent} 340if! do_with_author output \ 341 git merge $STRATEGY-m"$msg"$new_parents 342then 343printf"%s\n""$msg">"$GIT_DIR"/MERGE_MSG 344 die_with_patch $sha1"Error redoing merge$sha1" 345fi 346echo"$sha1$(git rev-parse HEAD^0)">>"$REWRITTEN_LIST" 347;; 348*) 349 output git cherry-pick"$@"|| 350 die_with_patch $sha1"Could not pick$sha1" 351;; 352esac 353;; 354esac 355} 356 357nth_string () { 358case"$1"in 359*1[0-9]|*[04-9])echo"$1"th;; 360*1)echo"$1"st;; 361*2)echo"$1"nd;; 362*3)echo"$1"rd;; 363esac 364} 365 366update_squash_messages () { 367iftest -f"$SQUASH_MSG";then 368mv"$SQUASH_MSG""$SQUASH_MSG".bak ||exit 369 COUNT=$(($(sed-n \ 370-e"1s/^# This is a combination of \(.*\) commits\./\1/p" \ 371-e"q"<"$SQUASH_MSG".bak)+1)) 372{ 373echo"# This is a combination of$COUNTcommits." 374sed-e1d -e'2,/^./{ 375 /^$/d 376 }'<"$SQUASH_MSG".bak 377} >"$SQUASH_MSG" 378else 379 commit_message HEAD >"$FIXUP_MSG"|| die "Cannot write$FIXUP_MSG" 380 COUNT=2 381{ 382echo"# This is a combination of 2 commits." 383echo"# The first commit's message is:" 384echo 385cat"$FIXUP_MSG" 386} >"$SQUASH_MSG" 387fi 388case$1in 389 squash) 390rm-f"$FIXUP_MSG" 391echo 392echo"# This is the$(nth_string $COUNT)commit message:" 393echo 394 commit_message $2 395;; 396 fixup) 397echo 398echo"# The$(nth_string $COUNT)commit message will be skipped:" 399echo 400 commit_message $2|sed-e's/^/# /' 401;; 402esac>>"$SQUASH_MSG" 403} 404 405peek_next_command () { 406sed-n -e"/^#/d"-e'/^$/d'-e"s/ .*//p"-e"q"<"$TODO" 407} 408 409# A squash/fixup has failed. Prepare the long version of the squash 410# commit message, then die_with_patch. This code path requires the 411# user to edit the combined commit message for all commits that have 412# been squashed/fixedup so far. So also erase the old squash 413# messages, effectively causing the combined commit to be used as the 414# new basis for any further squash/fixups. Args: sha1 rest 415die_failed_squash() { 416mv"$SQUASH_MSG""$MSG"||exit 417rm-f"$FIXUP_MSG" 418cp"$MSG""$GIT_DIR"/MERGE_MSG ||exit 419 warn 420 warn "Could not apply$1...$2" 421 die_with_patch $1"" 422} 423 424flush_rewritten_pending() { 425test -s"$REWRITTEN_PENDING"||return 426 newsha1="$(git rev-parse HEAD^0)" 427sed"s/$/$newsha1/"<"$REWRITTEN_PENDING">>"$REWRITTEN_LIST" 428rm-f"$REWRITTEN_PENDING" 429} 430 431record_in_rewritten() { 432 oldsha1="$(git rev-parse $1)" 433echo"$oldsha1">>"$REWRITTEN_PENDING" 434 435case"$(peek_next_command)"in 436 squash|s|fixup|f) 437;; 438*) 439 flush_rewritten_pending 440;; 441esac 442} 443 444do_next () { 445rm-f"$MSG""$AUTHOR_SCRIPT""$AMEND"||exit 446read -r command sha1 rest <"$TODO" 447case"$command"in 448'#'*|''|noop) 449 mark_action_done 450;; 451 pick|p) 452 comment_for_reflog pick 453 454 mark_action_done 455 pick_one $sha1|| 456 die_with_patch $sha1"Could not apply$sha1...$rest" 457 record_in_rewritten $sha1 458;; 459 reword|r) 460 comment_for_reflog reword 461 462 mark_action_done 463 pick_one $sha1|| 464 die_with_patch $sha1"Could not apply$sha1...$rest" 465 git commit --amend --no-post-rewrite 466 record_in_rewritten $sha1 467;; 468 edit|e) 469 comment_for_reflog edit 470 471 mark_action_done 472 pick_one $sha1|| 473 die_with_patch $sha1"Could not apply$sha1...$rest" 474echo"$sha1">"$DOTEST"/stopped-sha 475 make_patch $sha1 476 git rev-parse --verify HEAD >"$AMEND" 477 warn "Stopped at$sha1...$rest" 478 warn "You can amend the commit now, with" 479 warn 480 warn " git commit --amend" 481 warn 482 warn "Once you are satisfied with your changes, run" 483 warn 484 warn " git rebase --continue" 485 warn 486exit0 487;; 488 squash|s|fixup|f) 489case"$command"in 490 squash|s) 491 squash_style=squash 492;; 493 fixup|f) 494 squash_style=fixup 495;; 496esac 497 comment_for_reflog $squash_style 498 499test -f"$DONE"&& has_action "$DONE"|| 500 die "Cannot '$squash_style' without a previous commit" 501 502 mark_action_done 503 update_squash_messages $squash_style $sha1 504 author_script=$(get_author_ident_from_commit HEAD) 505echo"$author_script">"$AUTHOR_SCRIPT" 506eval"$author_script" 507 output git reset--soft HEAD^ 508 pick_one -n$sha1|| die_failed_squash $sha1"$rest" 509case"$(peek_next_command)"in 510 squash|s|fixup|f) 511# This is an intermediate commit; its message will only be 512# used in case of trouble. So use the long version: 513 do_with_author output git commit --no-verify -F"$SQUASH_MSG"|| 514 die_failed_squash $sha1"$rest" 515;; 516*) 517# This is the final command of this squash/fixup group 518iftest -f"$FIXUP_MSG" 519then 520 do_with_author git commit --no-verify -F"$FIXUP_MSG"|| 521 die_failed_squash $sha1"$rest" 522else 523cp"$SQUASH_MSG""$GIT_DIR"/SQUASH_MSG ||exit 524rm-f"$GIT_DIR"/MERGE_MSG 525 do_with_author git commit --no-verify -e|| 526 die_failed_squash $sha1"$rest" 527fi 528rm-f"$SQUASH_MSG""$FIXUP_MSG" 529;; 530esac 531 record_in_rewritten $sha1 532;; 533 x|"exec") 534read -r command rest <"$TODO" 535 mark_action_done 536printf'Executing: %s\n'"$rest" 537# "exec" command doesn't take a sha1 in the todo-list. 538# => can't just use $sha1 here. 539 git rev-parse --verify HEAD >"$DOTEST"/stopped-sha 540${SHELL:-@SHELL_PATH@}-c"$rest"# Actual execution 541 status=$? 542iftest"$status"-ne0 543then 544 warn "Execution failed:$rest" 545 warn "You can fix the problem, and then run" 546 warn 547 warn " git rebase --continue" 548 warn 549exit"$status" 550fi 551# Run in subshell because require_clean_work_tree can die. 552if! (require_clean_work_tree "rebase") 553then 554 warn "Commit or stash your changes, and then run" 555 warn 556 warn " git rebase --continue" 557 warn 558exit1 559fi 560;; 561*) 562 warn "Unknown command:$command$sha1$rest" 563if git rev-parse --verify -q"$sha1">/dev/null 564then 565 die_with_patch $sha1"Please fix this in the file$TODO." 566else 567 die "Please fix this in the file$TODO." 568fi 569;; 570esac 571test -s"$TODO"&&return 572 573 comment_for_reflog finish && 574 HEADNAME=$(cat "$DOTEST"/head-name)&& 575 OLDHEAD=$(cat "$DOTEST"/head)&& 576 SHORTONTO=$(git rev-parse --short $(cat "$DOTEST"/onto)) && 577 NEWHEAD=$(git rev-parse HEAD)&& 578case$HEADNAMEin 579 refs/*) 580 message="$GIT_REFLOG_ACTION:$HEADNAMEonto$SHORTONTO"&& 581 git update-ref -m"$message"$HEADNAME $NEWHEAD $OLDHEAD&& 582 git symbolic-ref HEAD $HEADNAME 583;; 584esac&& { 585test!-f"$DOTEST"/verbose || 586 git diff-tree --stat$(cat "$DOTEST"/head)..HEAD 587} && 588{ 589test -s"$REWRITTEN_LIST"&& 590 git notes copy --for-rewrite=rebase <"$REWRITTEN_LIST"|| 591 true # we don't care if this copying failed 592} && 593iftest -x"$GIT_DIR"/hooks/post-rewrite&& 594test -s"$REWRITTEN_LIST";then 595"$GIT_DIR"/hooks/post-rewrite rebase <"$REWRITTEN_LIST" 596 true # we don't care if this hook failed 597fi&& 598rm-rf"$DOTEST"&& 599 git gc --auto&& 600 warn "Successfully rebased and updated$HEADNAME." 601 602exit 603} 604 605do_rest () { 606while: 607do 608 do_next 609done 610} 611 612# skip picking commits whose parents are unchanged 613skip_unnecessary_picks () { 614 fd=3 615whileread -r command rest 616do 617# fd=3 means we skip the command 618case"$fd,$command"in 6193,pick|3,p) 620# pick a commit whose parent is current $ONTO -> skip 621 sha1=${rest%% *} 622case"$(git rev-parse --verify --quiet "$sha1"^)"in 623"$ONTO"*) 624 ONTO=$sha1 625;; 626*) 627 fd=1 628;; 629esac 630;; 6313,#*|3,) 632# copy comments 633;; 634*) 635 fd=1 636;; 637esac 638printf'%s\n'"$command${rest:+ }$rest">&$fd 639done<"$TODO">"$TODO.new"3>>"$DONE"&& 640mv-f"$TODO".new "$TODO"&& 641case"$(peek_next_command)"in 642 squash|s|fixup|f) 643 record_in_rewritten "$ONTO" 644;; 645esac|| 646 die "Could not skip unnecessary pick commands" 647} 648 649# check if no other options are set 650is_standalone () { 651test$#-eq2-a"$2"='--'&& 652test -z"$ONTO"&& 653test -z"$PRESERVE_MERGES"&& 654test -z"$STRATEGY"&& 655test -z"$VERBOSE" 656} 657 658get_saved_options () { 659test -d"$REWRITTEN"&& PRESERVE_MERGES=t 660test -f"$DOTEST"/strategy && STRATEGY="$(cat "$DOTEST"/strategy)" 661test -f"$DOTEST"/verbose && VERBOSE=t 662test -f"$DOTEST"/rebase-root&& REBASE_ROOT=t 663} 664 665# Rearrange the todo list that has both "pick sha1 msg" and 666# "pick sha1 fixup!/squash! msg" appears in it so that the latter 667# comes immediately after the former, and change "pick" to 668# "fixup"/"squash". 669rearrange_squash () { 670# extract fixup!/squash! lines and resolve any referenced sha1's 671whileread -r pick sha1 message 672do 673case"$message"in 674"squash! "*|"fixup! "*) 675 action="${message%%!*}" 676 rest="${message#*! }" 677echo"$sha1$action$rest" 678# if it's a single word, try to resolve to a full sha1 and 679# emit a second copy. This allows us to match on both message 680# and on sha1 prefix 681iftest"${rest#* }"="$rest";then 682 fullsha="$(git rev-parse -q --verify "$rest" 2>/dev/null)" 683iftest -n"$fullsha";then 684# prefix the action to uniquely identify this line as 685# intended for full sha1 match 686echo"$sha1+$action$fullsha" 687fi 688fi 689esac 690done>"$1.sq"<"$1" 691test -s"$1.sq"||return 692 693 used= 694whileread -r pick sha1 message 695do 696case"$used"in 697*"$sha1"*)continue;; 698esac 699printf'%s\n'"$pick$sha1$message" 700 used="$used$sha1" 701whileread -r squash action msg 702do 703case"$used"in 704*"$squash"*)continue;; 705esac 706 emit=0 707case"$action"in 708+*) 709 action="${action#+}" 710# full sha1 prefix test 711case"$msg"in"$sha1"*) emit=1;;esac;; 712*) 713# message prefix test 714case"$message"in"$msg"*) emit=1;;esac;; 715esac 716iftest$emit=1;then 717printf'%s\n'"$action$squash$action!$msg" 718 used="$used$squash" 719fi 720done<"$1.sq" 721done>"$1.rearranged"<"$1" 722cat"$1.rearranged">"$1" 723rm-f"$1.sq""$1.rearranged" 724} 725 726LF=' 727' 728parse_onto () { 729case"$1"in 730*...*) 731if left=${1%...*} right=${1#*...}&& 732 onto=$(git merge-base --all ${left:-HEAD} ${right:-HEAD}) 733then 734case"$onto"in 735 ?*"$LF"?* |'') 736exit1;; 737esac 738echo"$onto" 739exit0 740fi 741esac 742 git rev-parse --verify"$1^0" 743} 744 745whiletest$#!=0 746do 747case"$1"in 748--no-verify) 749 OK_TO_SKIP_PRE_REBASE=yes 750;; 751--verify) 752;; 753--continue) 754 is_standalone "$@"|| usage 755 get_saved_options 756 comment_for_reflog continue 757 758test -d"$DOTEST"|| die "No interactive rebase running" 759 760# Sanity check 761 git rev-parse --verify HEAD >/dev/null || 762 die "Cannot read HEAD" 763 git update-index --ignore-submodules --refresh&& 764 git diff-files --quiet --ignore-submodules|| 765 die "Working tree is dirty" 766 767# do we have anything to commit? 768if git diff-index --cached --quiet --ignore-submodules HEAD -- 769then 770: Nothing to commit -- skip this 771else 772 . "$AUTHOR_SCRIPT"|| 773 die "Cannot find the author identity" 774 amend= 775iftest -f"$AMEND" 776then 777 amend=$(git rev-parse --verify HEAD) 778test"$amend"=$(cat "$AMEND")|| 779 die "\ 780You have uncommitted changes in your working tree. Please, commit them 781first and then run 'git rebase --continue' again." 782 git reset--soft HEAD^ || 783 die "Cannot rewind the HEAD" 784fi 785 do_with_author git commit --no-verify -F"$MSG"-e|| { 786test -n"$amend"&& git reset--soft$amend 787 die "Could not commit staged changes." 788} 789fi 790 791 record_in_rewritten "$(cat "$DOTEST"/stopped-sha)" 792 793 require_clean_work_tree "rebase" 794 do_rest 795;; 796--abort) 797 is_standalone "$@"|| usage 798 get_saved_options 799 comment_for_reflog abort 800 801 git rerere clear 802test -d"$DOTEST"|| die "No interactive rebase running" 803 804 HEADNAME=$(cat "$DOTEST"/head-name) 805 HEAD=$(cat "$DOTEST"/head) 806case$HEADNAMEin 807 refs/*) 808 git symbolic-ref HEAD $HEADNAME 809;; 810esac&& 811 output git reset--hard$HEAD&& 812rm-rf"$DOTEST" 813exit 814;; 815--skip) 816 is_standalone "$@"|| usage 817 get_saved_options 818 comment_for_reflog skip 819 820 git rerere clear 821test -d"$DOTEST"|| die "No interactive rebase running" 822 823 output git reset--hard&& do_rest 824;; 825-s) 826case"$#,$1"in 827*,*=*) 828 STRATEGY="-s "$(expr "z$1" : 'z-[^=]*=\(.*\)') ;; 829 1,*) 830 usage ;; 831 *) 832 STRATEGY="-s$2" 833 shift ;; 834 esac 835 ;; 836 -m) 837 # we use merge anyway 838 ;; 839 -v) 840 VERBOSE=t 841 ;; 842 -p) 843 PRESERVE_MERGES=t 844 ;; 845 -i) 846 # yeah, we know 847 ;; 848 --no-ff) 849 NEVER_FF=t 850 ;; 851 --root) 852 REBASE_ROOT=t 853 ;; 854 --autosquash) 855 AUTOSQUASH=t 856 ;; 857 --no-autosquash) 858 AUTOSQUASH= 859 ;; 860 --onto) 861 shift 862 ONTO=$(parse_onto "$1")|| 863 die "Does not point to a valid commit:$1" 864 ;; 865 --) 866 shift 867 test -z "$REBASE_ROOT" -a$#-ge 1 -a$#-le 2 || 868 test ! -z "$REBASE_ROOT" -a$#-le 1 || usage 869 test -d "$DOTEST" && 870 die "Interactive rebase already started" 871 872 git var GIT_COMMITTER_IDENT >/dev/null || 873 die "You need to set your committer info first" 874 875 if test -z "$REBASE_ROOT" 876 then 877 UPSTREAM_ARG="$1" 878 UPSTREAM=$(git rev-parse --verify "$1")|| die "Invalid base" 879 test -z "$ONTO" && ONTO=$UPSTREAM 880 shift 881 else 882 UPSTREAM= 883 UPSTREAM_ARG=--root 884 test -z "$ONTO" && 885 die "You must specify --onto when using --root" 886 fi 887 run_pre_rebase_hook "$UPSTREAM_ARG" "$@" 888 889 comment_for_reflog start 890 891 require_clean_work_tree "rebase" "Please commit or stash them." 892 893 if test ! -z "$1" 894 then 895 output git checkout "$1" || 896 die "Could not checkout$1" 897 fi 898 899 HEAD=$(git rev-parse --verify HEAD)|| die "No HEAD?" 900 mkdir "$DOTEST" || die "Could not create temporary$DOTEST" 901 902 : > "$DOTEST"/interactive || die "Could not mark as interactive" 903 git symbolic-ref HEAD > "$DOTEST"/head-name 2> /dev/null || 904 echo "detached HEAD" > "$DOTEST"/head-name 905 906 echo$HEAD> "$DOTEST"/head 907 case "$REBASE_ROOT" in 908 '') 909 rm -f "$DOTEST"/rebase-root ;; 910 *) 911 : >"$DOTEST"/rebase-root ;; 912 esac 913 echo$ONTO> "$DOTEST"/onto 914 test -z "$STRATEGY" || echo "$STRATEGY" > "$DOTEST"/strategy 915 test t = "$VERBOSE" && : > "$DOTEST"/verbose 916 if test t = "$PRESERVE_MERGES" 917 then 918 if test -z "$REBASE_ROOT" 919 then 920 mkdir "$REWRITTEN" && 921 for c in$(git merge-base --all $HEAD $UPSTREAM) 922 do 923 echo$ONTO> "$REWRITTEN"/$c|| 924 die "Could not init rewritten commits" 925 done 926 else 927 mkdir "$REWRITTEN" && 928 echo$ONTO> "$REWRITTEN"/root || 929 die "Could not init rewritten commits" 930 fi 931 # No cherry-pick because our first pass is to determine 932 # parents to rewrite and skipping dropped commits would 933 # prematurely end our probe 934 MERGES_OPTION= 935 first_after_upstream="$(git rev-list --reverse --first-parent $UPSTREAM..$HEAD | head -n 1)" 936 else 937 MERGES_OPTION="--no-merges --cherry-pick" 938 fi 939 940 SHORTHEAD=$(git rev-parse --short $HEAD) 941 SHORTONTO=$(git rev-parse --short $ONTO) 942 if test -z "$REBASE_ROOT" 943 # this is now equivalent to ! -z "$UPSTREAM" 944 then 945 SHORTUPSTREAM=$(git rev-parse --short $UPSTREAM) 946 REVISIONS=$UPSTREAM...$HEAD 947 SHORTREVISIONS=$SHORTUPSTREAM..$SHORTHEAD 948 else 949 REVISIONS=$ONTO...$HEAD 950 SHORTREVISIONS=$SHORTHEAD 951 fi 952 git rev-list$MERGES_OPTION--pretty=oneline --abbrev-commit \ 953 --abbrev=7 --reverse --left-right --topo-order \ 954$REVISIONS| \ 955 sed -n "s/^>//p" | 956 while read -r shortsha1 rest 957 do 958 if test t != "$PRESERVE_MERGES" 959 then 960 printf '%s\n' "pick$shortsha1$rest" >> "$TODO" 961 else 962 sha1=$(git rev-parse $shortsha1) 963 if test -z "$REBASE_ROOT" 964 then 965 preserve=t 966 for p in$(git rev-list --parents -1 $sha1 | cut -d' ' -s -f2-) 967 do 968 if test -f "$REWRITTEN"/$p-a \($p!=$ONTO-o$sha1=$first_after_upstream\) 969 then 970 preserve=f 971 fi 972 done 973 else 974 preserve=f 975 fi 976 if test f = "$preserve" 977 then 978 touch "$REWRITTEN"/$sha1 979 printf '%s\n' "pick$shortsha1$rest" >> "$TODO" 980 fi 981 fi 982 done 983 984 # Watch for commits that been dropped by --cherry-pick 985 if test t = "$PRESERVE_MERGES" 986 then 987 mkdir "$DROPPED" 988 # Save all non-cherry-picked changes 989 git rev-list$REVISIONS--left-right --cherry-pick | \ 990 sed -n "s/^>//p" > "$DOTEST"/not-cherry-picks 991 # Now all commits and note which ones are missing in 992 # not-cherry-picks and hence being dropped 993 git rev-list$REVISIONS| 994 while read rev 995 do 996 if test -f "$REWRITTEN"/$rev-a "$(sane_grep "$rev" "$DOTEST"/not-cherry-picks)" = "" 997 then 998 # Use -f2 because if rev-list is telling us this commit is 999 # not worthwhile, we don't want to track its multiple heads,1000# just the history of its first-parent for others that will1001# be rebasing on top of it1002 git rev-list --parents -1$rev| cut -d' '-s -f2>"$DROPPED"/$rev1003 short=$(git rev-list -1 --abbrev-commit --abbrev=7 $rev)1004 sane_grep -v"^[a-z][a-z]*$short"<"$TODO">"${TODO}2";mv"${TODO}2""$TODO"1005rm"$REWRITTEN"/$rev1006fi1007done1008fi10091010test -s"$TODO"||echo noop >>"$TODO"1011test -n"$AUTOSQUASH"&& rearrange_squash "$TODO"1012cat>>"$TODO"<< EOF10131014# Rebase$SHORTREVISIONSonto$SHORTONTO1015#1016# Commands:1017# p, pick = use commit1018# r, reword = use commit, but edit the commit message1019# e, edit = use commit, but stop for amending1020# s, squash = use commit, but meld into previous commit1021# f, fixup = like "squash", but discard this commit's log message1022# x <cmd>, exec <cmd> = Run a shell command <cmd>, and stop if it fails1023#1024# If you remove a line here THAT COMMIT WILL BE LOST.1025# However, if you remove everything, the rebase will be aborted.1026#1027EOF10281029 has_action "$TODO"||1030 die_abort "Nothing to do"10311032cp"$TODO""$TODO".backup1033 git_editor "$TODO"||1034 die_abort "Could not execute editor"10351036 has_action "$TODO"||1037 die_abort "Nothing to do"10381039test -d"$REWRITTEN"||test -n"$NEVER_FF"|| skip_unnecessary_picks10401041 output git checkout $ONTO|| die_abort "could not detach HEAD"1042 git update-ref ORIG_HEAD $HEAD1043 do_rest1044;;1045esac1046shift1047done