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