Как запустить git rebase --interactive неинтерактивным способом?
Можно ли сделать следующее?
- Делать
git rebase --interactive
просто выводить стандартный шаблон в файл, а не выводить в файл и открывать его в редакторе. - Позвольте пользователю редактировать файл.
- Позвольте пользователю повторно запустить
git rebase
с именем отредактированного файла. - Продолжайте с обычным процессом ребазирования.
Вариант использования: перебазирование по сценарию, конечно. Посмотрите, как переупорядочить коммиты в 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 выходит за рамки этого сценария.