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