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