git-rebase--interactive.shon commit commit-graph: split up close_reachable() progress output (01ca387)
   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# https://public-inbox.org/git/m1odwkyuf5.fsf_-_@ebiederm.dsl.xmission.com/
   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
  16GIT_CHERRY_PICK_HELP="$resolvemsg"
  17export GIT_CHERRY_PICK_HELP
  18
  19comment_char=$(git config --get core.commentchar 2>/dev/null)
  20case "$comment_char" in
  21'' | auto)
  22        comment_char="#"
  23        ;;
  24?)
  25        ;;
  26*)
  27        comment_char=$(echo "$comment_char" | cut -c1)
  28        ;;
  29esac
  30
  31orig_reflog_action="$GIT_REFLOG_ACTION"
  32
  33comment_for_reflog () {
  34        case "$orig_reflog_action" in
  35        ''|rebase*)
  36                GIT_REFLOG_ACTION="rebase -i ($1)"
  37                export GIT_REFLOG_ACTION
  38                ;;
  39        esac
  40}
  41
  42append_todo_help () {
  43        gettext "
  44Commands:
  45p, pick <commit> = use commit
  46r, reword <commit> = use commit, but edit the commit message
  47e, edit <commit> = use commit, but stop for amending
  48s, squash <commit> = use commit, but meld into previous commit
  49f, fixup <commit> = like \"squash\", but discard this commit's log message
  50x, exec <command> = run command (the rest of the line) using shell
  51d, drop <commit> = remove commit
  52l, label <label> = label current HEAD with a name
  53t, reset <label> = reset HEAD to a label
  54m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
  55.       create a merge commit using the original merge commit's
  56.       message (or the oneline, if no original merge commit was
  57.       specified). Use -c <commit> to reword the commit message.
  58
  59These lines can be re-ordered; they are executed from top to bottom.
  60" | git stripspace --comment-lines >>"$todo"
  61
  62        if test $(get_missing_commit_check_level) = error
  63        then
  64                gettext "
  65Do not remove any line. Use 'drop' explicitly to remove a commit.
  66" | git stripspace --comment-lines >>"$todo"
  67        else
  68                gettext "
  69If you remove a line here THAT COMMIT WILL BE LOST.
  70" | git stripspace --comment-lines >>"$todo"
  71        fi
  72}
  73
  74die_abort () {
  75        apply_autostash
  76        rm -rf "$state_dir"
  77        die "$1"
  78}
  79
  80has_action () {
  81        test -n "$(git stripspace --strip-comments <"$1")"
  82}
  83
  84git_sequence_editor () {
  85        if test -z "$GIT_SEQUENCE_EDITOR"
  86        then
  87                GIT_SEQUENCE_EDITOR="$(git config sequence.editor)"
  88                if [ -z "$GIT_SEQUENCE_EDITOR" ]
  89                then
  90                        GIT_SEQUENCE_EDITOR="$(git var GIT_EDITOR)" || return $?
  91                fi
  92        fi
  93
  94        eval "$GIT_SEQUENCE_EDITOR" '"$@"'
  95}
  96
  97expand_todo_ids() {
  98        git rebase--helper --expand-ids
  99}
 100
 101collapse_todo_ids() {
 102        git rebase--helper --shorten-ids
 103}
 104
 105# Switch to the branch in $into and notify it in the reflog
 106checkout_onto () {
 107        GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name"
 108        output git checkout $onto || die_abort "$(gettext "could not detach HEAD")"
 109        git update-ref ORIG_HEAD $orig_head
 110}
 111
 112get_missing_commit_check_level () {
 113        check_level=$(git config --get rebase.missingCommitsCheck)
 114        check_level=${check_level:-ignore}
 115        # Don't be case sensitive
 116        printf '%s' "$check_level" | tr 'A-Z' 'a-z'
 117}
 118
 119# Initiate an action. If the cannot be any
 120# further action it  may exec a command
 121# or exit and not return.
 122#
 123# TODO: Consider a cleaner return model so it
 124# never exits and always return 0 if process
 125# is complete.
 126#
 127# Parameter 1 is the action to initiate.
 128#
 129# Returns 0 if the action was able to complete
 130# and if 1 if further processing is required.
 131initiate_action () {
 132        case "$1" in
 133        continue)
 134                exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \
 135                     --continue
 136                ;;
 137        skip)
 138                git rerere clear
 139                exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \
 140                     --continue
 141                ;;
 142        edit-todo)
 143                git stripspace --strip-comments <"$todo" >"$todo".new
 144                mv -f "$todo".new "$todo"
 145                collapse_todo_ids
 146                append_todo_help
 147                gettext "
 148You are editing the todo file of an ongoing interactive rebase.
 149To continue rebase after editing, run:
 150    git rebase --continue
 151
 152" | git stripspace --comment-lines >>"$todo"
 153
 154                git_sequence_editor "$todo" ||
 155                        die "$(gettext "Could not execute editor")"
 156                expand_todo_ids
 157
 158                exit
 159                ;;
 160        show-current-patch)
 161                exec git show REBASE_HEAD --
 162                ;;
 163        *)
 164                return 1 # continue
 165                ;;
 166        esac
 167}
 168
 169setup_reflog_action () {
 170        comment_for_reflog start
 171
 172        if test ! -z "$switch_to"
 173        then
 174                GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to"
 175                output git checkout "$switch_to" -- ||
 176                        die "$(eval_gettext "Could not checkout \$switch_to")"
 177
 178                comment_for_reflog start
 179        fi
 180}
 181
 182init_basic_state () {
 183        orig_head=$(git rev-parse --verify HEAD) || die "$(gettext "No HEAD?")"
 184        mkdir -p "$state_dir" || die "$(eval_gettext "Could not create temporary \$state_dir")"
 185        rm -f "$(git rev-parse --git-path REBASE_HEAD)"
 186
 187        : > "$state_dir"/interactive || die "$(gettext "Could not mark as interactive")"
 188        write_basic_state
 189}
 190
 191init_revisions_and_shortrevisions () {
 192        shorthead=$(git rev-parse --short $orig_head)
 193        shortonto=$(git rev-parse --short $onto)
 194        if test -z "$rebase_root"
 195                # this is now equivalent to ! -z "$upstream"
 196        then
 197                shortupstream=$(git rev-parse --short $upstream)
 198                revisions=$upstream...$orig_head
 199                shortrevisions=$shortupstream..$shorthead
 200        else
 201                revisions=$onto...$orig_head
 202                shortrevisions=$shorthead
 203                test -z "$squash_onto" ||
 204                echo "$squash_onto" >"$state_dir"/squash-onto
 205        fi
 206}
 207
 208complete_action() {
 209        test -s "$todo" || echo noop >> "$todo"
 210        test -z "$autosquash" || git rebase--helper --rearrange-squash || exit
 211        test -n "$cmd" && git rebase--helper --add-exec-commands "$cmd"
 212
 213        todocount=$(git stripspace --strip-comments <"$todo" | wc -l)
 214        todocount=${todocount##* }
 215
 216cat >>"$todo" <<EOF
 217
 218$comment_char $(eval_ngettext \
 219        "Rebase \$shortrevisions onto \$shortonto (\$todocount command)" \
 220        "Rebase \$shortrevisions onto \$shortonto (\$todocount commands)" \
 221        "$todocount")
 222EOF
 223        append_todo_help
 224        gettext "
 225        However, if you remove everything, the rebase will be aborted.
 226
 227        " | git stripspace --comment-lines >>"$todo"
 228
 229        if test -z "$keep_empty"
 230        then
 231                printf '%s\n' "$comment_char $(gettext "Note that empty commits are commented out")" >>"$todo"
 232        fi
 233
 234
 235        has_action "$todo" ||
 236                return 2
 237
 238        cp "$todo" "$todo".backup
 239        collapse_todo_ids
 240        git_sequence_editor "$todo" ||
 241                die_abort "$(gettext "Could not execute editor")"
 242
 243        has_action "$todo" ||
 244                return 2
 245
 246        git rebase--helper --check-todo-list || {
 247                ret=$?
 248                checkout_onto
 249                exit $ret
 250        }
 251
 252        expand_todo_ids
 253
 254        test -n "$force_rebase" ||
 255        onto="$(git rebase--helper --skip-unnecessary-picks)" ||
 256        die "Could not skip unnecessary pick commands"
 257
 258        checkout_onto
 259        require_clean_work_tree "rebase"
 260        exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \
 261             --continue
 262}
 263
 264git_rebase__interactive () {
 265        initiate_action "$action"
 266        ret=$?
 267        if test $ret = 0; then
 268                return 0
 269        fi
 270
 271        setup_reflog_action
 272        init_basic_state
 273
 274        init_revisions_and_shortrevisions
 275
 276        git rebase--helper --make-script ${keep_empty:+--keep-empty} \
 277                ${rebase_merges:+--rebase-merges} \
 278                ${rebase_cousins:+--rebase-cousins} \
 279                $revisions ${restrict_revision+^$restrict_revision} >"$todo" ||
 280        die "$(gettext "Could not generate todo list")"
 281
 282        complete_action
 283}