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# The file containing rebase commands, comments, and empty lines. 14# This file is created by "git rebase -i" then edited by the user. As 15# the lines are processed, they are removed from the front of this 16# file and written to the tail of $done. 17todo="$state_dir"/git-rebase-todo 18 19# The rebase command lines that have already been processed. A line 20# is moved here when it is first handled, before any associated user 21# actions. 22done="$state_dir"/done 23 24# The commit message that is planned to be used for any changes that 25# need to be committed following a user interaction. 26msg="$state_dir"/message 27 28# The file into which is accumulated the suggested commit message for 29# squash/fixup commands. When the first of a series of squash/fixups 30# is seen, the file is created and the commit message from the 31# previous commit and from the first squash/fixup commit are written 32# to it. The commit message for each subsequent squash/fixup commit 33# is appended to the file as it is processed. 34# 35# The first line of the file is of the form 36# # This is a combination of $count commits. 37# where $count is the number of commits whose messages have been 38# written to the file so far (including the initial "pick" commit). 39# Each time that a commit message is processed, this line is read and 40# updated. It is deleted just before the combined commit is made. 41squash_msg="$state_dir"/message-squash 42 43# If the current series of squash/fixups has not yet included a squash 44# command, then this file exists and holds the commit message of the 45# original "pick" commit. (If the series ends without a "squash" 46# command, then this can be used as the commit message of the combined 47# commit without opening the editor.) 48fixup_msg="$state_dir"/message-fixup 49 50# $rewritten is the name of a directory containing files for each 51# commit that is reachable by at least one merge base of $head and 52# $upstream. They are not necessarily rewritten, but their children 53# might be. This ensures that commits on merged, but otherwise 54# unrelated side branches are left alone. (Think "X" in the man page's 55# example.) 56rewritten="$state_dir"/rewritten 57 58dropped="$state_dir"/dropped 59 60end="$state_dir"/end 61msgnum="$state_dir"/msgnum 62 63# A script to set the GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and 64# GIT_AUTHOR_DATE that will be used for the commit that is currently 65# being rebased. 66author_script="$state_dir"/author-script 67 68# When an "edit" rebase command is being processed, the SHA1 of the 69# commit to be edited is recorded in this file. When "git rebase 70# --continue" is executed, if there are any staged changes then they 71# will be amended to the HEAD commit, but only provided the HEAD 72# commit is still the commit to be edited. When any other rebase 73# command is processed, this file is deleted. 74amend="$state_dir"/amend 75 76# For the post-rewrite hook, we make a list of rewritten commits and 77# their new sha1s. The rewritten-pending list keeps the sha1s of 78# commits that have been processed, but not committed yet, 79# e.g. because they are waiting for a 'squash' command. 80rewritten_list="$state_dir"/rewritten-list 81rewritten_pending="$state_dir"/rewritten-pending 82 83strategy_args= 84iftest -n"$do_merge" 85then 86 strategy_args=${strategy:+--strategy=$strategy} 87eval' 88 for strategy_opt in '"$strategy_opts"' 89 do 90 strategy_args="$strategy_args-X$(git rev-parse --sq-quote "${strategy_opt#--}")" 91 done 92 ' 93fi 94 95GIT_CHERRY_PICK_HELP="$resolvemsg" 96export GIT_CHERRY_PICK_HELP 97 98comment_char=$(git config --get core.commentchar 2>/dev/null | cut -c1) 99:${comment_char:=#} 100 101warn () { 102printf'%s\n'"$*">&2 103} 104 105# Output the commit message for the specified commit. 106commit_message () { 107 git cat-file commit "$1"|sed"1,/^$/d" 108} 109 110orig_reflog_action="$GIT_REFLOG_ACTION" 111 112comment_for_reflog () { 113case"$orig_reflog_action"in 114''|rebase*) 115 GIT_REFLOG_ACTION="rebase -i ($1)" 116export GIT_REFLOG_ACTION 117;; 118esac 119} 120 121last_count= 122mark_action_done () { 123sed-e1q <"$todo">>"$done" 124sed-e1d <"$todo">>"$todo".new 125mv-f"$todo".new "$todo" 126 new_count=$(git stripspace --strip-comments <"$done" | wc -l) 127echo$new_count>"$msgnum" 128 total=$(($new_count + $(git stripspace --strip-comments <"$todo" | wc -l))) 129echo$total>"$end" 130iftest"$last_count"!="$new_count" 131then 132 last_count=$new_count 133printf"Rebasing (%d/%d)\r"$new_count $total 134test -z"$verbose"||echo 135fi 136} 137 138append_todo_help () { 139 git stripspace --comment-lines>>"$todo"<<\EOF 140 141Commands: 142 p, pick = use commit 143 r, reword = use commit, but edit the commit message 144 e, edit = use commit, but stop for amending 145 s, squash = use commit, but meld into previous commit 146 f, fixup = like "squash", but discard this commit's log message 147 x, exec = run command (the rest of the line) using shell 148 149These lines can be re-ordered; they are executed from top to bottom. 150 151If you remove a line here THAT COMMIT WILL BE LOST. 152EOF 153} 154 155make_patch () { 156 sha1_and_parents="$(git rev-list --parents -1 "$1")" 157 case "$sha1_and_parents" in 158 ?*''?*''?*) 159 git diff --cc$sha1_and_parents 160 ;; 161 ?*''?*) 162 git diff-tree -p "$1^!" 163 ;; 164 *) 165 echo "Root commit" 166 ;; 167 esac > "$state_dir"/patch 168 test -f "$msg" || 169 commit_message "$1" > "$msg" 170 test -f "$author_script" || 171 get_author_ident_from_commit "$1" > "$author_script" 172} 173 174die_with_patch () { 175 echo "$1" > "$state_dir"/stopped-sha 176 make_patch "$1" 177 git rerere 178 die "$2" 179} 180 181exit_with_patch () { 182 echo "$1" > "$state_dir"/stopped-sha 183 make_patch$1 184 git rev-parse --verify HEAD > "$amend" 185 warn "You can amend the commit now, with" 186 warn 187 warn " git commit --amend" 188 warn 189 warn "Once you are satisfied with your changes, run" 190 warn 191 warn " git rebase --continue" 192 warn 193 exit$2 194} 195 196die_abort () { 197 rm -rf "$state_dir" 198 die "$1" 199} 200 201has_action () { 202 test -n "$(git stripspace --strip-comments <"$1")" 203} 204 205is_empty_commit() { 206 tree=$(git rev-parse -q --verify "$1"^{tree} 2>/dev/null || 207 die "$1: not a commit that can be picked") 208 ptree=$(git rev-parse -q --verify "$1"^^{tree} 2>/dev/null || 209 ptree=4b825dc642cb6eb9a060e54bf8d69288fbee4904) 210 test "$tree" = "$ptree" 211} 212 213is_merge_commit() 214{ 215 git rev-parse --verify --quiet "$1"^2 >/dev/null 2>&1 216} 217 218# Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and 219# GIT_AUTHOR_DATE exported from the current environment. 220do_with_author () { 221 ( 222 export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE 223 "$@" 224 ) 225} 226 227git_sequence_editor () { 228 if test -z "$GIT_SEQUENCE_EDITOR" 229 then 230 GIT_SEQUENCE_EDITOR="$(git config sequence.editor)" 231 if [ -z "$GIT_SEQUENCE_EDITOR" ] 232 then 233 GIT_SEQUENCE_EDITOR="$(git var GIT_EDITOR)" || return $? 234 fi 235 fi 236 237 eval "$GIT_SEQUENCE_EDITOR" '"$@"' 238} 239 240pick_one () { 241 ff=--ff 242 243 case "$1" in -n) sha1=$2; ff= ;; *) sha1=$1;; esac 244 case "$force_rebase" in '') ;; ?*) ff= ;; esac 245 output git rev-parse --verify$sha1|| die "Invalid commit name:$sha1" 246 247 if is_empty_commit "$sha1" 248 then 249 empty_args="--allow-empty" 250 fi 251 252 test -d "$rewritten" && 253 pick_one_preserving_merges "$@" && return 254 output eval git cherry-pick "$strategy_args"$empty_args$ff"$@" 255} 256 257pick_one_preserving_merges () { 258 fast_forward=t 259 case "$1" in 260 -n) 261 fast_forward=f 262 sha1=$2 263 ;; 264 *) 265 sha1=$1 266 ;; 267 esac 268 sha1=$(git rev-parse $sha1) 269 270 if test -f "$state_dir"/current-commit 271 then 272 if test "$fast_forward" = t 273 then 274 while read current_commit 275 do 276 git rev-parse HEAD > "$rewritten"/$current_commit 277 done <"$state_dir"/current-commit 278 rm "$state_dir"/current-commit || 279 die "Cannot write current commit's replacement sha1" 280 fi 281 fi 282 283 echo$sha1>> "$state_dir"/current-commit 284 285 # rewrite parents; if none were rewritten, we can fast-forward. 286 new_parents= 287 pend="$(git rev-list --parents -1 $sha1 | cut -d' ' -s -f2-)" 288 if test "$pend" = "" 289 then 290 pend=" root" 291 fi 292 while [ "$pend" != "" ] 293 do 294 p=$(expr "$pend" : ' \([^ ]*\)') 295 pend="${pend# $p}" 296 297 if test -f "$rewritten"/$p 298 then 299 new_p=$(cat "$rewritten"/$p) 300 301 # If the todo reordered commits, and our parent is marked for 302 # rewriting, but hasn't been gotten to yet, assume the user meant to 303 # drop it on top of the current HEAD 304 if test -z "$new_p" 305 then 306 new_p=$(git rev-parse HEAD) 307 fi 308 309 test$p!=$new_p&& fast_forward=f 310 case "$new_parents" in 311 *$new_p*) 312 ;; # do nothing; that parent is already there 313 *) 314 new_parents="$new_parents $new_p" 315 ;; 316 esac 317 else 318 if test -f "$dropped"/$p 319 then 320 fast_forward=f 321 replacement="$(cat "$dropped"/$p)" 322 test -z "$replacement" && replacement=root 323 pend="$replacement$pend" 324 else 325 new_parents="$new_parents $p" 326 fi 327 fi 328 done 329 case$fast_forwardin 330 t) 331 output warn "Fast-forward to $sha1" 332 output git reset --hard$sha1|| 333 die "Cannot fast-forward to $sha1" 334 ;; 335 f) 336 first_parent=$(expr "$new_parents" : ' \([^ ]*\)') 337 338 if [ "$1" != "-n" ] 339 then 340 # detach HEAD to current parent 341 output git checkout$first_parent2> /dev/null || 342 die "Cannot move HEAD to $first_parent" 343 fi 344 345 case "$new_parents" in 346 ' '*' '*) 347 test "a$1" = a-n && die "Refusing to squash a merge:$sha1" 348 349 # redo merge 350 author_script_content=$(get_author_ident_from_commit $sha1) 351 eval "$author_script_content" 352 msg_content="$(commit_message $sha1)" 353 # No point in merging the first parent, that's HEAD 354 new_parents=${new_parents# $first_parent} 355 merge_args="--no-log --no-ff" 356 if ! do_with_author output eval \ 357 'git merge$merge_args$strategy_args-m "$msg_content"$new_parents' 358 then 359 printf "%s\n" "$msg_content" > "$GIT_DIR"/MERGE_MSG 360 die_with_patch$sha1"Error redoing merge $sha1" 361 fi 362 echo "$sha1 $(git rev-parse HEAD^0)" >> "$rewritten_list" 363 ;; 364 *) 365 output eval git cherry-pick "$strategy_args" "$@" || 366 die_with_patch$sha1"Could not pick $sha1" 367 ;; 368 esac 369 ;; 370 esac 371} 372 373nth_string () { 374 case "$1" in 375 *1[0-9]|*[04-9]) echo "$1"th;; 376 *1) echo "$1"st;; 377 *2) echo "$1"nd;; 378 *3) echo "$1"rd;; 379 esac 380} 381 382update_squash_messages () { 383 if test -f "$squash_msg"; then 384 mv "$squash_msg" "$squash_msg".bak || exit 385 count=$(($(sed -n \ 386 -e "1s/^. This is a combination of \(.*\) commits\./\1/p" \ 387 -e "q" < "$squash_msg".bak)+1)) 388 { 389 printf '%s\n' "$comment_char This is a combination of $count commits." 390 sed -e 1d -e '2,/^./{ 391 /^$/d 392 }' <"$squash_msg".bak 393 } >"$squash_msg" 394 else 395 commit_message HEAD > "$fixup_msg" || die "Cannot write$fixup_msg" 396 count=2 397 { 398 printf '%s\n' "$comment_char This is a combination of 2 commits." 399 printf '%s\n' "$comment_char The first commit's message is:" 400 echo 401 cat "$fixup_msg" 402 } >"$squash_msg" 403 fi 404 case$1in 405 squash) 406 rm -f "$fixup_msg" 407 echo 408 printf '%s\n' "$comment_charThis is the$(nth_string $count)commit message:" 409 echo 410 commit_message$2 411 ;; 412 fixup) 413 echo 414 printf '%s\n' "$comment_charThe$(nth_string $count)commit message will be skipped:" 415 echo 416 # Change the space after the comment character to TAB: 417 commit_message$2| git stripspace --comment-lines | sed -e 's/ / /' 418 ;; 419 esac >>"$squash_msg" 420} 421 422peek_next_command () { 423 git stripspace --strip-comments <"$todo" | sed -n -e 's/ .*//p' -e q 424} 425 426# A squash/fixup has failed. Prepare the long version of the squash 427# commit message, then die_with_patch. This code path requires the 428# user to edit the combined commit message for all commits that have 429# been squashed/fixedup so far. So also erase the old squash 430# messages, effectively causing the combined commit to be used as the 431# new basis for any further squash/fixups. Args: sha1 rest 432die_failed_squash() { 433 mv "$squash_msg" "$msg" || exit 434 rm -f "$fixup_msg" 435 cp "$msg" "$GIT_DIR"/MERGE_MSG || exit 436 warn 437 warn "Could not apply$1...$2" 438 die_with_patch$1"" 439} 440 441flush_rewritten_pending() { 442 test -s "$rewritten_pending" || return 443 newsha1="$(git rev-parse HEAD^0)" 444 sed "s/$/$newsha1/" < "$rewritten_pending" >> "$rewritten_list" 445 rm -f "$rewritten_pending" 446} 447 448record_in_rewritten() { 449 oldsha1="$(git rev-parse $1)" 450 echo "$oldsha1" >> "$rewritten_pending" 451 452 case "$(peek_next_command)" in 453 squash|s|fixup|f) 454 ;; 455 *) 456 flush_rewritten_pending 457 ;; 458 esac 459} 460 461do_pick () { 462 if test "$(git rev-parse HEAD)" = "$squash_onto" 463 then 464 # Set the correct commit message and author info on the 465 # sentinel root before cherry-picking the original changes 466 # without committing (-n). Finally, update the sentinel again 467 # to include these changes. If the cherry-pick results in a 468 # conflict, this means our behaviour is similar to a standard 469 # failed cherry-pick during rebase, with a dirty index to 470 # resolve before manually running git commit --amend then git 471 # rebase --continue. 472 git commit --allow-empty --allow-empty-message --amend \ 473 --no-post-rewrite -n -q -C$1&& 474 pick_one -n$1&& 475 git commit --allow-empty --allow-empty-message \ 476 --amend --no-post-rewrite -n -q -C$1|| 477 die_with_patch$1"Could not apply$1...$2" 478 else 479 pick_one$1|| 480 die_with_patch$1"Could not apply$1...$2" 481 fi 482} 483 484do_next () { 485 rm -f "$msg" "$author_script" "$amend" || exit 486 read -r command sha1 rest < "$todo" 487 case "$command" in 488 "$comment_char"*|''|noop) 489 mark_action_done 490 ;; 491 pick|p) 492 comment_for_reflog pick 493 494 mark_action_done 495 do_pick$sha1"$rest" 496 record_in_rewritten$sha1 497 ;; 498 reword|r) 499 comment_for_reflog reword 500 501 mark_action_done 502 do_pick$sha1"$rest" 503 git commit --amend --no-post-rewrite || { 504 warn "Could not amend commit after successfully picking$sha1...$rest" 505 warn "This is most likely due to an empty commit message, or the pre-commit hook" 506 warn "failed. If the pre-commit hook failed, you may need to resolve the issue before" 507 warn "you are able to reword the commit." 508 exit_with_patch$sha11 509 } 510 record_in_rewritten$sha1 511 ;; 512 edit|e) 513 comment_for_reflog edit 514 515 mark_action_done 516 do_pick$sha1"$rest" 517 warn "Stopped at$sha1...$rest" 518 exit_with_patch$sha10 519 ;; 520 squash|s|fixup|f) 521 case "$command" in 522 squash|s) 523 squash_style=squash 524 ;; 525 fixup|f) 526 squash_style=fixup 527 ;; 528 esac 529 comment_for_reflog$squash_style 530 531 test -f "$done" && has_action "$done" || 532 die "Cannot '$squash_style' without a previous commit" 533 534 mark_action_done 535 update_squash_messages$squash_style$sha1 536 author_script_content=$(get_author_ident_from_commit HEAD) 537 echo "$author_script_content" > "$author_script" 538 eval "$author_script_content" 539 if ! pick_one -n$sha1 540 then 541 git rev-parse --verify HEAD >"$amend" 542 die_failed_squash$sha1"$rest" 543 fi 544 case "$(peek_next_command)" in 545 squash|s|fixup|f) 546 # This is an intermediate commit; its message will only be 547 # used in case of trouble. So use the long version: 548 do_with_author output git commit --amend --no-verify -F "$squash_msg" || 549 die_failed_squash$sha1"$rest" 550 ;; 551 *) 552 # This is the final command of this squash/fixup group 553 if test -f "$fixup_msg" 554 then 555 do_with_author git commit --amend --no-verify -F "$fixup_msg" || 556 die_failed_squash$sha1"$rest" 557 else 558 cp "$squash_msg" "$GIT_DIR"/SQUASH_MSG || exit 559 rm -f "$GIT_DIR"/MERGE_MSG 560 do_with_author git commit --amend --no-verify -F "$GIT_DIR"/SQUASH_MSG -e || 561 die_failed_squash$sha1"$rest" 562 fi 563 rm -f "$squash_msg" "$fixup_msg" 564 ;; 565 esac 566 record_in_rewritten$sha1 567 ;; 568 x|"exec") 569 read -r command rest < "$todo" 570 mark_action_done 571 printf 'Executing: %s\n' "$rest" 572 # "exec" command doesn't take a sha1 in the todo-list. 573# => can't just use $sha1 here. 574 git rev-parse --verify HEAD >"$state_dir"/stopped-sha 575${SHELL:-@SHELL_PATH@}-c"$rest"# Actual execution 576 status=$? 577# Run in subshell because require_clean_work_tree can die. 578 dirty=f 579(require_clean_work_tree "rebase"2>/dev/null) || dirty=t 580iftest"$status"-ne0 581then 582 warn "Execution failed:$rest" 583test"$dirty"= f || 584 warn "and made changes to the index and/or the working tree" 585 586 warn "You can fix the problem, and then run" 587 warn 588 warn " git rebase --continue" 589 warn 590iftest$status-eq127# command not found 591then 592 status=1 593fi 594exit"$status" 595eliftest"$dirty"= t 596then 597 warn "Execution succeeded:$rest" 598 warn "but left changes to the index and/or the working tree" 599 warn "Commit or stash your changes, and then run" 600 warn 601 warn " git rebase --continue" 602 warn 603exit1 604fi 605;; 606*) 607 warn "Unknown command:$command$sha1$rest" 608 fixtodo="Please fix this using 'git rebase --edit-todo'." 609if git rev-parse --verify -q"$sha1">/dev/null 610then 611 die_with_patch $sha1"$fixtodo" 612else 613 die "$fixtodo" 614fi 615;; 616esac 617test -s"$todo"&&return 618 619 comment_for_reflog finish && 620 newhead=$(git rev-parse HEAD)&& 621case$head_namein 622 refs/*) 623 message="$GIT_REFLOG_ACTION:$head_nameonto$onto"&& 624 git update-ref -m"$message"$head_name $newhead $orig_head&& 625 git symbolic-ref \ 626-m"$GIT_REFLOG_ACTION: returning to$head_name" \ 627 HEAD $head_name 628;; 629esac&& { 630test!-f"$state_dir"/verbose || 631 git diff-tree --stat$orig_head..HEAD 632} && 633{ 634test -s"$rewritten_list"&& 635 git notes copy --for-rewrite=rebase <"$rewritten_list"|| 636 true # we don't care if this copying failed 637} && 638iftest -x"$GIT_DIR"/hooks/post-rewrite&& 639test -s"$rewritten_list";then 640"$GIT_DIR"/hooks/post-rewrite rebase <"$rewritten_list" 641 true # we don't care if this hook failed 642fi&& 643 warn "Successfully rebased and updated$head_name." 644 645return1# not failure; just to break the do_rest loop 646} 647 648# can only return 0, when the infinite loop breaks 649do_rest () { 650while: 651do 652 do_next ||break 653done 654} 655 656# skip picking commits whose parents are unchanged 657skip_unnecessary_picks () { 658 fd=3 659whileread -r command rest 660do 661# fd=3 means we skip the command 662case"$fd,$command"in 6633,pick|3,p) 664# pick a commit whose parent is current $onto -> skip 665 sha1=${rest%% *} 666case"$(git rev-parse --verify --quiet "$sha1"^)"in 667"$onto"*) 668 onto=$sha1 669;; 670*) 671 fd=1 672;; 673esac 674;; 6753,"$comment_char"*|3,) 676# copy comments 677;; 678*) 679 fd=1 680;; 681esac 682printf'%s\n'"$command${rest:+ }$rest">&$fd 683done<"$todo">"$todo.new"3>>"$done"&& 684mv-f"$todo".new "$todo"&& 685case"$(peek_next_command)"in 686 squash|s|fixup|f) 687 record_in_rewritten "$onto" 688;; 689esac|| 690 die "Could not skip unnecessary pick commands" 691} 692 693transform_todo_ids () { 694whileread -r command rest 695do 696case"$command"in 697"$comment_char"* |exec) 698# Be careful for oddball commands like 'exec' 699# that do not have a SHA-1 at the beginning of $rest. 700;; 701*) 702 sha1=$(git rev-parse --verify --quiet "$@" ${rest%% *})&& 703 rest="$sha1${rest#* }" 704;; 705esac 706printf'%s\n'"$command${rest:+ }$rest" 707done<"$todo">"$todo.new"&& 708mv-f"$todo.new""$todo" 709} 710 711expand_todo_ids() { 712 transform_todo_ids 713} 714 715collapse_todo_ids() { 716 transform_todo_ids --short=7 717} 718 719# Rearrange the todo list that has both "pick sha1 msg" and 720# "pick sha1 fixup!/squash! msg" appears in it so that the latter 721# comes immediately after the former, and change "pick" to 722# "fixup"/"squash". 723rearrange_squash () { 724# extract fixup!/squash! lines and resolve any referenced sha1's 725whileread -r pick sha1 message 726do 727case"$message"in 728"squash! "*|"fixup! "*) 729 action="${message%%!*}" 730 rest=$message 731 prefix= 732# skip all squash! or fixup! (but save for later) 733while: 734do 735case"$rest"in 736"squash! "*|"fixup! "*) 737 prefix="$prefix${rest%%!*}," 738 rest="${rest#*! }" 739;; 740*) 741break 742;; 743esac 744done 745echo"$sha1$action$prefix$rest" 746# if it's a single word, try to resolve to a full sha1 and 747# emit a second copy. This allows us to match on both message 748# and on sha1 prefix 749iftest"${rest#* }"="$rest";then 750 fullsha="$(git rev-parse -q --verify "$rest" 2>/dev/null)" 751iftest -n"$fullsha";then 752# prefix the action to uniquely identify this line as 753# intended for full sha1 match 754echo"$sha1+$action$prefix$fullsha" 755fi 756fi 757esac 758done>"$1.sq"<"$1" 759test -s"$1.sq"||return 760 761 used= 762whileread -r pick sha1 message 763do 764case"$used"in 765*"$sha1"*)continue;; 766esac 767printf'%s\n'"$pick$sha1$message" 768 used="$used$sha1" 769whileread -r squash action msg_prefix msg_content 770do 771case"$used"in 772*"$squash"*)continue;; 773esac 774 emit=0 775case"$action"in 776+*) 777 action="${action#+}" 778# full sha1 prefix test 779case"$msg_content"in"$sha1"*) emit=1;;esac;; 780*) 781# message prefix test 782case"$message"in"$msg_content"*) emit=1;;esac;; 783esac 784iftest$emit=1;then 785 real_prefix=$(echo "$msg_prefix" | sed "s/,/! /g") 786printf'%s\n'"$action$squash${real_prefix}$msg_content" 787 used="$used$squash" 788fi 789done<"$1.sq" 790done>"$1.rearranged"<"$1" 791cat"$1.rearranged">"$1" 792rm-f"$1.sq""$1.rearranged" 793} 794 795# Add commands after a pick or after a squash/fixup serie 796# in the todo list. 797add_exec_commands () { 798{ 799 first=t 800whileread -r insn rest 801do 802case$insnin 803 pick) 804test -n"$first"|| 805printf"%s""$cmd" 806;; 807esac 808printf"%s %s\n""$insn""$rest" 809 first= 810done 811printf"%s""$cmd" 812} <"$1">"$1.new"&& 813mv"$1.new""$1" 814} 815 816case"$action"in 817continue) 818# do we have anything to commit? 819if git diff-index --cached --quiet HEAD -- 820then 821: Nothing to commit -- skip this 822else 823if!test -f"$author_script" 824then 825 die "You have staged changes in your working tree. If these changes are meant to be 826squashed into the previous commit, run: 827 828 git commit --amend 829 830If they are meant to go into a new commit, run: 831 832 git commit 833 834In both case, once you're done, continue with: 835 836 git rebase --continue 837" 838fi 839 . "$author_script"|| 840 die "Error trying to find the author identity to amend commit" 841iftest -f"$amend" 842then 843 current_head=$(git rev-parse --verify HEAD) 844test"$current_head"=$(cat "$amend")|| 845 die "\ 846You have uncommitted changes in your working tree. Please, commit them 847first and then run 'git rebase --continue' again." 848 do_with_author git commit --amend --no-verify -F"$msg"-e|| 849 die "Could not commit staged changes." 850else 851 do_with_author git commit --no-verify -F"$msg"-e|| 852 die "Could not commit staged changes." 853fi 854fi 855 856 record_in_rewritten "$(cat "$state_dir"/stopped-sha)" 857 858 require_clean_work_tree "rebase" 859 do_rest 860return0 861;; 862skip) 863 git rerere clear 864 865 do_rest 866return0 867;; 868edit-todo) 869 git stripspace --strip-comments<"$todo">"$todo".new 870mv-f"$todo".new "$todo" 871 collapse_todo_ids 872 append_todo_help 873 git stripspace --comment-lines>>"$todo"<<\EOF 874 875You are editing the todo file of an ongoing interactive rebase. 876To continue rebase after editing, run: 877 git rebase --continue 878 879EOF 880 881 git_sequence_editor "$todo"|| 882 die "Could not execute editor" 883 expand_todo_ids 884 885exit 886;; 887esac 888 889git var GIT_COMMITTER_IDENT >/dev/null || 890 die "You need to set your committer info first" 891 892comment_for_reflog start 893 894iftest!-z"$switch_to" 895then 896 GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout$switch_to" 897 output git checkout "$switch_to"--|| 898 die "Could not checkout$switch_to" 899 900 comment_for_reflog start 901fi 902 903orig_head=$(git rev-parse --verify HEAD)|| die "No HEAD?" 904mkdir-p"$state_dir"|| die "Could not create temporary$state_dir" 905 906: >"$state_dir"/interactive || die "Could not mark as interactive" 907write_basic_state 908iftest t ="$preserve_merges" 909then 910iftest -z"$rebase_root" 911then 912mkdir"$rewritten"&& 913for c in$(git merge-base --all $orig_head $upstream) 914do 915echo$onto>"$rewritten"/$c|| 916 die "Could not init rewritten commits" 917done 918else 919mkdir"$rewritten"&& 920echo$onto>"$rewritten"/root || 921 die "Could not init rewritten commits" 922fi 923# No cherry-pick because our first pass is to determine 924# parents to rewrite and skipping dropped commits would 925# prematurely end our probe 926 merges_option= 927else 928 merges_option="--no-merges --cherry-pick" 929fi 930 931shorthead=$(git rev-parse --short $orig_head) 932shortonto=$(git rev-parse --short $onto) 933iftest -z"$rebase_root" 934# this is now equivalent to ! -z "$upstream" 935then 936 shortupstream=$(git rev-parse --short $upstream) 937 revisions=$upstream...$orig_head 938 shortrevisions=$shortupstream..$shorthead 939else 940 revisions=$onto...$orig_head 941 shortrevisions=$shorthead 942fi 943git rev-list$merges_option--pretty=oneline --abbrev-commit \ 944--abbrev=7--reverse --left-right --topo-order \ 945$revisions| \ 946sed-n"s/^>//p"| 947whileread -r shortsha1 rest 948do 949 950iftest -z"$keep_empty"&& is_empty_commit $shortsha1&& ! is_merge_commit $shortsha1 951then 952 comment_out="$comment_char" 953else 954 comment_out= 955fi 956 957iftest t !="$preserve_merges" 958then 959printf'%s\n'"${comment_out}pick$shortsha1$rest">>"$todo" 960else 961 sha1=$(git rev-parse $shortsha1) 962iftest -z"$rebase_root" 963then 964 preserve=t 965for p in$(git rev-list --parents -1 $sha1 | cut -d' ' -s -f2-) 966do 967iftest -f"$rewritten"/$p 968then 969 preserve=f 970fi 971done 972else 973 preserve=f 974fi 975iftest f ="$preserve" 976then 977touch"$rewritten"/$sha1 978printf'%s\n'"${comment_out}pick$shortsha1$rest">>"$todo" 979fi 980fi 981done 982 983# Watch for commits that been dropped by --cherry-pick 984iftest t ="$preserve_merges" 985then 986mkdir"$dropped" 987# Save all non-cherry-picked changes 988 git rev-list$revisions--left-right --cherry-pick| \ 989sed-n"s/^>//p">"$state_dir"/not-cherry-picks 990# Now all commits and note which ones are missing in 991# not-cherry-picks and hence being dropped 992 git rev-list$revisions| 993whilereadrev 994do 995iftest -f"$rewritten"/$rev-a"$(sane_grep "$rev" "$state_dir"/not-cherry-picks)"="" 996then 997# Use -f2 because if rev-list is telling us this commit is 998# not worthwhile, we don't want to track its multiple heads, 999# just the history of its first-parent for others that will1000# be rebasing on top of it1001 git rev-list --parents -1$rev| cut -d' '-s -f2>"$dropped"/$rev1002 short=$(git rev-list -1 --abbrev-commit --abbrev=7 $rev)1003 sane_grep -v"^[a-z][a-z]*$short"<"$todo">"${todo}2";mv"${todo}2""$todo"1004rm"$rewritten"/$rev1005fi1006done1007fi10081009test -s"$todo"||echo noop >>"$todo"1010test -n"$autosquash"&& rearrange_squash "$todo"1011test -n"$cmd"&& add_exec_commands "$todo"10121013cat>>"$todo"<<EOF10141015$comment_charRebase$shortrevisionsonto$shortonto1016EOF1017append_todo_help1018git stripspace --comment-lines>>"$todo"<<\EOF10191020However,if you remove everything, the rebase will be aborted.10211022EOF10231024iftest -z"$keep_empty"1025then1026printf'%s\n'"$comment_charNote that empty commits are commented out">>"$todo"1027fi102810291030has_action "$todo"||1031 die_abort "Nothing to do"10321033cp"$todo""$todo".backup1034git_sequence_editor "$todo"||1035 die_abort "Could not execute editor"10361037has_action "$todo"||1038 die_abort "Nothing to do"10391040expand_todo_ids10411042test -d"$rewritten"||test -n"$force_rebase"|| skip_unnecessary_picks10431044GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout$onto_name"1045output git checkout $onto|| die_abort "could not detach HEAD"1046git update-ref ORIG_HEAD $orig_head1047do_rest