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

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

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

Вариант использования: конечно, скриптовый ребазинг. См. как изменить порядок коммитов в Git в неинтерактивном режиме например.


person pfalcon    schedule 12.09.2012    source источник
comment
См. stackoverflow.com/questions/12270357/really-flatten- a-git-merge, где это тоже может быть полезно.   -  person pfalcon    schedule 12.09.2012
comment
Помимо git rebase ниже, еще одним вариантом является git filter-branch: stackoverflow.com/questions/19636750/   -  person MarcH    schedule 09.11.2016


Ответы (9)


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

person pfalcon    schedule 12.09.2012
comment
не знал GIT_SEQUENCE_EDITOR, кажется полезным;) - person c00kiemon5ter; 12.09.2012
comment
Или вместо создания сценария для этой единственной цели просто используйте существующую команду true, которая игнорирует любые аргументы и имеет фиксированный код возврата 0. - person me_and; 13.09.2012
comment
@me_ и это помогает только в том случае, если вы хотите сделать rebase -i без фактического изменения порядка коммитов. - person Paŭlo Ebermann; 08.07.2014
comment
Вот еще один пример, в котором исправлена ​​опечатка в последних пяти сообщениях о фиксации: EDITOR="sed -i -e 's/borken/broken/g'" GIT_SEQUENCE_EDITOR="sed -i -e 's/pick/reword/g'" git rebase -i HEAD~5 - person MarcH; 24.03.2015
comment
По какой-то неизвестной причине EDITOR теперь игнорируется git --version 2.5.5. С другой стороны, VISUAL все еще работает. Итак, вот еще один пример повторного создания 5 последних идентификаторов изменений. Предполагается, что установлен обработчик фиксации Gerrit. VISUAL="sed -i -e '/^[[:blank:]]*Change-Id/ d'" GIT_SEQUENCE_EDITOR="sed -i -e 's/pick/reword/g'" git rebase -i HEAD~5 . Успешно протестирован с git версии 2.5.5 - person MarcH; 09.11.2016
comment
Также: убедитесь, что git config --global core.editor возвращается пустым. - person MarcH; 09.11.2016
comment
Я обнаружил, что VISUAL также не работает в моей попытке автоматическая перезагрузка git, но GIT_EDITOR работает. - person John Vandenberg; 25.09.2017
comment
@MarcH: Пожалуйста, укажите альтернативы в комментариях к чьему-либо ответу (а лучше в собственном ответе), а не путем редактирования контента, который имеет чью-то подпись. Спасибо. - person pfalcon; 28.10.2017
comment
И EDITOR, и VISUAL работали у меня. git-2.26.0. - person x-yuri; 13.05.2020

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

GIT_SEQUENCE_EDITOR="sed -i -re 's/^pick /e /'" git rebase -i
person Leif Wickland    schedule 13.03.2013

Переменная GIT_SEQUENCE_EDITOR изначально использовалась для изменения редактора. В эту переменную можно передать сценарий, чтобы использовать git rebase -i неинтерактивным образом. Итак, можно использовать:

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

Эта команда запустит sed в файле, предоставленном git rebase -i. Он изменит строку pick 134567 на e 1234567 (и, таким образом, отредактируйте фиксацию 1234567). Вы можете изменить e с помощью r (переработка), f (исправление), s (сквош) или d (сброс) (последнее не поддерживается старыми версиями git).

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

#!/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 d drop t split; do
     [[ $ACTION == $A ]] && CORRECT=1
done 
[[ "$CORRECT" ]] || exit 1
git merge-base --is-ancestor $COMMIT HEAD || exit 1
if [[ $ACTION == "drop" || $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

Первым аргументом должно быть одно действие. В сценарии используются те же имена действий, что и в git-rebase. Он также добавляет действие «split» (и позволяет использовать drop со старыми версиями git).

Он также проверяет, является ли запрашиваемая вами фиксация предком HEAD. Это распространенная (и действительно досадная) ошибка с rebase -i.

Второй аргумент - это фиксация, которую нужно отредактировать / удалить / разделить / перефразировать.

Затем вы добавляете псевдоним в свой .gitconfig:

[alias]
  autorebase = ! path_to_your_script
person Jérôme Pouiller    schedule 09.10.2013
comment
Хороший ответ, спасибо! Не могли бы вы добавить комментарии, чтобы немного объяснить, что делает каждый шаг? - person Hadrien TOMA; 29.05.2020

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

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

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

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

Размещение файла тоже подойдет:

GIT_SEQUENCE_EDITOR='cat rebase_data_file >' git rebase -i [<additional params>]
person James Foucar    schedule 22.05.2014

Вы можете использовать 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.

person Archimedes Trajano    schedule 14.05.2016
comment
Это хорошо работает с git --interactive --exec <cmd> <branch>. Я установил <cmd> на команду, которая запускает тесты, введенные или измененные моей веткой, а <branch> на master. Это заставляет git запускать мои тесты для каждой фиксации в ветке. - person Mike; 11.10.2017
comment
Вы можете использовать родные aliases от git, используя -c sequence.editor=touch вместо GIT_SEQUENCE_EDITOR. Например, в вашем разделе .gitconfig [alias]: rs = -c sequence.editor=touch rebase --interactive --autosquash --autostash. - person nh2; 06.06.2020

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

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"
person c00kiemon5ter    schedule 12.09.2012
comment
Спасибо, наверное, мы начали писать ответы примерно в одно и то же время, я не видел ваших, пока не отправил свои ;-) - person pfalcon; 12.09.2012
comment
Я думаю, что проще переопределить EDITOR для каждого сеанса или для каждой команды. - person MarcH; 24.03.2015
comment
Я настоятельно не рекомендую делать git config --unset-all или что-то еще, что может изменить файл конфигурации пользователя в сценарии. Чтобы установить переменную конфигурации git для одной команды, используйте git -c var=val, и в этом случае установка EDITOR намного проще. Это переменная среды, поэтому применяется только к текущему процессу, она не мешает другим процессам и не записывает что-либо на диск. - person Matthieu Moy; 14.05.2016
comment
Я обнаружил, что настройка EDITOR больше не работает, и мне нужно было использовать вместо нее GIT_EDITOR. - person John Vandenberg; 25.09.2017

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

$ GIT_SEQUENCE_EDITOR=true git rebase -i --autosquash $COMMIT_HASH~1
person Wooseong Kim    schedule 08.08.2019

Как уже упоминали другие, вам необходимо предоставить настраиваемое значение 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 "$@"
}
person Matthew D. Scholefield    schedule 04.08.2019
comment
Следует указывать $ 1 и $ @ - person D. Ben Knoble; 04.08.2019
comment
Цитирование не имеет значения при назначении переменных, но я удалил присвоение variables, потому что он будет принимать только первый дополнительный аргумент, если не используется присвоение массива. - person Matthew D. Scholefield; 04.08.2019

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

Я также упростил его и удалил действие _2 _ / _ 3_ и преобразование _4 _-> _ 5_, которые IMO выходят за рамки этого сценария.

person John Gliksberg    schedule 23.02.2017