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