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