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