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