94c23a7af2291fbfc0e390966e3455ab0f1083ca
   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
  42die_abort () {
  43        apply_autostash
  44        rm -rf "$state_dir"
  45        die "$1"
  46}
  47
  48has_action () {
  49        test -n "$(git stripspace --strip-comments <"$1")"
  50}
  51
  52git_sequence_editor () {
  53        if test -z "$GIT_SEQUENCE_EDITOR"
  54        then
  55                GIT_SEQUENCE_EDITOR="$(git config sequence.editor)"
  56                if [ -z "$GIT_SEQUENCE_EDITOR" ]
  57                then
  58                        GIT_SEQUENCE_EDITOR="$(git var GIT_EDITOR)" || return $?
  59                fi
  60        fi
  61
  62        eval "$GIT_SEQUENCE_EDITOR" '"$@"'
  63}
  64
  65expand_todo_ids() {
  66        git rebase--helper --expand-ids
  67}
  68
  69collapse_todo_ids() {
  70        git rebase--helper --shorten-ids
  71}
  72
  73# Switch to the branch in $into and notify it in the reflog
  74checkout_onto () {
  75        GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name"
  76        output git checkout $onto || die_abort "$(gettext "could not detach HEAD")"
  77        git update-ref ORIG_HEAD $orig_head
  78}
  79
  80get_missing_commit_check_level () {
  81        check_level=$(git config --get rebase.missingCommitsCheck)
  82        check_level=${check_level:-ignore}
  83        # Don't be case sensitive
  84        printf '%s' "$check_level" | tr 'A-Z' 'a-z'
  85}
  86
  87# Initiate an action. If the cannot be any
  88# further action it  may exec a command
  89# or exit and not return.
  90#
  91# TODO: Consider a cleaner return model so it
  92# never exits and always return 0 if process
  93# is complete.
  94#
  95# Parameter 1 is the action to initiate.
  96#
  97# Returns 0 if the action was able to complete
  98# and if 1 if further processing is required.
  99initiate_action () {
 100        case "$1" in
 101        continue)
 102                exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \
 103                     --continue
 104                ;;
 105        skip)
 106                git rerere clear
 107                exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \
 108                     --continue
 109                ;;
 110        edit-todo)
 111                git stripspace --strip-comments <"$todo" >"$todo".new
 112                mv -f "$todo".new "$todo"
 113                collapse_todo_ids
 114                git rebase--helper --append-todo-help --write-edit-todo
 115
 116                git_sequence_editor "$todo" ||
 117                        die "$(gettext "Could not execute editor")"
 118                expand_todo_ids
 119
 120                exit
 121                ;;
 122        show-current-patch)
 123                exec git show REBASE_HEAD --
 124                ;;
 125        *)
 126                return 1 # continue
 127                ;;
 128        esac
 129}
 130
 131setup_reflog_action () {
 132        comment_for_reflog start
 133
 134        if test ! -z "$switch_to"
 135        then
 136                GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to"
 137                output git checkout "$switch_to" -- ||
 138                        die "$(eval_gettext "Could not checkout \$switch_to")"
 139
 140                comment_for_reflog start
 141        fi
 142}
 143
 144init_basic_state () {
 145        orig_head=$(git rev-parse --verify HEAD) || die "$(gettext "No HEAD?")"
 146        mkdir -p "$state_dir" || die "$(eval_gettext "Could not create temporary \$state_dir")"
 147        rm -f "$(git rev-parse --git-path REBASE_HEAD)"
 148
 149        : > "$state_dir"/interactive || die "$(gettext "Could not mark as interactive")"
 150        write_basic_state
 151}
 152
 153init_revisions_and_shortrevisions () {
 154        shorthead=$(git rev-parse --short $orig_head)
 155        shortonto=$(git rev-parse --short $onto)
 156        if test -z "$rebase_root"
 157                # this is now equivalent to ! -z "$upstream"
 158        then
 159                shortupstream=$(git rev-parse --short $upstream)
 160                revisions=$upstream...$orig_head
 161                shortrevisions=$shortupstream..$shorthead
 162        else
 163                revisions=$onto...$orig_head
 164                shortrevisions=$shorthead
 165                test -z "$squash_onto" ||
 166                echo "$squash_onto" >"$state_dir"/squash-onto
 167        fi
 168}
 169
 170complete_action() {
 171        test -s "$todo" || echo noop >> "$todo"
 172        test -z "$autosquash" || git rebase--helper --rearrange-squash || exit
 173        test -n "$cmd" && git rebase--helper --add-exec-commands "$cmd"
 174
 175        todocount=$(git stripspace --strip-comments <"$todo" | wc -l)
 176        todocount=${todocount##* }
 177
 178cat >>"$todo" <<EOF
 179
 180$comment_char $(eval_ngettext \
 181        "Rebase \$shortrevisions onto \$shortonto (\$todocount command)" \
 182        "Rebase \$shortrevisions onto \$shortonto (\$todocount commands)" \
 183        "$todocount")
 184EOF
 185        git rebase--helper --append-todo-help ${keep_empty:+--keep-empty}
 186
 187        has_action "$todo" ||
 188                return 2
 189
 190        cp "$todo" "$todo".backup
 191        collapse_todo_ids
 192        git_sequence_editor "$todo" ||
 193                die_abort "$(gettext "Could not execute editor")"
 194
 195        has_action "$todo" ||
 196                return 2
 197
 198        git rebase--helper --check-todo-list || {
 199                ret=$?
 200                checkout_onto
 201                exit $ret
 202        }
 203
 204        expand_todo_ids
 205
 206        test -n "$force_rebase" ||
 207        onto="$(git rebase--helper --skip-unnecessary-picks)" ||
 208        die "Could not skip unnecessary pick commands"
 209
 210        checkout_onto
 211        require_clean_work_tree "rebase"
 212        exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \
 213             --continue
 214}
 215
 216git_rebase__interactive () {
 217        initiate_action "$action"
 218        ret=$?
 219        if test $ret = 0; then
 220                return 0
 221        fi
 222
 223        setup_reflog_action
 224        init_basic_state
 225
 226        init_revisions_and_shortrevisions
 227
 228        git rebase--helper --make-script ${keep_empty:+--keep-empty} \
 229                ${rebase_merges:+--rebase-merges} \
 230                ${rebase_cousins:+--rebase-cousins} \
 231                $revisions ${restrict_revision+^$restrict_revision} >"$todo" ||
 232        die "$(gettext "Could not generate todo list")"
 233
 234        complete_action
 235}