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