# This shell script fragment is sourced by git-rebase to implement # its interactive mode. "git rebase --interactive" makes it easy # to fix up commits in the middle of a series and rearrange commits. # # Copyright (c) 2006 Johannes E. Schindelin # # The original idea comes from Eric W. Biederman, in # https://public-inbox.org/git/m1odwkyuf5.fsf_-_@ebiederm.dsl.xmission.com/ # # The file containing rebase commands, comments, and empty lines. # This file is created by "git rebase -i" then edited by the user. As # the lines are processed, they are removed from the front of this # file and written to the tail of $done. todo="$state_dir"/git-rebase-todo GIT_CHERRY_PICK_HELP="$resolvemsg" export GIT_CHERRY_PICK_HELP comment_char=$(git config --get core.commentchar 2>/dev/null) case "$comment_char" in '' | auto) comment_char="#" ;; ?) ;; *) comment_char=$(echo "$comment_char" | cut -c1) ;; esac orig_reflog_action="$GIT_REFLOG_ACTION" comment_for_reflog () { case "$orig_reflog_action" in ''|rebase*) GIT_REFLOG_ACTION="rebase -i ($1)" export GIT_REFLOG_ACTION ;; esac } append_todo_help () { gettext " Commands: p, pick <commit> = use commit r, reword <commit> = use commit, but edit the commit message e, edit <commit> = use commit, but stop for amending s, squash <commit> = use commit, but meld into previous commit f, fixup <commit> = like \"squash\", but discard this commit's log message x, exec <command> = run command (the rest of the line) using shell d, drop <commit> = remove commit l, label <label> = label current HEAD with a name t, reset <label> = reset HEAD to a label m, merge [-C <commit> | -c <commit>] <label> [# <oneline>] . create a merge commit using the original merge commit's . message (or the oneline, if no original merge commit was . specified). Use -c <commit> to reword the commit message. These lines can be re-ordered; they are executed from top to bottom. " | git stripspace --comment-lines >>"$todo" if test $(get_missing_commit_check_level) = error then gettext " Do not remove any line. Use 'drop' explicitly to remove a commit. " | git stripspace --comment-lines >>"$todo" else gettext " If you remove a line here THAT COMMIT WILL BE LOST. " | git stripspace --comment-lines >>"$todo" fi } die_abort () { apply_autostash rm -rf "$state_dir" die "$1" } has_action () { test -n "$(git stripspace --strip-comments <"$1")" } git_sequence_editor () { if test -z "$GIT_SEQUENCE_EDITOR" then GIT_SEQUENCE_EDITOR="$(git config sequence.editor)" if [ -z "$GIT_SEQUENCE_EDITOR" ] then GIT_SEQUENCE_EDITOR="$(git var GIT_EDITOR)" || return $? fi fi eval "$GIT_SEQUENCE_EDITOR" '"$@"' } expand_todo_ids() { git rebase--helper --expand-ids } collapse_todo_ids() { git rebase--helper --shorten-ids } # Switch to the branch in $into and notify it in the reflog checkout_onto () { GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" output git checkout $onto || die_abort "$(gettext "could not detach HEAD")" git update-ref ORIG_HEAD $orig_head } get_missing_commit_check_level () { check_level=$(git config --get rebase.missingCommitsCheck) check_level=${check_level:-ignore} # Don't be case sensitive printf '%s' "$check_level" | tr 'A-Z' 'a-z' } # Initiate an action. If the cannot be any # further action it may exec a command # or exit and not return. # # TODO: Consider a cleaner return model so it # never exits and always return 0 if process # is complete. # # Parameter 1 is the action to initiate. # # Returns 0 if the action was able to complete # and if 1 if further processing is required. initiate_action () { case "$1" in continue) exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \ --continue ;; skip) git rerere clear exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \ --continue ;; edit-todo) git stripspace --strip-comments <"$todo" >"$todo".new mv -f "$todo".new "$todo" collapse_todo_ids append_todo_help gettext " You are editing the todo file of an ongoing interactive rebase. To continue rebase after editing, run: git rebase --continue " | git stripspace --comment-lines >>"$todo" git_sequence_editor "$todo" || die "$(gettext "Could not execute editor")" expand_todo_ids exit ;; show-current-patch) exec git show REBASE_HEAD -- ;; *) return 1 # continue ;; esac } setup_reflog_action () { comment_for_reflog start if test ! -z "$switch_to" then GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to" output git checkout "$switch_to" -- || die "$(eval_gettext "Could not checkout \$switch_to")" comment_for_reflog start fi } init_basic_state () { orig_head=$(git rev-parse --verify HEAD) || die "$(gettext "No HEAD?")" mkdir -p "$state_dir" || die "$(eval_gettext "Could not create temporary \$state_dir")" rm -f "$(git rev-parse --git-path REBASE_HEAD)" : > "$state_dir"/interactive || die "$(gettext "Could not mark as interactive")" write_basic_state } init_revisions_and_shortrevisions () { shorthead=$(git rev-parse --short $orig_head) shortonto=$(git rev-parse --short $onto) if test -z "$rebase_root" # this is now equivalent to ! -z "$upstream" then shortupstream=$(git rev-parse --short $upstream) revisions=$upstream...$orig_head shortrevisions=$shortupstream..$shorthead else revisions=$onto...$orig_head shortrevisions=$shorthead test -z "$squash_onto" || echo "$squash_onto" >"$state_dir"/squash-onto fi } complete_action() { test -s "$todo" || echo noop >> "$todo" test -z "$autosquash" || git rebase--helper --rearrange-squash || exit test -n "$cmd" && git rebase--helper --add-exec-commands "$cmd" todocount=$(git stripspace --strip-comments <"$todo" | wc -l) todocount=${todocount##* } cat >>"$todo" <<EOF $comment_char $(eval_ngettext \ "Rebase \$shortrevisions onto \$shortonto (\$todocount command)" \ "Rebase \$shortrevisions onto \$shortonto (\$todocount commands)" \ "$todocount") EOF append_todo_help gettext " However, if you remove everything, the rebase will be aborted. " | git stripspace --comment-lines >>"$todo" if test -z "$keep_empty" then printf '%s\n' "$comment_char $(gettext "Note that empty commits are commented out")" >>"$todo" fi has_action "$todo" || return 2 cp "$todo" "$todo".backup collapse_todo_ids git_sequence_editor "$todo" || die_abort "$(gettext "Could not execute editor")" has_action "$todo" || return 2 git rebase--helper --check-todo-list || { ret=$? checkout_onto exit $ret } expand_todo_ids test -n "$force_rebase" || onto="$(git rebase--helper --skip-unnecessary-picks)" || die "Could not skip unnecessary pick commands" checkout_onto require_clean_work_tree "rebase" exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \ --continue } git_rebase__interactive () { initiate_action "$action" ret=$? if test $ret = 0; then return 0 fi setup_reflog_action init_basic_state init_revisions_and_shortrevisions git rebase--helper --make-script ${keep_empty:+--keep-empty} \ ${rebase_merges:+--rebase-merges} \ ${rebase_cousins:+--rebase-cousins} \ $revisions ${restrict_revision+^$restrict_revision} >"$todo" || die "$(gettext "Could not generate todo list")" complete_action }