1# This shell script fragment is sourced by git-rebase to implement 2# its interactive mode. "git rebase --interactive" makes it easy 3# to fix up commits in the middle of a series and rearrange commits. 4# 5# Copyright (c) 2006 Johannes E. Schindelin 6# 7# The original idea comes from Eric W. Biederman, in 8# http://article.gmane.org/gmane.comp.version-control.git/22407 9# 10# The file containing rebase commands, comments, and empty lines. 11# This file is created by "git rebase -i" then edited by the user. As 12# the lines are processed, they are removed from the front of this 13# file and written to the tail of $done. 14todo="$state_dir"/git-rebase-todo 15 16# The rebase command lines that have already been processed. A line 17# is moved here when it is first handled, before any associated user 18# actions. 19done="$state_dir"/done 20 21# The commit message that is planned to be used for any changes that 22# need to be committed following a user interaction. 23msg="$state_dir"/message 24 25# The file into which is accumulated the suggested commit message for 26# squash/fixup commands. When the first of a series of squash/fixups 27# is seen, the file is created and the commit message from the 28# previous commit and from the first squash/fixup commit are written 29# to it. The commit message for each subsequent squash/fixup commit 30# is appended to the file as it is processed. 31# 32# The first line of the file is of the form 33# # This is a combination of $count commits. 34# where $count is the number of commits whose messages have been 35# written to the file so far (including the initial "pick" commit). 36# Each time that a commit message is processed, this line is read and 37# updated. It is deleted just before the combined commit is made. 38squash_msg="$state_dir"/message-squash 39 40# If the current series of squash/fixups has not yet included a squash 41# command, then this file exists and holds the commit message of the 42# original "pick" commit. (If the series ends without a "squash" 43# command, then this can be used as the commit message of the combined 44# commit without opening the editor.) 45fixup_msg="$state_dir"/message-fixup 46 47# $rewritten is the name of a directory containing files for each 48# commit that is reachable by at least one merge base of $head and 49# $upstream. They are not necessarily rewritten, but their children 50# might be. This ensures that commits on merged, but otherwise 51# unrelated side branches are left alone. (Think "X" in the man page's 52# example.) 53rewritten="$state_dir"/rewritten 54 55dropped="$state_dir"/dropped 56 57end="$state_dir"/end 58msgnum="$state_dir"/msgnum 59 60# A script to set the GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and 61# GIT_AUTHOR_DATE that will be used for the commit that is currently 62# being rebased. 63author_script="$state_dir"/author-script 64 65# When an "edit" rebase command is being processed, the SHA1 of the 66# commit to be edited is recorded in this file. When "git rebase 67# --continue" is executed, if there are any staged changes then they 68# will be amended to the HEAD commit, but only provided the HEAD 69# commit is still the commit to be edited. When any other rebase 70# command is processed, this file is deleted. 71amend="$state_dir"/amend 72 73# For the post-rewrite hook, we make a list of rewritten commits and 74# their new sha1s. The rewritten-pending list keeps the sha1s of 75# commits that have been processed, but not committed yet, 76# e.g. because they are waiting for a 'squash' command. 77rewritten_list="$state_dir"/rewritten-list 78rewritten_pending="$state_dir"/rewritten-pending 79 80# Work around Git for Windows' Bash whose "read" does not strip CRLF 81# and leaves CR at the end instead. 82cr=$(printf "\015") 83 84strategy_args= 85iftest -n"$do_merge" 86then 87 strategy_args=${strategy:+--strategy=$strategy} 88eval' 89 for strategy_opt in '"$strategy_opts"' 90 do 91 strategy_args="$strategy_args-X$(git rev-parse --sq-quote "${strategy_opt#--}")" 92 done 93 ' 94fi 95 96GIT_CHERRY_PICK_HELP="$resolvemsg" 97export GIT_CHERRY_PICK_HELP 98 99comment_char=$(git config --get core.commentchar 2>/dev/null | cut -c1) 100:${comment_char:=#} 101 102warn () { 103printf'%s\n'"$*">&2 104} 105 106# Output the commit message for the specified commit. 107commit_message () { 108 git cat-file commit "$1"|sed"1,/^$/d" 109} 110 111orig_reflog_action="$GIT_REFLOG_ACTION" 112 113comment_for_reflog () { 114case"$orig_reflog_action"in 115''|rebase*) 116 GIT_REFLOG_ACTION="rebase -i ($1)" 117export GIT_REFLOG_ACTION 118;; 119esac 120} 121 122last_count= 123mark_action_done () { 124sed-e1q <"$todo">>"$done" 125sed-e1d <"$todo">>"$todo".new 126mv-f"$todo".new "$todo" 127 new_count=$(git stripspace --strip-comments <"$done" | wc -l) 128echo$new_count>"$msgnum" 129 total=$(($new_count + $(git stripspace --strip-comments <"$todo" | wc -l))) 130echo$total>"$end" 131iftest"$last_count"!="$new_count" 132then 133 last_count=$new_count 134printf"Rebasing (%d/%d)\r"$new_count $total 135test -z"$verbose"||echo 136fi 137} 138 139# Put the last action marked done at the beginning of the todo list 140# again. If there has not been an action marked done yet, leave the list of 141# items on the todo list unchanged. 142reschedule_last_action () { 143tail-n1"$done"|cat-"$todo">"$todo".new 144sed-e \$d<"$done">"$done".new 145mv-f"$todo".new "$todo" 146mv-f"$done".new "$done" 147} 148 149append_todo_help () { 150 git stripspace --comment-lines>>"$todo"<<\EOF 151 152Commands: 153 p, pick = use commit 154 r, reword = use commit, but edit the commit message 155 e, edit = use commit, but stop for amending 156 s, squash = use commit, but meld into previous commit 157 f, fixup = like "squash", but discard this commit's log message 158 x, exec = run command (the rest of the line) using shell 159 d, drop = remove commit 160 161These lines can be re-ordered; they are executed from top to bottom. 162 163EOF 164 if test$(get_missing_commit_check_level)= error 165 then 166 git stripspace --comment-lines >>"$todo" <<\EOF 167Do not remove any line. Use 'drop' explicitly to remove a commit. 168EOF 169 else 170 git stripspace --comment-lines >>"$todo" <<\EOF 171If you remove a line here THAT COMMIT WILL BE LOST. 172EOF 173 fi 174} 175 176make_patch () { 177 sha1_and_parents="$(git rev-list --parents -1 "$1")" 178 case "$sha1_and_parents" in 179 ?*''?*''?*) 180 git diff --cc$sha1_and_parents 181 ;; 182 ?*''?*) 183 git diff-tree -p "$1^!" 184 ;; 185 *) 186 echo "Root commit" 187 ;; 188 esac > "$state_dir"/patch 189 test -f "$msg" || 190 commit_message "$1" > "$msg" 191 test -f "$author_script" || 192 get_author_ident_from_commit "$1" > "$author_script" 193} 194 195die_with_patch () { 196 echo "$1" > "$state_dir"/stopped-sha 197 make_patch "$1" 198 git rerere 199 die "$2" 200} 201 202exit_with_patch () { 203 echo "$1" > "$state_dir"/stopped-sha 204 make_patch$1 205 git rev-parse --verify HEAD > "$amend" 206 gpg_sign_opt_quoted=${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")} 207 warn "You can amend the commit now, with" 208 warn 209 warn " git commit --amend$gpg_sign_opt_quoted" 210 warn 211 warn "Once you are satisfied with your changes, run" 212 warn 213 warn " git rebase --continue" 214 warn 215 exit$2 216} 217 218die_abort () { 219 apply_autostash 220 rm -rf "$state_dir" 221 die "$1" 222} 223 224has_action () { 225 test -n "$(git stripspace --strip-comments <"$1")" 226} 227 228is_empty_commit() { 229 tree=$(git rev-parse -q --verify "$1"^{tree} 2>/dev/null || 230 die "$1: not a commit that can be picked") 231 ptree=$(git rev-parse -q --verify "$1"^^{tree} 2>/dev/null || 232 ptree=4b825dc642cb6eb9a060e54bf8d69288fbee4904) 233 test "$tree" = "$ptree" 234} 235 236is_merge_commit() 237{ 238 git rev-parse --verify --quiet "$1"^2 >/dev/null 2>&1 239} 240 241# Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and 242# GIT_AUTHOR_DATE exported from the current environment. 243do_with_author () { 244 ( 245 export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE 246 "$@" 247 ) 248} 249 250git_sequence_editor () { 251 if test -z "$GIT_SEQUENCE_EDITOR" 252 then 253 GIT_SEQUENCE_EDITOR="$(git config sequence.editor)" 254 if [ -z "$GIT_SEQUENCE_EDITOR" ] 255 then 256 GIT_SEQUENCE_EDITOR="$(git var GIT_EDITOR)" || return $? 257 fi 258 fi 259 260 eval "$GIT_SEQUENCE_EDITOR" '"$@"' 261} 262 263pick_one () { 264 ff=--ff 265 266 case "$1" in -n) sha1=$2; ff= ;; *) sha1=$1;; esac 267 case "$force_rebase" in '') ;; ?*) ff= ;; esac 268 output git rev-parse --verify$sha1|| die "Invalid commit name:$sha1" 269 270 if is_empty_commit "$sha1" 271 then 272 empty_args="--allow-empty" 273 fi 274 275 test -d "$rewritten" && 276 pick_one_preserving_merges "$@" && return 277 output eval git cherry-pick \ 278${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")}\ 279 "$strategy_args"$empty_args$ff"$@" 280 281 # If cherry-pick dies it leaves the to-be-picked commit unrecorded. Reschedule 282 # previous task so this commit is not lost. 283 ret=$? 284 case "$ret" in [01]) ;; *) reschedule_last_action ;; esac 285 return$ret 286} 287 288pick_one_preserving_merges () { 289 fast_forward=t 290 case "$1" in 291 -n) 292 fast_forward=f 293 sha1=$2 294 ;; 295 *) 296 sha1=$1 297 ;; 298 esac 299 sha1=$(git rev-parse $sha1) 300 301 if test -f "$state_dir"/current-commit 302 then 303 if test "$fast_forward" = t 304 then 305 while read current_commit 306 do 307 git rev-parse HEAD > "$rewritten"/$current_commit 308 done <"$state_dir"/current-commit 309 rm "$state_dir"/current-commit || 310 die "Cannot write current commit's replacement sha1" 311 fi 312 fi 313 314 echo$sha1>> "$state_dir"/current-commit 315 316 # rewrite parents; if none were rewritten, we can fast-forward. 317 new_parents= 318 pend="$(git rev-list --parents -1 $sha1 | cut -d' ' -s -f2-)" 319 if test "$pend" = "" 320 then 321 pend=" root" 322 fi 323 while [ "$pend" != "" ] 324 do 325 p=$(expr "$pend" : ' \([^ ]*\)') 326 pend="${pend# $p}" 327 328 if test -f "$rewritten"/$p 329 then 330 new_p=$(cat "$rewritten"/$p) 331 332 # If the todo reordered commits, and our parent is marked for 333 # rewriting, but hasn't been gotten to yet, assume the user meant to 334 # drop it on top of the current HEAD 335 if test -z "$new_p" 336 then 337 new_p=$(git rev-parse HEAD) 338 fi 339 340 test$p!=$new_p&& fast_forward=f 341 case "$new_parents" in 342 *$new_p*) 343 ;; # do nothing; that parent is already there 344 *) 345 new_parents="$new_parents $new_p" 346 ;; 347 esac 348 else 349 if test -f "$dropped"/$p 350 then 351 fast_forward=f 352 replacement="$(cat "$dropped"/$p)" 353 test -z "$replacement" && replacement=root 354 pend="$replacement$pend" 355 else 356 new_parents="$new_parents $p" 357 fi 358 fi 359 done 360 case$fast_forwardin 361 t) 362 output warn "Fast-forward to $sha1" 363 output git reset --hard$sha1|| 364 die "Cannot fast-forward to $sha1" 365 ;; 366 f) 367 first_parent=$(expr "$new_parents" : ' \([^ ]*\)') 368 369 if [ "$1" != "-n" ] 370 then 371 # detach HEAD to current parent 372 output git checkout$first_parent2> /dev/null || 373 die "Cannot move HEAD to $first_parent" 374 fi 375 376 case "$new_parents" in 377 ' '*' '*) 378 test "a$1" = a-n && die "Refusing to squash a merge:$sha1" 379 380 # redo merge 381 author_script_content=$(get_author_ident_from_commit $sha1) 382 eval "$author_script_content" 383 msg_content="$(commit_message $sha1)" 384 # No point in merging the first parent, that's HEAD 385 new_parents=${new_parents# $first_parent} 386 merge_args="--no-log --no-ff" 387 if ! do_with_author output eval \ 388 'git merge${gpg_sign_opt:+"$gpg_sign_opt"}\ 389$merge_args$strategy_args-m "$msg_content"$new_parents' 390 then 391 printf "%s\n" "$msg_content" > "$GIT_DIR"/MERGE_MSG 392 die_with_patch$sha1"Error redoing merge $sha1" 393 fi 394 echo "$sha1 $(git rev-parse HEAD^0)" >> "$rewritten_list" 395 ;; 396 *) 397 output eval git cherry-pick \ 398${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")}\ 399 "$strategy_args" "$@" || 400 die_with_patch$sha1"Could not pick $sha1" 401 ;; 402 esac 403 ;; 404 esac 405} 406 407nth_string () { 408 case "$1" in 409 *1[0-9]|*[04-9]) echo "$1"th;; 410 *1) echo "$1"st;; 411 *2) echo "$1"nd;; 412 *3) echo "$1"rd;; 413 esac 414} 415 416update_squash_messages () { 417 if test -f "$squash_msg"; then 418 mv "$squash_msg" "$squash_msg".bak || exit 419 count=$(($(sed -n \ 420 -e "1s/^. This is a combination of \(.*\) commits\./\1/p" \ 421 -e "q" < "$squash_msg".bak)+1)) 422 { 423 printf '%s\n' "$comment_char This is a combination of $count commits." 424 sed -e 1d -e '2,/^./{ 425 /^$/d 426 }' <"$squash_msg".bak 427 } >"$squash_msg" 428 else 429 commit_message HEAD > "$fixup_msg" || die "Cannot write$fixup_msg" 430 count=2 431 { 432 printf '%s\n' "$comment_char This is a combination of 2 commits." 433 printf '%s\n' "$comment_char The first commit's message is:" 434 echo 435 cat "$fixup_msg" 436 } >"$squash_msg" 437 fi 438 case$1in 439 squash) 440 rm -f "$fixup_msg" 441 echo 442 printf '%s\n' "$comment_charThis is the$(nth_string $count)commit message:" 443 echo 444 commit_message$2 445 ;; 446 fixup) 447 echo 448 printf '%s\n' "$comment_charThe$(nth_string $count)commit message will be skipped:" 449 echo 450 # Change the space after the comment character to TAB: 451 commit_message$2| git stripspace --comment-lines | sed -e 's/ / /' 452 ;; 453 esac >>"$squash_msg" 454} 455 456peek_next_command () { 457 git stripspace --strip-comments <"$todo" | sed -n -e 's/ .*//p' -e q 458} 459 460# A squash/fixup has failed. Prepare the long version of the squash 461# commit message, then die_with_patch. This code path requires the 462# user to edit the combined commit message for all commits that have 463# been squashed/fixedup so far. So also erase the old squash 464# messages, effectively causing the combined commit to be used as the 465# new basis for any further squash/fixups. Args: sha1 rest 466die_failed_squash() { 467 mv "$squash_msg" "$msg" || exit 468 rm -f "$fixup_msg" 469 cp "$msg" "$GIT_DIR"/MERGE_MSG || exit 470 warn 471 warn "Could not apply$1...$2" 472 die_with_patch$1"" 473} 474 475flush_rewritten_pending() { 476 test -s "$rewritten_pending" || return 477 newsha1="$(git rev-parse HEAD^0)" 478 sed "s/$/$newsha1/" < "$rewritten_pending" >> "$rewritten_list" 479 rm -f "$rewritten_pending" 480} 481 482record_in_rewritten() { 483 oldsha1="$(git rev-parse $1)" 484 echo "$oldsha1" >> "$rewritten_pending" 485 486 case "$(peek_next_command)" in 487 squash|s|fixup|f) 488 ;; 489 *) 490 flush_rewritten_pending 491 ;; 492 esac 493} 494 495do_pick () { 496 if test "$(git rev-parse HEAD)" = "$squash_onto" 497 then 498 # Set the correct commit message and author info on the 499 # sentinel root before cherry-picking the original changes 500 # without committing (-n). Finally, update the sentinel again 501 # to include these changes. If the cherry-pick results in a 502 # conflict, this means our behaviour is similar to a standard 503 # failed cherry-pick during rebase, with a dirty index to 504 # resolve before manually running git commit --amend then git 505 # rebase --continue. 506 git commit --allow-empty --allow-empty-message --amend \ 507 --no-post-rewrite -n -q -C$1&& 508 pick_one -n$1&& 509 git commit --allow-empty --allow-empty-message \ 510 --amend --no-post-rewrite -n -q -C$1\ 511${gpg_sign_opt:+"$gpg_sign_opt"}|| 512 die_with_patch$1"Could not apply$1...$2" 513 else 514 pick_one$1|| 515 die_with_patch$1"Could not apply$1...$2" 516 fi 517} 518 519do_next () { 520 rm -f "$msg" "$author_script" "$amend" "$state_dir"/stopped-sha || exit 521 read -r command sha1 rest < "$todo" 522 case "$command" in 523 "$comment_char"*|''|noop|drop|d) 524 mark_action_done 525 ;; 526 "$cr") 527 # Work around CR left by "read" (e.g. with Git for Windows' Bash). 528 mark_action_done 529;; 530 pick|p) 531 comment_for_reflog pick 532 533 mark_action_done 534 do_pick $sha1"$rest" 535 record_in_rewritten $sha1 536;; 537 reword|r) 538 comment_for_reflog reword 539 540 mark_action_done 541 do_pick $sha1"$rest" 542 git commit --amend --no-post-rewrite${gpg_sign_opt:+"$gpg_sign_opt"}|| { 543 warn "Could not amend commit after successfully picking$sha1...$rest" 544 warn "This is most likely due to an empty commit message, or the pre-commit hook" 545 warn "failed. If the pre-commit hook failed, you may need to resolve the issue before" 546 warn "you are able to reword the commit." 547 exit_with_patch $sha11 548} 549 record_in_rewritten $sha1 550;; 551 edit|e) 552 comment_for_reflog edit 553 554 mark_action_done 555 do_pick $sha1"$rest" 556 warn "Stopped at$sha1...$rest" 557 exit_with_patch $sha10 558;; 559 squash|s|fixup|f) 560case"$command"in 561 squash|s) 562 squash_style=squash 563;; 564 fixup|f) 565 squash_style=fixup 566;; 567esac 568 comment_for_reflog $squash_style 569 570test -f"$done"&& has_action "$done"|| 571 die "Cannot '$squash_style' without a previous commit" 572 573 mark_action_done 574 update_squash_messages $squash_style $sha1 575 author_script_content=$(get_author_ident_from_commit HEAD) 576echo"$author_script_content">"$author_script" 577eval"$author_script_content" 578if! pick_one -n$sha1 579then 580 git rev-parse --verify HEAD >"$amend" 581 die_failed_squash $sha1"$rest" 582fi 583case"$(peek_next_command)"in 584 squash|s|fixup|f) 585# This is an intermediate commit; its message will only be 586# used in case of trouble. So use the long version: 587 do_with_author output git commit --amend --no-verify -F"$squash_msg" \ 588${gpg_sign_opt:+"$gpg_sign_opt"}|| 589 die_failed_squash $sha1"$rest" 590;; 591*) 592# This is the final command of this squash/fixup group 593iftest -f"$fixup_msg" 594then 595 do_with_author git commit --amend --no-verify -F"$fixup_msg" \ 596${gpg_sign_opt:+"$gpg_sign_opt"}|| 597 die_failed_squash $sha1"$rest" 598else 599cp"$squash_msg""$GIT_DIR"/SQUASH_MSG ||exit 600rm-f"$GIT_DIR"/MERGE_MSG 601 do_with_author git commit --amend --no-verify -F"$GIT_DIR"/SQUASH_MSG -e \ 602${gpg_sign_opt:+"$gpg_sign_opt"}|| 603 die_failed_squash $sha1"$rest" 604fi 605rm-f"$squash_msg""$fixup_msg" 606;; 607esac 608 record_in_rewritten $sha1 609;; 610 x|"exec") 611read -r command rest <"$todo" 612 mark_action_done 613printf'Executing: %s\n'"$rest" 614"${SHELL:-@SHELL_PATH@}"-c"$rest"# Actual execution 615 status=$? 616# Run in subshell because require_clean_work_tree can die. 617 dirty=f 618(require_clean_work_tree "rebase"2>/dev/null) || dirty=t 619iftest"$status"-ne0 620then 621 warn "Execution failed:$rest" 622test"$dirty"= f || 623 warn "and made changes to the index and/or the working tree" 624 625 warn "You can fix the problem, and then run" 626 warn 627 warn " git rebase --continue" 628 warn 629iftest$status-eq127# command not found 630then 631 status=1 632fi 633exit"$status" 634eliftest"$dirty"= t 635then 636 warn "Execution succeeded:$rest" 637 warn "but left changes to the index and/or the working tree" 638 warn "Commit or stash your changes, and then run" 639 warn 640 warn " git rebase --continue" 641 warn 642exit1 643fi 644;; 645*) 646 warn "Unknown command:$command$sha1$rest" 647 fixtodo="Please fix this using 'git rebase --edit-todo'." 648if git rev-parse --verify -q"$sha1">/dev/null 649then 650 die_with_patch $sha1"$fixtodo" 651else 652 die "$fixtodo" 653fi 654;; 655esac 656test -s"$todo"&&return 657 658 comment_for_reflog finish && 659 newhead=$(git rev-parse HEAD)&& 660case$head_namein 661 refs/*) 662 message="$GIT_REFLOG_ACTION:$head_nameonto$onto"&& 663 git update-ref -m"$message"$head_name $newhead $orig_head&& 664 git symbolic-ref \ 665-m"$GIT_REFLOG_ACTION: returning to$head_name" \ 666 HEAD $head_name 667;; 668esac&& { 669test!-f"$state_dir"/verbose || 670 git diff-tree --stat$orig_head..HEAD 671} && 672{ 673test -s"$rewritten_list"&& 674 git notes copy --for-rewrite=rebase <"$rewritten_list"|| 675 true # we don't care if this copying failed 676} && 677 hook="$(git rev-parse --git-path hooks/post-rewrite)" 678iftest -x"$hook"&&test -s"$rewritten_list";then 679"$hook" rebase <"$rewritten_list" 680 true # we don't care if this hook failed 681fi&& 682 warn "Successfully rebased and updated$head_name." 683 684return1# not failure; just to break the do_rest loop 685} 686 687# can only return 0, when the infinite loop breaks 688do_rest () { 689while: 690do 691 do_next ||break 692done 693} 694 695# skip picking commits whose parents are unchanged 696skip_unnecessary_picks () { 697 fd=3 698whileread -r command rest 699do 700# fd=3 means we skip the command 701case"$fd,$command"in 7023,pick|3,p) 703# pick a commit whose parent is current $onto -> skip 704 sha1=${rest%% *} 705case"$(git rev-parse --verify --quiet "$sha1"^)"in 706"$onto"*) 707 onto=$sha1 708;; 709*) 710 fd=1 711;; 712esac 713;; 7143,"$comment_char"*|3,) 715# copy comments 716;; 717*) 718 fd=1 719;; 720esac 721printf'%s\n'"$command${rest:+ }$rest">&$fd 722done<"$todo">"$todo.new"3>>"$done"&& 723mv-f"$todo".new "$todo"&& 724case"$(peek_next_command)"in 725 squash|s|fixup|f) 726 record_in_rewritten "$onto" 727;; 728esac|| 729 die "Could not skip unnecessary pick commands" 730} 731 732transform_todo_ids () { 733whileread -r command rest 734do 735case"$command"in 736"$comment_char"* |exec) 737# Be careful for oddball commands like 'exec' 738# that do not have a SHA-1 at the beginning of $rest. 739;; 740*) 741 sha1=$(git rev-parse --verify --quiet "$@" ${rest%%[ ]*})&& 742 rest="$sha1${rest#*[ ]}" 743;; 744esac 745printf'%s\n'"$command${rest:+ }$rest" 746done<"$todo">"$todo.new"&& 747mv-f"$todo.new""$todo" 748} 749 750expand_todo_ids() { 751 transform_todo_ids 752} 753 754collapse_todo_ids() { 755 transform_todo_ids --short 756} 757 758# Rearrange the todo list that has both "pick sha1 msg" and 759# "pick sha1 fixup!/squash! msg" appears in it so that the latter 760# comes immediately after the former, and change "pick" to 761# "fixup"/"squash". 762# 763# Note that if the config has specified a custom instruction format 764# each log message will be re-retrieved in order to normalize the 765# autosquash arrangement 766rearrange_squash () { 767# extract fixup!/squash! lines and resolve any referenced sha1's 768whileread -r pick sha1 message 769do 770test -z"${format}"|| message=$(git log -n 1 --format="%s" ${sha1}) 771case"$message"in 772"squash! "*|"fixup! "*) 773 action="${message%%!*}" 774 rest=$message 775 prefix= 776# skip all squash! or fixup! (but save for later) 777while: 778do 779case"$rest"in 780"squash! "*|"fixup! "*) 781 prefix="$prefix${rest%%!*}," 782 rest="${rest#*! }" 783;; 784*) 785break 786;; 787esac 788done 789printf'%s %s %s %s\n'"$sha1""$action""$prefix""$rest" 790# if it's a single word, try to resolve to a full sha1 and 791# emit a second copy. This allows us to match on both message 792# and on sha1 prefix 793iftest"${rest#* }"="$rest";then 794 fullsha="$(git rev-parse -q --verify "$rest" 2>/dev/null)" 795iftest -n"$fullsha";then 796# prefix the action to uniquely identify this line as 797# intended for full sha1 match 798echo"$sha1+$action$prefix$fullsha" 799fi 800fi 801esac 802done>"$1.sq"<"$1" 803test -s"$1.sq"||return 804 805 used= 806whileread -r pick sha1 message 807do 808case"$used"in 809*"$sha1"*)continue;; 810esac 811printf'%s\n'"$pick$sha1$message" 812test -z"${format}"|| message=$(git log -n 1 --format="%s" ${sha1}) 813 used="$used$sha1" 814whileread -r squash action msg_prefix msg_content 815do 816case"$used"in 817*"$squash"*)continue;; 818esac 819 emit=0 820case"$action"in 821+*) 822 action="${action#+}" 823# full sha1 prefix test 824case"$msg_content"in"$sha1"*) emit=1;;esac;; 825*) 826# message prefix test 827case"$message"in"$msg_content"*) emit=1;;esac;; 828esac 829iftest$emit=1;then 830iftest -n"${format}" 831then 832 msg_content=$(git log -n 1 --format="${format}" ${squash}) 833else 834 msg_content="$(echo "$msg_prefix" | sed "s/,/! /g")$msg_content" 835fi 836printf'%s\n'"$action$squash$msg_content" 837 used="$used$squash" 838fi 839done<"$1.sq" 840done>"$1.rearranged"<"$1" 841cat"$1.rearranged">"$1" 842rm-f"$1.sq""$1.rearranged" 843} 844 845# Add commands after a pick or after a squash/fixup serie 846# in the todo list. 847add_exec_commands () { 848{ 849 first=t 850whileread -r insn rest 851do 852case$insnin 853 pick) 854test -n"$first"|| 855printf"%s""$cmd" 856;; 857esac 858printf"%s %s\n""$insn""$rest" 859 first= 860done 861printf"%s""$cmd" 862} <"$1">"$1.new"&& 863mv"$1.new""$1" 864} 865 866# Check if the SHA-1 passed as an argument is a 867# correct one, if not then print $2 in "$todo".badsha 868# $1: the SHA-1 to test 869# $2: the line number of the input 870# $3: the input filename 871check_commit_sha () { 872 badsha=0 873iftest -z$1 874then 875 badsha=1 876else 877 sha1_verif="$(git rev-parse --verify --quiet $1^{commit})" 878iftest -z$sha1_verif 879then 880 badsha=1 881fi 882fi 883 884iftest$badsha-ne0 885then 886 line="$(sed -n -e "${2}p" "$3")" 887 warn "Warning: the SHA-1 is missing or isn't" \ 888"a commit in the following line:" 889 warn " -$line" 890 warn 891fi 892 893return$badsha 894} 895 896# prints the bad commits and bad commands 897# from the todolist in stdin 898check_bad_cmd_and_sha () { 899 retval=0 900 lineno=0 901whileread -r command rest 902do 903 lineno=$(( $lineno + 1 )) 904case$commandin 905"$comment_char"*|''|noop|x|exec) 906# Doesn't expect a SHA-1 907;; 908"$cr") 909# Work around CR left by "read" (e.g. with Git for 910# Windows' Bash). 911;; 912 pick|p|drop|d|reword|r|edit|e|squash|s|fixup|f) 913if! check_commit_sha "${rest%%[ ]*}""$lineno""$1" 914then 915 retval=1 916fi 917;; 918*) 919 line="$(sed -n -e "${lineno}p" "$1")" 920 warn "Warning: the command isn't recognized" \ 921"in the following line:" 922 warn " -$line" 923 warn 924 retval=1 925;; 926esac 927done<"$1" 928return$retval 929} 930 931# Print the list of the SHA-1 of the commits 932# from stdin to stdout 933todo_list_to_sha_list () { 934 git stripspace --strip-comments| 935whileread -r command sha1 rest 936do 937case$commandin 938"$comment_char"*|''|noop|x|"exec") 939;; 940*) 941 long_sha=$(git rev-list --no-walk "$sha1" 2>/dev/null) 942printf"%s\n""$long_sha" 943;; 944esac 945done 946} 947 948# Use warn for each line in stdin 949warn_lines () { 950whileread -r line 951do 952 warn " -$line" 953done 954} 955 956# Switch to the branch in $into and notify it in the reflog 957checkout_onto () { 958 GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout$onto_name" 959 output git checkout $onto|| die_abort "could not detach HEAD" 960 git update-ref ORIG_HEAD $orig_head 961} 962 963get_missing_commit_check_level () { 964 check_level=$(git config --get rebase.missingCommitsCheck) 965 check_level=${check_level:-ignore} 966# Don't be case sensitive 967printf'%s'"$check_level"|tr'A-Z''a-z' 968} 969 970# Check if the user dropped some commits by mistake 971# Behaviour determined by rebase.missingCommitsCheck. 972# Check if there is an unrecognized command or a 973# bad SHA-1 in a command. 974check_todo_list () { 975 raise_error=f 976 977 check_level=$(get_missing_commit_check_level) 978 979case"$check_level"in 980 warn|error) 981# Get the SHA-1 of the commits 982 todo_list_to_sha_list <"$todo".backup >"$todo".oldsha1 983 todo_list_to_sha_list <"$todo">"$todo".newsha1 984 985# Sort the SHA-1 and compare them 986sort-u"$todo".oldsha1 >"$todo".oldsha1+ 987mv"$todo".oldsha1+"$todo".oldsha1 988sort-u"$todo".newsha1 >"$todo".newsha1+ 989mv"$todo".newsha1+"$todo".newsha1 990comm-2 -3"$todo".oldsha1 "$todo".newsha1 >"$todo".miss 991 992# Warn about missing commits 993iftest -s"$todo".miss 994then 995test"$check_level"= error && raise_error=t 996 997 warn "Warning: some commits may have been dropped" \ 998"accidentally." 999 warn "Dropped commits (newer to older):"10001001# Make the list user-friendly and display1002 opt="--no-walk=sorted --format=oneline --abbrev-commit --stdin"1003 git rev-list$opt<"$todo".miss | warn_lines10041005 warn "To avoid this message, use\"drop\"to" \1006"explicitly remove a commit."1007 warn1008 warn "Use 'git config rebase.missingCommitsCheck' to change" \1009"the level of warnings."1010 warn "The possible behaviours are: ignore, warn, error."1011 warn1012fi1013;;1014 ignore)1015;;1016*)1017 warn "Unrecognized setting$check_levelfor option" \1018"rebase.missingCommitsCheck. Ignoring."1019;;1020esac10211022if! check_bad_cmd_and_sha "$todo"1023then1024 raise_error=t1025fi10261027iftest$raise_error= t1028then1029# Checkout before the first commit of the1030# rebase: this way git rebase --continue1031# will work correctly as it expects HEAD to be1032# placed before the commit of the next action1033 checkout_onto10341035 warn "You can fix this with 'git rebase --edit-todo'."1036 die "Or you can abort the rebase with 'git rebase --abort'."1037fi1038}10391040# The whole contents of this file is run by dot-sourcing it from1041# inside a shell function. It used to be that "return"s we see1042# below were not inside any function, and expected to return1043# to the function that dot-sourced us.1044#1045# However, FreeBSD /bin/sh misbehaves on such a construct and1046# continues to run the statements that follow such a "return".1047# As a work-around, we introduce an extra layer of a function1048# here, and immediately call it after defining it.1049git_rebase__interactive () {10501051case"$action"in1052continue)1053# do we have anything to commit?1054if git diff-index --cached --quiet HEAD --1055then1056# Nothing to commit -- skip this commit10571058test!-f"$GIT_DIR"/CHERRY_PICK_HEAD ||1059rm"$GIT_DIR"/CHERRY_PICK_HEAD ||1060 die "Could not remove CHERRY_PICK_HEAD"1061else1062if!test -f"$author_script"1063then1064 gpg_sign_opt_quoted=${gpg_sign_opt:+$(git rev-parse --sq-quote "$gpg_sign_opt")}1065 die "You have staged changes in your working tree. If these changes are meant to be1066squashed into the previous commit, run:10671068 git commit --amend$gpg_sign_opt_quoted10691070If they are meant to go into a new commit, run:10711072 git commit$gpg_sign_opt_quoted10731074In both case, once you're done, continue with:10751076 git rebase --continue1077"1078fi1079 . "$author_script"||1080 die "Error trying to find the author identity to amend commit"1081iftest -f"$amend"1082then1083 current_head=$(git rev-parse --verify HEAD)1084test"$current_head"=$(cat "$amend")||1085 die "\1086You have uncommitted changes in your working tree. Please, commit them1087first and then run 'git rebase --continue' again."1088 do_with_author git commit --amend --no-verify -F"$msg"-e \1089${gpg_sign_opt:+"$gpg_sign_opt"}||1090 die "Could not commit staged changes."1091else1092 do_with_author git commit --no-verify -F"$msg"-e \1093${gpg_sign_opt:+"$gpg_sign_opt"}||1094 die "Could not commit staged changes."1095fi1096fi10971098iftest -r"$state_dir"/stopped-sha1099then1100 record_in_rewritten "$(cat "$state_dir"/stopped-sha)"1101fi11021103 require_clean_work_tree "rebase"1104 do_rest1105return01106;;1107skip)1108 git rerere clear11091110 do_rest1111return01112;;1113edit-todo)1114 git stripspace --strip-comments<"$todo">"$todo".new1115mv-f"$todo".new "$todo"1116 collapse_todo_ids1117 append_todo_help1118 git stripspace --comment-lines>>"$todo"<<\EOF11191120You are editing the todo file of an ongoing interactive rebase.1121To continue rebase after editing, run:1122 git rebase --continue11231124EOF11251126 git_sequence_editor "$todo"||1127 die "Could not execute editor"1128 expand_todo_ids11291130exit1131;;1132esac11331134git var GIT_COMMITTER_IDENT >/dev/null ||1135 die "You need to set your committer info first"11361137comment_for_reflog start11381139iftest!-z"$switch_to"1140then1141 GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout$switch_to"1142 output git checkout "$switch_to"--||1143 die "Could not checkout$switch_to"11441145 comment_for_reflog start1146fi11471148orig_head=$(git rev-parse --verify HEAD)|| die "No HEAD?"1149mkdir-p"$state_dir"|| die "Could not create temporary$state_dir"11501151: >"$state_dir"/interactive || die "Could not mark as interactive"1152write_basic_state1153iftest t ="$preserve_merges"1154then1155iftest -z"$rebase_root"1156then1157mkdir"$rewritten"&&1158for c in$(git merge-base --all $orig_head $upstream)1159do1160echo$onto>"$rewritten"/$c||1161 die "Could not init rewritten commits"1162done1163else1164mkdir"$rewritten"&&1165echo$onto>"$rewritten"/root ||1166 die "Could not init rewritten commits"1167fi1168# No cherry-pick because our first pass is to determine1169# parents to rewrite and skipping dropped commits would1170# prematurely end our probe1171 merges_option=1172else1173 merges_option="--no-merges --cherry-pick"1174fi11751176shorthead=$(git rev-parse --short $orig_head)1177shortonto=$(git rev-parse --short $onto)1178iftest -z"$rebase_root"1179# this is now equivalent to ! -z "$upstream"1180then1181 shortupstream=$(git rev-parse --short $upstream)1182 revisions=$upstream...$orig_head1183 shortrevisions=$shortupstream..$shorthead1184else1185 revisions=$onto...$orig_head1186 shortrevisions=$shorthead1187fi1188format=$(git config --get rebase.instructionFormat)1189# the 'rev-list .. | sed' requires %m to parse; the instruction requires %H to parse1190git rev-list$merges_option--format="%m%H${format:-%s}" \1191--reverse --left-right --topo-order \1192$revisions ${restrict_revision+^$restrict_revision}| \1193sed-n"s/^>//p"|1194whileread -r sha1 rest1195do11961197iftest -z"$keep_empty"&& is_empty_commit $sha1&& ! is_merge_commit $sha11198then1199 comment_out="$comment_char"1200else1201 comment_out=1202fi12031204iftest t !="$preserve_merges"1205then1206printf'%s\n'"${comment_out}pick$sha1$rest">>"$todo"1207else1208iftest -z"$rebase_root"1209then1210 preserve=t1211for p in$(git rev-list --parents -1 $sha1 | cut -d' ' -s -f2-)1212do1213iftest -f"$rewritten"/$p1214then1215 preserve=f1216fi1217done1218else1219 preserve=f1220fi1221iftest f ="$preserve"1222then1223touch"$rewritten"/$sha11224printf'%s\n'"${comment_out}pick$sha1$rest">>"$todo"1225fi1226fi1227done12281229# Watch for commits that been dropped by --cherry-pick1230iftest t ="$preserve_merges"1231then1232mkdir"$dropped"1233# Save all non-cherry-picked changes1234 git rev-list$revisions--left-right --cherry-pick| \1235sed-n"s/^>//p">"$state_dir"/not-cherry-picks1236# Now all commits and note which ones are missing in1237# not-cherry-picks and hence being dropped1238 git rev-list$revisions|1239whilereadrev1240do1241iftest -f"$rewritten"/$rev&&test"$(sane_grep "$rev" "$state_dir"/not-cherry-picks)"=""1242then1243# Use -f2 because if rev-list is telling us this commit is1244# not worthwhile, we don't want to track its multiple heads,1245# just the history of its first-parent for others that will1246# be rebasing on top of it1247 git rev-list --parents -1$rev| cut -d' '-s -f2>"$dropped"/$rev1248 sha1=$(git rev-list -1 $rev)1249 sane_grep -v"^[a-z][a-z]*$sha1"<"$todo">"${todo}2";mv"${todo}2""$todo"1250rm"$rewritten"/$rev1251fi1252done1253fi12541255test -s"$todo"||echo noop >>"$todo"1256test -n"$autosquash"&& rearrange_squash "$todo"1257test -n"$cmd"&& add_exec_commands "$todo"12581259todocount=$(git stripspace --strip-comments <"$todo" | wc -l)1260todocount=${todocount##* }12611262cat>>"$todo"<<EOF12631264$comment_charRebase$shortrevisionsonto$shortonto($todocountcommand(s))1265EOF1266append_todo_help1267git stripspace --comment-lines>>"$todo"<<\EOF12681269However,if you remove everything, the rebase will be aborted.12701271EOF12721273iftest -z"$keep_empty"1274then1275printf'%s\n'"$comment_charNote that empty commits are commented out">>"$todo"1276fi127712781279has_action "$todo"||1280return212811282cp"$todo""$todo".backup1283collapse_todo_ids1284git_sequence_editor "$todo"||1285 die_abort "Could not execute editor"12861287has_action "$todo"||1288return212891290check_todo_list12911292expand_todo_ids12931294test -d"$rewritten"||test -n"$force_rebase"|| skip_unnecessary_picks12951296checkout_onto1297do_rest12981299}1300# ... and then we call the whole thing.1301git_rebase__interactive