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 13OPTIONS_KEEPDASHDASH= 14OPTIONS_SPEC="\ 15git-rebase [-i] [options] [--] <upstream> [<branch>] 16git-rebase [-i] (--continue | --abort | --skip) 17-- 18 Available options are 19v,verbose display a diffstat of what changed upstream 20onto= rebase onto given branch instead of upstream 21p,preserve-merges try to recreate merges instead of ignoring them 22s,strategy= use the given merge strategy 23m,merge always used (no-op) 24i,interactive always used (no-op) 25 Actions: 26continue continue rebasing process 27abort abort rebasing process and restore original branch 28skip skip current patch and continue rebasing process 29no-verify override pre-rebase hook from stopping the operation 30root rebase all reachable commmits up to the root(s) 31" 32 33. git-sh-setup 34require_work_tree 35 36DOTEST="$GIT_DIR/rebase-merge" 37 38# The file containing rebase commands, comments, and empty lines. 39# This file is created by "git rebase -i" then edited by the user. As 40# the lines are processed, they are removed from the front of this 41# file and written to the tail of $DONE. 42TODO="$DOTEST"/git-rebase-todo 43 44# The rebase command lines that have already been processed. A line 45# is moved here when it is first handled, before any associated user 46# actions. 47DONE="$DOTEST"/done 48 49# The commit message that is planned to be used for any changes that 50# need to be committed following a user interaction. 51MSG="$DOTEST"/message 52 53# The file into which is accumulated the suggested commit message for 54# squash/fixup commands. When the first of a series of squash/fixups 55# is seen, the file is created and the commit message from the 56# previous commit and from the first squash/fixup commit are written 57# to it. The commit message for each subsequent squash/fixup commit 58# is appended to the file as it is processed. 59# 60# The first line of the file is of the form 61# # This is a combination of $COUNT commits. 62# where $COUNT is the number of commits whose messages have been 63# written to the file so far (including the initial "pick" commit). 64# Each time that a commit message is processed, this line is read and 65# updated. It is deleted just before the combined commit is made. 66SQUASH_MSG="$DOTEST"/message-squash 67 68# $REWRITTEN is the name of a directory containing files for each 69# commit that is reachable by at least one merge base of $HEAD and 70# $UPSTREAM. They are not necessarily rewritten, but their children 71# might be. This ensures that commits on merged, but otherwise 72# unrelated side branches are left alone. (Think "X" in the man page's 73# example.) 74REWRITTEN="$DOTEST"/rewritten 75 76DROPPED="$DOTEST"/dropped 77PRESERVE_MERGES= 78STRATEGY= 79ONTO= 80VERBOSE= 81OK_TO_SKIP_PRE_REBASE= 82REBASE_ROOT= 83 84GIT_CHERRY_PICK_HELP=" After resolving the conflicts, 85mark the corrected paths with 'git add <paths>', and 86run 'git rebase --continue'" 87export GIT_CHERRY_PICK_HELP 88 89warn () { 90echo"$*">&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 107run_pre_rebase_hook () { 108iftest -z"$OK_TO_SKIP_PRE_REBASE"&& 109test -x"$GIT_DIR/hooks/pre-rebase" 110then 111"$GIT_DIR/hooks/pre-rebase"${1+"$@"}|| { 112echo>&2"The pre-rebase hook refused to rebase." 113exit1 114} 115fi 116} 117 118require_clean_work_tree () { 119# test if working tree is dirty 120 git rev-parse --verify HEAD > /dev/null && 121 git update-index --ignore-submodules --refresh&& 122 git diff-files --quiet --ignore-submodules&& 123 git diff-index --cached --quiet HEAD --ignore-submodules --|| 124 die "Working tree is dirty" 125} 126 127ORIG_REFLOG_ACTION="$GIT_REFLOG_ACTION" 128 129comment_for_reflog () { 130case"$ORIG_REFLOG_ACTION"in 131''|rebase*) 132 GIT_REFLOG_ACTION="rebase -i ($1)" 133export GIT_REFLOG_ACTION 134;; 135esac 136} 137 138last_count= 139mark_action_done () { 140sed-e1q <"$TODO">>"$DONE" 141sed-e1d <"$TODO">>"$TODO".new 142mv-f"$TODO".new "$TODO" 143 count=$(sane_grep -c '^[^#]' < "$DONE") 144 total=$(($count+$(sane_grep -c '^[^#]' < "$TODO"))) 145iftest"$last_count"!="$count" 146then 147 last_count=$count 148printf"Rebasing (%d/%d)\r"$count $total 149test -z"$VERBOSE"||echo 150fi 151} 152 153make_patch () { 154 sha1_and_parents="$(git rev-list --parents -1 "$1")" 155case"$sha1_and_parents"in 156 ?*' '?*' '?*) 157 git diff--cc$sha1_and_parents 158;; 159 ?*' '?*) 160 git diff-tree -p"$1^!" 161;; 162*) 163echo"Root commit" 164;; 165esac>"$DOTEST"/patch 166test -f"$MSG"|| 167 git cat-file commit "$1"|sed"1,/^$/d">"$MSG" 168test -f"$DOTEST"/author-script|| 169 get_author_ident_from_commit "$1">"$DOTEST"/author-script 170} 171 172die_with_patch () { 173 make_patch "$1" 174 git rerere 175 die "$2" 176} 177 178die_abort () { 179rm-rf"$DOTEST" 180 die "$1" 181} 182 183has_action () { 184 sane_grep '^[^#]'"$1">/dev/null 185} 186 187pick_one () { 188 no_ff= 189case"$1"in-n) sha1=$2; no_ff=t ;; *) sha1=$1;;esac 190 output git rev-parse --verify$sha1|| die "Invalid commit name:$sha1" 191test -d"$REWRITTEN"&& 192 pick_one_preserving_merges "$@"&&return 193iftest -n"$REBASE_ROOT" 194then 195 output git cherry-pick"$@" 196return 197fi 198 parent_sha1=$(git rev-parse --verify $sha1^)|| 199 die "Could not get the parent of$sha1" 200 current_sha1=$(git rev-parse --verify HEAD) 201iftest -z"$no_ff"-a"$current_sha1"="$parent_sha1" 202then 203 output git reset--hard$sha1 204 output warn Fast-forward to $(git rev-parse --short $sha1) 205else 206 output git cherry-pick"$@" 207fi 208} 209 210pick_one_preserving_merges () { 211 fast_forward=t 212case"$1"in 213-n) 214 fast_forward=f 215 sha1=$2 216;; 217*) 218 sha1=$1 219;; 220esac 221 sha1=$(git rev-parse $sha1) 222 223iftest -f"$DOTEST"/current-commit 224then 225iftest"$fast_forward"= t 226then 227cat"$DOTEST"/current-commit|whileread current_commit 228do 229 git rev-parse HEAD >"$REWRITTEN"/$current_commit 230done 231rm"$DOTEST"/current-commit|| 232 die "Cannot write current commit's replacement sha1" 233fi 234fi 235 236echo$sha1>>"$DOTEST"/current-commit 237 238# rewrite parents; if none were rewritten, we can fast-forward. 239 new_parents= 240 pend="$(git rev-list --parents -1 $sha1 | cut -d' ' -s -f2-)" 241iftest"$pend"=" " 242then 243 pend=" root" 244fi 245while["$pend"!=""] 246do 247 p=$(expr "$pend" : ' \([^ ]*\)') 248 pend="${pend# $p}" 249 250 if test -f "$REWRITTEN"/$p 251 then 252 new_p=$(cat "$REWRITTEN"/$p) 253 254 # If the todo reordered commits, and our parent is marked for 255 # rewriting, but hasn't been gotten to yet, assume the user meant to 256# drop it on top of the current HEAD 257iftest -z"$new_p" 258then 259 new_p=$(git rev-parse HEAD) 260fi 261 262test$p!=$new_p&& fast_forward=f 263case"$new_parents"in 264*$new_p*) 265;;# do nothing; that parent is already there 266*) 267 new_parents="$new_parents$new_p" 268;; 269esac 270else 271iftest -f"$DROPPED"/$p 272then 273 fast_forward=f 274 replacement="$(cat "$DROPPED"/$p)" 275test -z"$replacement"&& replacement=root 276 pend="$replacement$pend" 277else 278 new_parents="$new_parents$p" 279fi 280fi 281done 282case$fast_forwardin 283 t) 284 output warn "Fast-forward to$sha1" 285 output git reset--hard$sha1|| 286 die "Cannot fast-forward to$sha1" 287;; 288 f) 289 first_parent=$(expr "$new_parents" : ' \([^ ]*\)') 290 291 if [ "$1" != "-n" ] 292 then 293 # detach HEAD to current parent 294 output git checkout$first_parent2> /dev/null || 295 die "Cannot move HEAD to$first_parent" 296 fi 297 298 case "$new_parents" in 299 ''*''*) 300 test "a$1" = a-n && die "Refusing to squash a merge:$sha1" 301 302 # redo merge 303 author_script=$(get_author_ident_from_commit $sha1) 304 eval "$author_script" 305 msg="$(git cat-file commit $sha1 | sed -e '1,/^$/d')" 306 # No point in merging the first parent, that's HEAD 307 new_parents=${new_parents# $first_parent} 308if! GIT_AUTHOR_NAME="$GIT_AUTHOR_NAME" \ 309 GIT_AUTHOR_EMAIL="$GIT_AUTHOR_EMAIL" \ 310 GIT_AUTHOR_DATE="$GIT_AUTHOR_DATE" \ 311 output git merge $STRATEGY-m"$msg" \ 312$new_parents 313then 314printf"%s\n""$msg">"$GIT_DIR"/MERGE_MSG 315 die_with_patch $sha1"Error redoing merge$sha1" 316fi 317;; 318*) 319 output git cherry-pick"$@"|| 320 die_with_patch $sha1"Could not pick$sha1" 321;; 322esac 323;; 324esac 325} 326 327nth_string () { 328case"$1"in 329*1[0-9]|*[04-9])echo"$1"th;; 330*1)echo"$1"st;; 331*2)echo"$1"nd;; 332*3)echo"$1"rd;; 333esac 334} 335 336make_squash_message () { 337iftest -f"$SQUASH_MSG";then 338# We want to be careful about matching only the commit 339# message comment lines generated by this function. 340# "[snrt][tdh]" matches the nth_string endings. 341 COUNT=$(($(sed -n "s/^# Th[^0-9]*\([1-9][0-9]*\)[snrt][tdh] commit message.*:/\1/p" \ 342 < "$SQUASH_MSG" | sed -ne '$p')+1)) 343 echo "# This is a combination of $COUNT commits." 344sed-e1d -e'2,/^./{ 345 /^$/d 346 }'<"$SQUASH_MSG" 347else 348 COUNT=2 349echo"# This is a combination of two commits." 350echo"# The first commit's message is:" 351echo 352 git cat-file commit HEAD |sed-e'1,/^$/d' 353fi 354case$1in 355 squash) 356echo 357echo"# This is the$(nth_string $COUNT)commit message:" 358echo 359 git cat-file commit $2|sed-e'1,/^$/d' 360;; 361 fixup) 362echo 363echo"# The$(nth_string $COUNT)commit message will be skipped:" 364echo 365# Comment the lines of the commit message out using 366# "# " rather than "# " to make them less likely to 367# confuse the sed regexp above. 368 git cat-file commit $2|sed-e'1,/^$/d'-e's/^/# /' 369;; 370esac 371} 372 373peek_next_command () { 374sed-n -e"/^#/d"-e"/^$/d"-e"s/ .*//p"-e"q"<"$TODO" 375} 376 377do_next () { 378rm-f"$MSG""$DOTEST"/author-script \ 379"$DOTEST"/amend ||exit 380read command sha1 rest <"$TODO" 381case"$command"in 382'#'*|''|noop) 383 mark_action_done 384;; 385 pick|p) 386 comment_for_reflog pick 387 388 mark_action_done 389 pick_one $sha1|| 390 die_with_patch $sha1"Could not apply$sha1...$rest" 391;; 392 reword|r) 393 comment_for_reflog reword 394 395 mark_action_done 396 pick_one $sha1|| 397 die_with_patch $sha1"Could not apply$sha1...$rest" 398 git commit --amend 399;; 400 edit|e) 401 comment_for_reflog edit 402 403 mark_action_done 404 pick_one $sha1|| 405 die_with_patch $sha1"Could not apply$sha1...$rest" 406 make_patch $sha1 407 git rev-parse --verify HEAD >"$DOTEST"/amend 408 warn "Stopped at$sha1...$rest" 409 warn "You can amend the commit now, with" 410 warn 411 warn " git commit --amend" 412 warn 413 warn "Once you are satisfied with your changes, run" 414 warn 415 warn " git rebase --continue" 416 warn 417exit0 418;; 419 squash|s|fixup|f) 420case"$command"in 421 squash|s) 422 squash_style=squash 423;; 424 fixup|f) 425 squash_style=fixup 426;; 427esac 428 comment_for_reflog $squash_style 429 430test -f"$DONE"&& has_action "$DONE"|| 431 die "Cannot '$squash_style' without a previous commit" 432 433 mark_action_done 434 make_squash_message $squash_style $sha1>"$MSG" 435 failed=f 436 author_script=$(get_author_ident_from_commit HEAD) 437 output git reset--soft HEAD^ 438 pick_one -n$sha1|| failed=t 439case"$(peek_next_command)"in 440 squash|s|fixup|f) 441 USE_OUTPUT=output 442 MSG_OPT=-F 443 EDIT_OR_FILE="$MSG" 444cp"$MSG""$SQUASH_MSG" 445;; 446*) 447 USE_OUTPUT= 448 MSG_OPT= 449 EDIT_OR_FILE=-e 450rm-f"$SQUASH_MSG"||exit 451cp"$MSG""$GIT_DIR"/SQUASH_MSG 452rm-f"$GIT_DIR"/MERGE_MSG ||exit 453;; 454esac 455echo"$author_script">"$DOTEST"/author-script 456iftest$failed= f 457then 458# This is like --amend, but with a different message 459eval"$author_script" 460 GIT_AUTHOR_NAME="$GIT_AUTHOR_NAME" \ 461 GIT_AUTHOR_EMAIL="$GIT_AUTHOR_EMAIL" \ 462 GIT_AUTHOR_DATE="$GIT_AUTHOR_DATE" \ 463$USE_OUTPUT git commit --no-verify \ 464$MSG_OPT"$EDIT_OR_FILE"|| failed=t 465fi 466iftest$failed= t 467then 468cp"$MSG""$GIT_DIR"/MERGE_MSG 469 warn 470 warn "Could not apply$sha1...$rest" 471 die_with_patch $sha1"" 472fi 473;; 474*) 475 warn "Unknown command:$command$sha1$rest" 476if git rev-parse --verify -q"$sha1">/dev/null 477then 478 die_with_patch $sha1"Please fix this in the file$TODO." 479else 480 die "Please fix this in the file$TODO." 481fi 482;; 483esac 484test -s"$TODO"&&return 485 486 comment_for_reflog finish && 487 HEADNAME=$(cat "$DOTEST"/head-name)&& 488 OLDHEAD=$(cat "$DOTEST"/head)&& 489 SHORTONTO=$(git rev-parse --short $(cat "$DOTEST"/onto)) && 490 NEWHEAD=$(git rev-parse HEAD)&& 491case$HEADNAMEin 492 refs/*) 493 message="$GIT_REFLOG_ACTION:$HEADNAMEonto$SHORTONTO"&& 494 git update-ref -m"$message"$HEADNAME $NEWHEAD $OLDHEAD&& 495 git symbolic-ref HEAD $HEADNAME 496;; 497esac&& { 498test!-f"$DOTEST"/verbose || 499 git diff-tree --stat$(cat "$DOTEST"/head)..HEAD 500} && 501rm-rf"$DOTEST"&& 502 git gc --auto&& 503 warn "Successfully rebased and updated$HEADNAME." 504 505exit 506} 507 508do_rest () { 509while: 510do 511 do_next 512done 513} 514 515# skip picking commits whose parents are unchanged 516skip_unnecessary_picks () { 517 fd=3 518whileread command sha1 rest 519do 520# fd=3 means we skip the command 521case"$fd,$command,$(git rev-parse --verify --quiet $sha1^)"in 5223,pick,"$ONTO"*|3,p,"$ONTO"*) 523# pick a commit whose parent is current $ONTO -> skip 524 ONTO=$sha1 525;; 5263,#*|3,,*) 527# copy comments 528;; 529*) 530 fd=1 531;; 532esac 533echo"$command${sha1:+ }$sha1${rest:+ }$rest">&$fd 534done<"$TODO">"$TODO.new"3>>"$DONE"&& 535mv-f"$TODO".new "$TODO"|| 536 die "Could not skip unnecessary pick commands" 537} 538 539# check if no other options are set 540is_standalone () { 541test$#-eq2-a"$2"='--'&& 542test -z"$ONTO"&& 543test -z"$PRESERVE_MERGES"&& 544test -z"$STRATEGY"&& 545test -z"$VERBOSE" 546} 547 548get_saved_options () { 549test -d"$REWRITTEN"&& PRESERVE_MERGES=t 550test -f"$DOTEST"/strategy && STRATEGY="$(cat "$DOTEST"/strategy)" 551test -f"$DOTEST"/verbose && VERBOSE=t 552test -f"$DOTEST"/rebase-root&& REBASE_ROOT=t 553} 554 555whiletest$#!=0 556do 557case"$1"in 558--no-verify) 559 OK_TO_SKIP_PRE_REBASE=yes 560;; 561--verify) 562;; 563--continue) 564 is_standalone "$@"|| usage 565 get_saved_options 566 comment_for_reflog continue 567 568test -d"$DOTEST"|| die "No interactive rebase running" 569 570# Sanity check 571 git rev-parse --verify HEAD >/dev/null || 572 die "Cannot read HEAD" 573 git update-index --ignore-submodules --refresh&& 574 git diff-files --quiet --ignore-submodules|| 575 die "Working tree is dirty" 576 577# do we have anything to commit? 578if git diff-index --cached --quiet --ignore-submodules HEAD -- 579then 580: Nothing to commit -- skip this 581else 582 . "$DOTEST"/author-script|| 583 die "Cannot find the author identity" 584 amend= 585iftest -f"$DOTEST"/amend 586then 587 amend=$(git rev-parse --verify HEAD) 588test"$amend"=$(cat "$DOTEST"/amend)|| 589 die "\ 590You have uncommitted changes in your working tree. Please, commit them 591first and then run 'git rebase --continue' again." 592 git reset--soft HEAD^ || 593 die "Cannot rewind the HEAD" 594fi 595export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE && 596 git commit --no-verify -F"$MSG"-e|| { 597test -n"$amend"&& git reset--soft$amend 598 die "Could not commit staged changes." 599} 600fi 601 602 require_clean_work_tree 603 do_rest 604;; 605--abort) 606 is_standalone "$@"|| usage 607 get_saved_options 608 comment_for_reflog abort 609 610 git rerere clear 611test -d"$DOTEST"|| die "No interactive rebase running" 612 613 HEADNAME=$(cat "$DOTEST"/head-name) 614 HEAD=$(cat "$DOTEST"/head) 615case$HEADNAMEin 616 refs/*) 617 git symbolic-ref HEAD $HEADNAME 618;; 619esac&& 620 output git reset--hard$HEAD&& 621rm-rf"$DOTEST" 622exit 623;; 624--skip) 625 is_standalone "$@"|| usage 626 get_saved_options 627 comment_for_reflog skip 628 629 git rerere clear 630test -d"$DOTEST"|| die "No interactive rebase running" 631 632 output git reset--hard&& do_rest 633;; 634-s) 635case"$#,$1"in 636*,*=*) 637 STRATEGY="-s "$(expr "z$1" : 'z-[^=]*=\(.*\)') ;; 638 1,*) 639 usage ;; 640 *) 641 STRATEGY="-s$2" 642 shift ;; 643 esac 644 ;; 645 -m) 646 # we use merge anyway 647 ;; 648 -v) 649 VERBOSE=t 650 ;; 651 -p) 652 PRESERVE_MERGES=t 653 ;; 654 -i) 655 # yeah, we know 656 ;; 657 --root) 658 REBASE_ROOT=t 659 ;; 660 --onto) 661 shift 662 ONTO=$(git rev-parse --verify "$1")|| 663 die "Does not point to a valid commit:$1" 664 ;; 665 --) 666 shift 667 test -z "$REBASE_ROOT" -a$#-ge 1 -a$#-le 2 || 668 test ! -z "$REBASE_ROOT" -a$#-le 1 || usage 669 test -d "$DOTEST" && 670 die "Interactive rebase already started" 671 672 git var GIT_COMMITTER_IDENT >/dev/null || 673 die "You need to set your committer info first" 674 675 if test -z "$REBASE_ROOT" 676 then 677 UPSTREAM_ARG="$1" 678 UPSTREAM=$(git rev-parse --verify "$1")|| die "Invalid base" 679 test -z "$ONTO" && ONTO=$UPSTREAM 680 shift 681 else 682 UPSTREAM= 683 UPSTREAM_ARG=--root 684 test -z "$ONTO" && 685 die "You must specify --onto when using --root" 686 fi 687 run_pre_rebase_hook "$UPSTREAM_ARG" "$@" 688 689 comment_for_reflog start 690 691 require_clean_work_tree 692 693 if test ! -z "$1" 694 then 695 output git show-ref --verify --quiet "refs/heads/$1" || 696 die "Invalid branchname:$1" 697 output git checkout "$1" || 698 die "Could not checkout$1" 699 fi 700 701 HEAD=$(git rev-parse --verify HEAD)|| die "No HEAD?" 702 mkdir "$DOTEST" || die "Could not create temporary$DOTEST" 703 704 : > "$DOTEST"/interactive || die "Could not mark as interactive" 705 git symbolic-ref HEAD > "$DOTEST"/head-name 2> /dev/null || 706 echo "detached HEAD" > "$DOTEST"/head-name 707 708 echo$HEAD> "$DOTEST"/head 709 case "$REBASE_ROOT" in 710 '') 711 rm -f "$DOTEST"/rebase-root ;; 712 *) 713 : >"$DOTEST"/rebase-root ;; 714 esac 715 echo$ONTO> "$DOTEST"/onto 716 test -z "$STRATEGY" || echo "$STRATEGY" > "$DOTEST"/strategy 717 test t = "$VERBOSE" && : > "$DOTEST"/verbose 718 if test t = "$PRESERVE_MERGES" 719 then 720 if test -z "$REBASE_ROOT" 721 then 722 mkdir "$REWRITTEN" && 723 for c in$(git merge-base --all $HEAD $UPSTREAM) 724 do 725 echo$ONTO> "$REWRITTEN"/$c|| 726 die "Could not init rewritten commits" 727 done 728 else 729 mkdir "$REWRITTEN" && 730 echo$ONTO> "$REWRITTEN"/root || 731 die "Could not init rewritten commits" 732 fi 733 # No cherry-pick because our first pass is to determine 734 # parents to rewrite and skipping dropped commits would 735 # prematurely end our probe 736 MERGES_OPTION= 737 first_after_upstream="$(git rev-list --reverse --first-parent $UPSTREAM..$HEAD | head -n 1)" 738 else 739 MERGES_OPTION="--no-merges --cherry-pick" 740 fi 741 742 SHORTHEAD=$(git rev-parse --short $HEAD) 743 SHORTONTO=$(git rev-parse --short $ONTO) 744 if test -z "$REBASE_ROOT" 745 # this is now equivalent to ! -z "$UPSTREAM" 746 then 747 SHORTUPSTREAM=$(git rev-parse --short $UPSTREAM) 748 REVISIONS=$UPSTREAM...$HEAD 749 SHORTREVISIONS=$SHORTUPSTREAM..$SHORTHEAD 750 else 751 REVISIONS=$ONTO...$HEAD 752 SHORTREVISIONS=$SHORTHEAD 753 fi 754 git rev-list$MERGES_OPTION--pretty=oneline --abbrev-commit \ 755 --abbrev=7 --reverse --left-right --topo-order \ 756$REVISIONS| \ 757 sed -n "s/^>//p" | while read shortsha1 rest 758 do 759 if test t != "$PRESERVE_MERGES" 760 then 761 echo "pick$shortsha1$rest" >> "$TODO" 762 else 763 sha1=$(git rev-parse $shortsha1) 764 if test -z "$REBASE_ROOT" 765 then 766 preserve=t 767 for p in$(git rev-list --parents -1 $sha1 | cut -d' ' -s -f2-) 768 do 769 if test -f "$REWRITTEN"/$p-a \($p!=$ONTO-o$sha1=$first_after_upstream\) 770 then 771 preserve=f 772 fi 773 done 774 else 775 preserve=f 776 fi 777 if test f = "$preserve" 778 then 779 touch "$REWRITTEN"/$sha1 780 echo "pick$shortsha1$rest" >> "$TODO" 781 fi 782 fi 783 done 784 785 # Watch for commits that been dropped by --cherry-pick 786 if test t = "$PRESERVE_MERGES" 787 then 788 mkdir "$DROPPED" 789 # Save all non-cherry-picked changes 790 git rev-list$REVISIONS--left-right --cherry-pick | \ 791 sed -n "s/^>//p" > "$DOTEST"/not-cherry-picks 792 # Now all commits and note which ones are missing in 793 # not-cherry-picks and hence being dropped 794 git rev-list$REVISIONS| 795 while read rev 796 do 797 if test -f "$REWRITTEN"/$rev-a "$(sane_grep "$rev" "$DOTEST"/not-cherry-picks)" = "" 798 then 799 # Use -f2 because if rev-list is telling us this commit is 800 # not worthwhile, we don't want to track its multiple heads, 801# just the history of its first-parent for others that will 802# be rebasing on top of it 803 git rev-list --parents -1$rev| cut -d' '-s -f2>"$DROPPED"/$rev 804 short=$(git rev-list -1 --abbrev-commit --abbrev=7 $rev) 805 sane_grep -v"^[a-z][a-z]*$short"<"$TODO">"${TODO}2";mv"${TODO}2""$TODO" 806rm"$REWRITTEN"/$rev 807fi 808done 809fi 810 811test -s"$TODO"||echo noop >>"$TODO" 812cat>>"$TODO"<< EOF 813 814# Rebase$SHORTREVISIONSonto$SHORTONTO 815# 816# Commands: 817# p, pick = use commit 818# r, reword = use commit, but edit the commit message 819# e, edit = use commit, but stop for amending 820# s, squash = use commit, but meld into previous commit 821# f, fixup = like "squash", but discard this commit's log message 822# 823# If you remove a line here THAT COMMIT WILL BE LOST. 824# However, if you remove everything, the rebase will be aborted. 825# 826EOF 827 828 has_action "$TODO"|| 829 die_abort "Nothing to do" 830 831cp"$TODO""$TODO".backup 832 git_editor "$TODO"|| 833 die "Could not execute editor" 834 835 has_action "$TODO"|| 836 die_abort "Nothing to do" 837 838test -d"$REWRITTEN"|| skip_unnecessary_picks 839 840 git update-ref ORIG_HEAD $HEAD 841 output git checkout $ONTO&& do_rest 842;; 843esac 844shift 845done