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 685LF=' 686' 687parse_onto () { 688case"$1"in 689*...*) 690if left=${1%...*} right=${1#*...}&& 691 onto=$(git merge-base --all ${left:-HEAD} ${right:-HEAD}) 692then 693case"$onto"in 694 ?*"$LF"?* |'') 695exit1;; 696esac 697echo"$onto" 698exit0 699fi 700esac 701 git rev-parse --verify"$1^0" 702} 703 704case"$action"in 705continue) 706 get_saved_options 707 comment_for_reflog continue 708 709# Sanity check 710 git rev-parse --verify HEAD >/dev/null || 711 die "Cannot read HEAD" 712 git update-index --ignore-submodules --refresh&& 713 git diff-files --quiet --ignore-submodules|| 714 die "Working tree is dirty" 715 716# do we have anything to commit? 717if git diff-index --cached --quiet --ignore-submodules HEAD -- 718then 719: Nothing to commit -- skip this 720else 721 . "$author_script"|| 722 die "Cannot find the author identity" 723 current_head= 724iftest -f"$amend" 725then 726 current_head=$(git rev-parse --verify HEAD) 727test"$current_head"=$(cat "$amend")|| 728 die "\ 729You have uncommitted changes in your working tree. Please, commit them 730first and then run 'git rebase --continue' again." 731 git reset--soft HEAD^ || 732 die "Cannot rewind the HEAD" 733fi 734 do_with_author git commit --no-verify -F"$msg"-e|| { 735test -n"$current_head"&& git reset--soft$current_head 736 die "Could not commit staged changes." 737} 738fi 739 740 record_in_rewritten "$(cat "$dotest"/stopped-sha)" 741 742 require_clean_work_tree "rebase" 743 do_rest 744;; 745abort) 746 get_saved_options 747 comment_for_reflog abort 748 749 git rerere clear 750 751 headname=$(cat "$dotest"/head-name) 752head=$(cat "$dotest"/head) 753case$headnamein 754 refs/*) 755 git symbolic-ref HEAD $headname 756;; 757esac&& 758 output git reset--hard$head&& 759rm-rf"$dotest" 760exit 761;; 762skip) 763 get_saved_options 764 comment_for_reflog skip 765 766 git rerere clear 767 768 output git reset--hard&& do_rest 769;; 770esac 771 772iftest -n"$onto" 773then 774 onto=$(parse_onto "$onto")|| die "Does not point to a valid commit:$1" 775fi 776 777test -z"$rebase_root"-a$#-ge1-a$#-le2|| 778test!-z"$rebase_root"-a$#-le1|| usage 779 780git var GIT_COMMITTER_IDENT >/dev/null || 781 die "You need to set your committer info first" 782 783iftest -z"$rebase_root" 784then 785 upstream_arg="$1" 786 upstream=$(git rev-parse --verify "$1")|| die "Invalid base" 787test -z"$onto"&& onto=$upstream 788shift 789else 790 upstream= 791 upstream_arg=--root 792test -z"$onto"&& 793 die "You must specify --onto when using --root" 794fi 795run_pre_rebase_hook "$upstream_arg""$@" 796 797comment_for_reflog start 798 799require_clean_work_tree "rebase""Please commit or stash them." 800 801iftest!-z"$1" 802then 803 output git checkout "$1"--|| 804 die "Could not checkout$1" 805fi 806 807head=$(git rev-parse --verify HEAD)|| die "No HEAD?" 808mkdir"$dotest"|| die "Could not create temporary$dotest" 809 810: >"$dotest"/interactive || die "Could not mark as interactive" 811git symbolic-ref HEAD >"$dotest"/head-name2> /dev/null || 812echo"detached HEAD">"$dotest"/head-name 813 814echo$head>"$dotest"/head 815case"$rebase_root"in 816'') 817rm-f"$dotest"/rebase-root;; 818*) 819: >"$dotest"/rebase-root;; 820esac 821echo$onto>"$dotest"/onto 822test -z"$strategy"||echo"$strategy">"$dotest"/strategy 823test t ="$verbose"&& : >"$dotest"/verbose 824iftest t ="$preserve_merges" 825then 826iftest -z"$rebase_root" 827then 828mkdir"$rewritten"&& 829for c in$(git merge-base --all $head $upstream) 830do 831echo$onto>"$rewritten"/$c|| 832 die "Could not init rewritten commits" 833done 834else 835mkdir"$rewritten"&& 836echo$onto>"$rewritten"/root || 837 die "Could not init rewritten commits" 838fi 839# No cherry-pick because our first pass is to determine 840# parents to rewrite and skipping dropped commits would 841# prematurely end our probe 842 merges_option= 843 first_after_upstream="$(git rev-list --reverse --first-parent $upstream..$head | head -n 1)" 844else 845 merges_option="--no-merges --cherry-pick" 846fi 847 848shorthead=$(git rev-parse --short $head) 849shortonto=$(git rev-parse --short $onto) 850iftest -z"$rebase_root" 851# this is now equivalent to ! -z "$upstream" 852then 853 shortupstream=$(git rev-parse --short $upstream) 854 revisions=$upstream...$head 855 shortrevisions=$shortupstream..$shorthead 856else 857 revisions=$onto...$head 858 shortrevisions=$shorthead 859fi 860git rev-list$merges_option--pretty=oneline --abbrev-commit \ 861--abbrev=7--reverse --left-right --topo-order \ 862$revisions| \ 863sed-n"s/^>//p"| 864whileread -r shortsha1 rest 865do 866iftest t !="$preserve_merges" 867then 868printf'%s\n'"pick$shortsha1$rest">>"$todo" 869else 870 sha1=$(git rev-parse $shortsha1) 871iftest -z"$rebase_root" 872then 873 preserve=t 874for p in$(git rev-list --parents -1 $sha1 | cut -d' ' -s -f2-) 875do 876iftest -f"$rewritten"/$p-a \($p!=$onto-o$sha1=$first_after_upstream \) 877then 878 preserve=f 879fi 880done 881else 882 preserve=f 883fi 884iftest f ="$preserve" 885then 886touch"$rewritten"/$sha1 887printf'%s\n'"pick$shortsha1$rest">>"$todo" 888fi 889fi 890done 891 892# Watch for commits that been dropped by --cherry-pick 893iftest t ="$preserve_merges" 894then 895mkdir"$dropped" 896# Save all non-cherry-picked changes 897 git rev-list$revisions--left-right --cherry-pick| \ 898sed-n"s/^>//p">"$dotest"/not-cherry-picks 899# Now all commits and note which ones are missing in 900# not-cherry-picks and hence being dropped 901 git rev-list$revisions| 902whilereadrev 903do 904iftest -f"$rewritten"/$rev-a"$(sane_grep "$rev" "$dotest"/not-cherry-picks)"="" 905then 906# Use -f2 because if rev-list is telling us this commit is 907# not worthwhile, we don't want to track its multiple heads, 908# just the history of its first-parent for others that will 909# be rebasing on top of it 910 git rev-list --parents -1$rev| cut -d' '-s -f2>"$dropped"/$rev 911 short=$(git rev-list -1 --abbrev-commit --abbrev=7 $rev) 912 sane_grep -v"^[a-z][a-z]*$short"<"$todo">"${todo}2";mv"${todo}2""$todo" 913rm"$rewritten"/$rev 914fi 915done 916fi 917 918test -s"$todo"||echo noop >>"$todo" 919test -n"$autosquash"&& rearrange_squash "$todo" 920cat>>"$todo"<< EOF 921 922# Rebase$shortrevisionsonto$shortonto 923# 924# Commands: 925# p, pick = use commit 926# r, reword = use commit, but edit the commit message 927# e, edit = use commit, but stop for amending 928# s, squash = use commit, but meld into previous commit 929# f, fixup = like "squash", but discard this commit's log message 930# x, exec = run command (the rest of the line) using shell 931# 932# If you remove a line here THAT COMMIT WILL BE LOST. 933# However, if you remove everything, the rebase will be aborted. 934# 935EOF 936 937has_action "$todo"|| 938 die_abort "Nothing to do" 939 940cp"$todo""$todo".backup 941git_editor "$todo"|| 942 die_abort "Could not execute editor" 943 944has_action "$todo"|| 945 die_abort "Nothing to do" 946 947test -d"$rewritten"||test -n"$force_rebase"|| skip_unnecessary_picks 948 949output git checkout $onto|| die_abort "could not detach HEAD" 950git update-ref ORIG_HEAD $head 951do_rest