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