Как запустить git rebase --interactive неинтерактивным способом?

Можно ли сделать следующее?

  1. Делать git rebase --interactive просто выводить стандартный шаблон в файл, а не выводить в файл и открывать его в редакторе.
  2. Позвольте пользователю редактировать файл.
  3. Позвольте пользователю повторно запустить git rebase с именем отредактированного файла.
  4. Продолжайте с обычным процессом ребазирования.

Вариант использования: перебазирование по сценарию, конечно. Посмотрите, как переупорядочить коммиты в Git неинтерактивно, например.

11 ответов

Решение

После некоторых размышлений и исследований ответ оказался тривиальным: git rebase -i берет имя редактора из известных переменных среды EDITOR/VISUAL, поэтому переопределение, указывающее на неинтерактивный скрипт, делает свою работу.

Тем не менее, EDITOR/VISUAL применяется безразлично к списку коммитов, коммитов сообщений при переписывании и всего остального. Итак, поскольку http://git.kernel.org/?p=git/git.git;a=commit;h=821881d88d3012a64a52ece9a8c2571ca00c35cd, существует специальная переменная окружения GIT_SEQUENCE_EDITOR, которая применяется только к списку коммитов.

Итак, рецепт для переупорядочения или выравнивания коммитов:

Бежать: GIT_SEQUENCE_EDITOR=<script> git rebase -i <params>, Ваш <script> должен принимать один аргумент: путь к файлу, содержащему стандартный список изменений rebase. Следует переписать его на месте и выйти. Обычная обработка rebase происходит после этого.

Добавляя к ответу @pfalcon, вы можете использовать sed в качестве GIT_SEQUENCE_EDITOR. Например, я хотел редактировать каждый коммит, поэтому я сделал это:

GIT_SEQUENCE_EDITOR="sed -i -re 's/^pick /e /'" git rebase -i

Я использую этот скрипт (в add он позволяет упростить разбиение коммитов):

#!/bin/bash

ACTION=$1
COMMIT=$(git rev-parse --short $2)
[[ "$COMMIT" ]] || exit 1
CORRECT=
for A in p pick r reword e edit s squash f fixup x exec d delete t split; do
     [[ $ACTION == $A ]] && CORRECT=1
done 
[[ "$CORRECT" ]] || exit 1
if [[ $ACTION == "delete" || $ACTION == "d" ]]; then
    GIT_SEQUENCE_EDITOR="sed -i -e '/^pick $COMMIT/d'" git rebase -i $COMMIT^^
elif [[ $ACTION == "split" || $ACTION == "t" ]]; then
    GIT_SEQUENCE_EDITOR="sed -i -e 's/^pick $COMMIT/edit $COMMIT/'" git rebase -i $COMMIT^^ || exit 1
    git reset --soft HEAD^
    echo "Hints:"
    echo "  Select files to be commited using 'git reset', 'git add' or 'git add -p'"
    echo "  Commit using 'git commit -c $COMMIT'"
    echo "  Finish with 'git rebase --continue'"
else
    GIT_SEQUENCE_EDITOR="sed -i -e 's/^pick $COMMIT/$1 $COMMIT/'" git rebase -i $COMMIT^^
fi

Добавьте псевдоним в ваш.gitconfig:

[alias]
  autorebase = ! path_to_your_script

Расширяя ответ pfalcon:

Бежать GIT_SEQUENCE_EDITOR=<script> git rebase -i <params>, <script> должен принимать один аргумент - путь к файлу, содержащему стандартный список изменений rebase. Скрипт должен переписать его на месте и выйти. Обычная обработка rebase происходит после этого.

Если у вас есть переменная среды, которая содержит содержимое, которое вы хотите:

GIT_SEQUENCE_EDITOR='echo "$REBASE_DATA" >' git rebase -i [<additional params>]

Catting файл тоже будет работать:

GIT_SEQUENCE_EDITOR='cat rebase_data_file >' git rebase -i [<additional params>]

Чтобы сделать именно то, что задает исходный вопрос, используйте sed -i '1s/^/b\n/'как ваш редактор

      git -c sequence.editor="sed -i '1s/^/b\n/'" rebase --interactive

Объяснение

  • git -cуказывает на запуск следующей команды git с указанным параметром
  • sequence.editorпараметр, определяющий «редактора», который будет редактировать файл redbase-todo
  • sed -iзапустить команду sed на месте
    • 1sна первой линии
    • ^соответствовать началу
    • b\nвставка и новая строка \nперсонаж. bили же breakэто команда rebase для остановки интерактивной перебазировки.
  • rebase --interactiveзапустить команду перебазирования

Это немедленно останавливает интерактивную перебазировку. Теперь вы можете редактировать .git/rebase-merge/git-rebase-todoи беги git rebase --continue.

Ты можешь использовать touch как редактор, который будет касаться файла, так что он будет выглядеть измененным. Например

GIT_SEQUENCE_EDITOR=touch git rebase -i [commit]

Для псевдонима это, учитывая baseline как тег, который я хочу перебазировать против

git config alias.baseline '!GIT_SEQUENCE_EDITOR=touch git rebase -i baseline'

Псевдоним работает под Windows, потому что выполняемая им оболочка bash не cmd,

Интерактивные режимы вызывают редактор настроек для работы с.
используемый редактор можно получить с помощью:

git config --get core.editor

Итак, если вы установили неинтерактивный редактор - это редактор, который принимает команды на stdin, вы можете работать с --interactive неинтерактивным способом:)
Я точно знаю vim принимает команды, как и стандартный редактор ed, конечно.

так что держите интерактивный редактор (если хотите)

$ ied="$(git config --get core.editor)"

установить неинтерактивный редактор

$ git config --unset-all core.editor
$ git config --add core.editor ed

и работать с ним..

$ printf '%s\n' "some-ed-cmd" "another-ed-cmd" "wq" | git rebase -i HEAD~5

и восстановите редактор (если хотите)

$ git config --unset-all core.editor
$ git config --add core.editor "$ied"

Я нашел решение. Вы можете использовать:

$ GIT_SEQUENCE_EDITOR=true git rebase -i --autosquash $COMMIT_HASH~1

На основе всех ответов я сделал небольшой скрипт:

      reword() {
    COMMITHASH=$1
    GIT_SEQUENCE_EDITOR="sed -i -re 's/^pick $COMMITHASH/r $COMMITHASH/'" git rebase -i $COMMITHASH~
}

Например, если вы хотите перефразировать коммит3d4e4bdc, вы можете просто запустить следующую команду в своем терминале:

      reword 3d4e4bdc

Вы можете добавить его в свой файлmy_aliases.zshили.bashrc

ПРИМЕЧАНИЕ. Этот пример предназначен для изменения слова. Если вы хотите отредактировать коммит, вы можете заменить$COMMITHASH/rк$COMMITHASH/e

Как уже упоминали другие, вам необходимо предоставить пользовательский GIT_SEQUENCE_EDITORзначение, которое изменит интерактивный файл перебазирования. Если вы просто хотите выполнить действие с одной фиксацией, вы можете сделать это следующим образом:

# Runs "edit" on HEAD~3
GIT_SEQUENCE_EDITOR="sed -i -ze 's/^pick/edit/'" git rebase -i HEAD~3

В качестве альтернативы, вот функция, чтобы обобщить это:

# Usage: git-rebase-custom edit HEAD~3
git-rebase-custom() {
    local action=$1
    shift

    GIT_SEQUENCE_EDITOR="sed -i -ze 's/^pick/$action/'" git rebase -i "$@"
}

Основываясь на ответе Джезза, я создал независимый от оболочки скрипт ( GitReb), который работает с ревизиями с несколькими аргументами, :/<text> синтаксис, root commit, а также делает некоторые проверки работоспособности.

Я также сделал это проще и удалил t / split действие и delete -> drop преобразование, которое IMO выходит за рамки этого сценария.

Другие вопросы по тегам