Search code examples
gitrebasegit-interactive-rebase

Make `git rebase -i` present and apply commits bottom to top


Git shows commits in the interactive-rebase todo list (produced by git rebase -i) in the opposite of the usual order: the most ancestral commit (typically, the oldest commit) is shown first, not last.

Can I get it the other way around, for consistency with the usual sort order of git log? That is, I'd like the todo list shown in the default sort order of git log, and I'd like the todo list to still be understood by Git after I've edited it, without having to manually re-reverse it.


Solution

  • You can use a custom sequence.editor config:

    git -c sequence.editor='tac "$1" > "$1.reverse" && "$(git config core.editor || echo "${GIT_EDITOR:-${EDITOR:-vi}}")" "$1.reverse" && tac "$1.reverse" > "$1"' rebase -i ...
    

    It's easy to configure a reusable alias for that and use it:

    git config alias.revbase "!git -c sequence.editor='tac \"\$1\" > \"\$1.reverse\" \
    && \"\$(git config core.editor || echo \"\${GIT_EDITOR:-${EDITOR:-vi}}\")\" \"\$1.reverse\" \
    && tac \"\$1.reverse\" > \"\$1\"' rebase -i"
    git revbase @~10
    

    Here's an approach that keeps the commented-out interactive-rebase hints on the bottom, and changes the line "top to bottom" to "bottom to top".

    function gri {
        local cmd='
            grep -v "^#\|^\$" "$1" | tac >"$1.reverse" &&
            grep "^#\|^\$" "$1" | sed "s/top to bottom/bottom to top/" >"$1.hints" &&
            cat "$1.reverse" "$1.hints" >"$1.gri" &&
            $EDITOR "$1.gri" &&
            tac "$1.gri" >"$1"'
        git -c sequence.editor="$cmd" rebase -i "$@"
    }