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