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