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 361update_squash_message () { 362iftest -f"$SQUASH_MSG";then 363mv"$SQUASH_MSG""$SQUASH_MSG".bak ||exit 364 COUNT=$(($(sed-n \ 365-e"1s/^# This is a combination of \(.*\) commits\./\1/p" \ 366-e"q"<"$SQUASH_MSG".bak)+1)) 367{ 368echo"# This is a combination of$COUNTcommits." 369sed-e1d -e'2,/^./{ 370 /^$/d 371 }'<"$SQUASH_MSG".bak 372} >$SQUASH_MSG 373else 374 COUNT=2 375{ 376echo"# This is a combination of 2 commits." 377echo"# The first commit's message is:" 378echo 379 commit_message HEAD 380} >$SQUASH_MSG 381fi 382case$1in 383 squash) 384echo 385echo"# This is the$(nth_string $COUNT)commit message:" 386echo 387 commit_message $2 388;; 389 fixup) 390echo 391echo"# The$(nth_string $COUNT)commit message will be skipped:" 392echo 393 commit_message $2|sed-e's/^/# /' 394;; 395esac>>$SQUASH_MSG 396} 397 398peek_next_command () { 399sed-n -e"/^#/d"-e"/^$/d"-e"s/ .*//p"-e"q"<"$TODO" 400} 401 402do_next () { 403rm-f"$MSG""$AUTHOR_SCRIPT""$AMEND"||exit 404read command sha1 rest <"$TODO" 405case"$command"in 406'#'*|''|noop) 407 mark_action_done 408;; 409 pick|p) 410 comment_for_reflog pick 411 412 mark_action_done 413 pick_one $sha1|| 414 die_with_patch $sha1"Could not apply$sha1...$rest" 415;; 416 reword|r) 417 comment_for_reflog reword 418 419 mark_action_done 420 pick_one $sha1|| 421 die_with_patch $sha1"Could not apply$sha1...$rest" 422 git commit --amend 423;; 424 edit|e) 425 comment_for_reflog edit 426 427 mark_action_done 428 pick_one $sha1|| 429 die_with_patch $sha1"Could not apply$sha1...$rest" 430 make_patch $sha1 431 git rev-parse --verify HEAD >"$AMEND" 432 warn "Stopped at$sha1...$rest" 433 warn "You can amend the commit now, with" 434 warn 435 warn " git commit --amend" 436 warn 437 warn "Once you are satisfied with your changes, run" 438 warn 439 warn " git rebase --continue" 440 warn 441exit0 442;; 443 squash|s|fixup|f) 444case"$command"in 445 squash|s) 446 squash_style=squash 447;; 448 fixup|f) 449 squash_style=fixup 450;; 451esac 452 comment_for_reflog $squash_style 453 454test -f"$DONE"&& has_action "$DONE"|| 455 die "Cannot '$squash_style' without a previous commit" 456 457 mark_action_done 458 update_squash_message $squash_style $sha1 459 failed=f 460 author_script=$(get_author_ident_from_commit HEAD) 461echo"$author_script">"$AUTHOR_SCRIPT" 462eval"$author_script" 463 output git reset--soft HEAD^ 464 pick_one -n$sha1|| failed=t 465case"$(peek_next_command)"in 466 squash|s|fixup|f) 467 USE_OUTPUT=output 468cp"$SQUASH_MSG""$MSG"||exit 469 MSG_OPT=-F 470 EDIT_OR_FILE="$MSG" 471;; 472*) 473 USE_OUTPUT= 474 MSG_OPT= 475 EDIT_OR_FILE=-e 476cp"$SQUASH_MSG""$MSG"||exit 477mv"$SQUASH_MSG""$GIT_DIR"/SQUASH_MSG ||exit 478rm-f"$GIT_DIR"/MERGE_MSG ||exit 479;; 480esac 481iftest$failed= f 482then 483# This is like --amend, but with a different message 484 do_with_author $USE_OUTPUT git commit --no-verify \ 485$MSG_OPT"$EDIT_OR_FILE"|| 486 failed=t 487fi 488iftest$failed= t 489then 490cp"$MSG""$GIT_DIR"/MERGE_MSG 491 warn 492 warn "Could not apply$sha1...$rest" 493 die_with_patch $sha1"" 494fi 495;; 496*) 497 warn "Unknown command:$command$sha1$rest" 498if git rev-parse --verify -q"$sha1">/dev/null 499then 500 die_with_patch $sha1"Please fix this in the file$TODO." 501else 502 die "Please fix this in the file$TODO." 503fi 504;; 505esac 506test -s"$TODO"&&return 507 508 comment_for_reflog finish && 509 HEADNAME=$(cat "$DOTEST"/head-name)&& 510 OLDHEAD=$(cat "$DOTEST"/head)&& 511 SHORTONTO=$(git rev-parse --short $(cat "$DOTEST"/onto)) && 512 NEWHEAD=$(git rev-parse HEAD)&& 513case$HEADNAMEin 514 refs/*) 515 message="$GIT_REFLOG_ACTION:$HEADNAMEonto$SHORTONTO"&& 516 git update-ref -m"$message"$HEADNAME $NEWHEAD $OLDHEAD&& 517 git symbolic-ref HEAD $HEADNAME 518;; 519esac&& { 520test!-f"$DOTEST"/verbose || 521 git diff-tree --stat$(cat "$DOTEST"/head)..HEAD 522} && 523rm-rf"$DOTEST"&& 524 git gc --auto&& 525 warn "Successfully rebased and updated$HEADNAME." 526 527exit 528} 529 530do_rest () { 531while: 532do 533 do_next 534done 535} 536 537# skip picking commits whose parents are unchanged 538skip_unnecessary_picks () { 539 fd=3 540whileread command sha1 rest 541do 542# fd=3 means we skip the command 543case"$fd,$command,$(git rev-parse --verify --quiet $sha1^)"in 5443,pick,"$ONTO"*|3,p,"$ONTO"*) 545# pick a commit whose parent is current $ONTO -> skip 546 ONTO=$sha1 547;; 5483,#*|3,,*) 549# copy comments 550;; 551*) 552 fd=1 553;; 554esac 555echo"$command${sha1:+ }$sha1${rest:+ }$rest">&$fd 556done<"$TODO">"$TODO.new"3>>"$DONE"&& 557mv-f"$TODO".new "$TODO"|| 558 die "Could not skip unnecessary pick commands" 559} 560 561# check if no other options are set 562is_standalone () { 563test$#-eq2-a"$2"='--'&& 564test -z"$ONTO"&& 565test -z"$PRESERVE_MERGES"&& 566test -z"$STRATEGY"&& 567test -z"$VERBOSE" 568} 569 570get_saved_options () { 571test -d"$REWRITTEN"&& PRESERVE_MERGES=t 572test -f"$DOTEST"/strategy && STRATEGY="$(cat "$DOTEST"/strategy)" 573test -f"$DOTEST"/verbose && VERBOSE=t 574test -f"$DOTEST"/rebase-root&& REBASE_ROOT=t 575} 576 577whiletest$#!=0 578do 579case"$1"in 580--no-verify) 581 OK_TO_SKIP_PRE_REBASE=yes 582;; 583--verify) 584;; 585--continue) 586 is_standalone "$@"|| usage 587 get_saved_options 588 comment_for_reflog continue 589 590test -d"$DOTEST"|| die "No interactive rebase running" 591 592# Sanity check 593 git rev-parse --verify HEAD >/dev/null || 594 die "Cannot read HEAD" 595 git update-index --ignore-submodules --refresh&& 596 git diff-files --quiet --ignore-submodules|| 597 die "Working tree is dirty" 598 599# do we have anything to commit? 600if git diff-index --cached --quiet --ignore-submodules HEAD -- 601then 602: Nothing to commit -- skip this 603else 604 . "$AUTHOR_SCRIPT"|| 605 die "Cannot find the author identity" 606 amend= 607iftest -f"$AMEND" 608then 609 amend=$(git rev-parse --verify HEAD) 610test"$amend"=$(cat "$AMEND")|| 611 die "\ 612You have uncommitted changes in your working tree. Please, commit them 613first and then run 'git rebase --continue' again." 614 git reset--soft HEAD^ || 615 die "Cannot rewind the HEAD" 616fi 617 do_with_author git commit --no-verify -F"$MSG"-e|| { 618test -n"$amend"&& git reset--soft$amend 619 die "Could not commit staged changes." 620} 621fi 622 623 require_clean_work_tree 624 do_rest 625;; 626--abort) 627 is_standalone "$@"|| usage 628 get_saved_options 629 comment_for_reflog abort 630 631 git rerere clear 632test -d"$DOTEST"|| die "No interactive rebase running" 633 634 HEADNAME=$(cat "$DOTEST"/head-name) 635 HEAD=$(cat "$DOTEST"/head) 636case$HEADNAMEin 637 refs/*) 638 git symbolic-ref HEAD $HEADNAME 639;; 640esac&& 641 output git reset--hard$HEAD&& 642rm-rf"$DOTEST" 643exit 644;; 645--skip) 646 is_standalone "$@"|| usage 647 get_saved_options 648 comment_for_reflog skip 649 650 git rerere clear 651test -d"$DOTEST"|| die "No interactive rebase running" 652 653 output git reset--hard&& do_rest 654;; 655-s) 656case"$#,$1"in 657*,*=*) 658 STRATEGY="-s "$(expr "z$1" : 'z-[^=]*=\(.*\)') ;; 659 1,*) 660 usage ;; 661 *) 662 STRATEGY="-s$2" 663 shift ;; 664 esac 665 ;; 666 -m) 667 # we use merge anyway 668 ;; 669 -v) 670 VERBOSE=t 671 ;; 672 -p) 673 PRESERVE_MERGES=t 674 ;; 675 -i) 676 # yeah, we know 677 ;; 678 --root) 679 REBASE_ROOT=t 680 ;; 681 --onto) 682 shift 683 ONTO=$(git rev-parse --verify "$1")|| 684 die "Does not point to a valid commit:$1" 685 ;; 686 --) 687 shift 688 test -z "$REBASE_ROOT" -a$#-ge 1 -a$#-le 2 || 689 test ! -z "$REBASE_ROOT" -a$#-le 1 || usage 690 test -d "$DOTEST" && 691 die "Interactive rebase already started" 692 693 git var GIT_COMMITTER_IDENT >/dev/null || 694 die "You need to set your committer info first" 695 696 if test -z "$REBASE_ROOT" 697 then 698 UPSTREAM_ARG="$1" 699 UPSTREAM=$(git rev-parse --verify "$1")|| die "Invalid base" 700 test -z "$ONTO" && ONTO=$UPSTREAM 701 shift 702 else 703 UPSTREAM= 704 UPSTREAM_ARG=--root 705 test -z "$ONTO" && 706 die "You must specify --onto when using --root" 707 fi 708 run_pre_rebase_hook "$UPSTREAM_ARG" "$@" 709 710 comment_for_reflog start 711 712 require_clean_work_tree 713 714 if test ! -z "$1" 715 then 716 output git show-ref --verify --quiet "refs/heads/$1" || 717 die "Invalid branchname:$1" 718 output git checkout "$1" || 719 die "Could not checkout$1" 720 fi 721 722 HEAD=$(git rev-parse --verify HEAD)|| die "No HEAD?" 723 mkdir "$DOTEST" || die "Could not create temporary$DOTEST" 724 725 : > "$DOTEST"/interactive || die "Could not mark as interactive" 726 git symbolic-ref HEAD > "$DOTEST"/head-name 2> /dev/null || 727 echo "detached HEAD" > "$DOTEST"/head-name 728 729 echo$HEAD> "$DOTEST"/head 730 case "$REBASE_ROOT" in 731 '') 732 rm -f "$DOTEST"/rebase-root ;; 733 *) 734 : >"$DOTEST"/rebase-root ;; 735 esac 736 echo$ONTO> "$DOTEST"/onto 737 test -z "$STRATEGY" || echo "$STRATEGY" > "$DOTEST"/strategy 738 test t = "$VERBOSE" && : > "$DOTEST"/verbose 739 if test t = "$PRESERVE_MERGES" 740 then 741 if test -z "$REBASE_ROOT" 742 then 743 mkdir "$REWRITTEN" && 744 for c in$(git merge-base --all $HEAD $UPSTREAM) 745 do 746 echo$ONTO> "$REWRITTEN"/$c|| 747 die "Could not init rewritten commits" 748 done 749 else 750 mkdir "$REWRITTEN" && 751 echo$ONTO> "$REWRITTEN"/root || 752 die "Could not init rewritten commits" 753 fi 754 # No cherry-pick because our first pass is to determine 755 # parents to rewrite and skipping dropped commits would 756 # prematurely end our probe 757 MERGES_OPTION= 758 first_after_upstream="$(git rev-list --reverse --first-parent $UPSTREAM..$HEAD | head -n 1)" 759 else 760 MERGES_OPTION="--no-merges --cherry-pick" 761 fi 762 763 SHORTHEAD=$(git rev-parse --short $HEAD) 764 SHORTONTO=$(git rev-parse --short $ONTO) 765 if test -z "$REBASE_ROOT" 766 # this is now equivalent to ! -z "$UPSTREAM" 767 then 768 SHORTUPSTREAM=$(git rev-parse --short $UPSTREAM) 769 REVISIONS=$UPSTREAM...$HEAD 770 SHORTREVISIONS=$SHORTUPSTREAM..$SHORTHEAD 771 else 772 REVISIONS=$ONTO...$HEAD 773 SHORTREVISIONS=$SHORTHEAD 774 fi 775 git rev-list$MERGES_OPTION--pretty=oneline --abbrev-commit \ 776 --abbrev=7 --reverse --left-right --topo-order \ 777$REVISIONS| \ 778 sed -n "s/^>//p" | while read shortsha1 rest 779 do 780 if test t != "$PRESERVE_MERGES" 781 then 782 echo "pick$shortsha1$rest" >> "$TODO" 783 else 784 sha1=$(git rev-parse $shortsha1) 785 if test -z "$REBASE_ROOT" 786 then 787 preserve=t 788 for p in$(git rev-list --parents -1 $sha1 | cut -d' ' -s -f2-) 789 do 790 if test -f "$REWRITTEN"/$p-a \($p!=$ONTO-o$sha1=$first_after_upstream\) 791 then 792 preserve=f 793 fi 794 done 795 else 796 preserve=f 797 fi 798 if test f = "$preserve" 799 then 800 touch "$REWRITTEN"/$sha1 801 echo "pick$shortsha1$rest" >> "$TODO" 802 fi 803 fi 804 done 805 806 # Watch for commits that been dropped by --cherry-pick 807 if test t = "$PRESERVE_MERGES" 808 then 809 mkdir "$DROPPED" 810 # Save all non-cherry-picked changes 811 git rev-list$REVISIONS--left-right --cherry-pick | \ 812 sed -n "s/^>//p" > "$DOTEST"/not-cherry-picks 813 # Now all commits and note which ones are missing in 814 # not-cherry-picks and hence being dropped 815 git rev-list$REVISIONS| 816 while read rev 817 do 818 if test -f "$REWRITTEN"/$rev-a "$(sane_grep "$rev" "$DOTEST"/not-cherry-picks)" = "" 819 then 820 # Use -f2 because if rev-list is telling us this commit is 821 # not worthwhile, we don't want to track its multiple heads, 822# just the history of its first-parent for others that will 823# be rebasing on top of it 824 git rev-list --parents -1$rev| cut -d' '-s -f2>"$DROPPED"/$rev 825 short=$(git rev-list -1 --abbrev-commit --abbrev=7 $rev) 826 sane_grep -v"^[a-z][a-z]*$short"<"$TODO">"${TODO}2";mv"${TODO}2""$TODO" 827rm"$REWRITTEN"/$rev 828fi 829done 830fi 831 832test -s"$TODO"||echo noop >>"$TODO" 833cat>>"$TODO"<< EOF 834 835# Rebase$SHORTREVISIONSonto$SHORTONTO 836# 837# Commands: 838# p, pick = use commit 839# r, reword = use commit, but edit the commit message 840# e, edit = use commit, but stop for amending 841# s, squash = use commit, but meld into previous commit 842# f, fixup = like "squash", but discard this commit's log message 843# 844# If you remove a line here THAT COMMIT WILL BE LOST. 845# However, if you remove everything, the rebase will be aborted. 846# 847EOF 848 849 has_action "$TODO"|| 850 die_abort "Nothing to do" 851 852cp"$TODO""$TODO".backup 853 git_editor "$TODO"|| 854 die "Could not execute editor" 855 856 has_action "$TODO"|| 857 die_abort "Nothing to do" 858 859test -d"$REWRITTEN"|| skip_unnecessary_picks 860 861 git update-ref ORIG_HEAD $HEAD 862 output git checkout $ONTO&& do_rest 863;; 864esac 865shift 866done