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