git remove выполняет неинтерактивную фиксацию

Я хочу не в интерактивном режиме удалить из моей истории неотправленные коммиты, содержащие ключевое слово темы (аналогично интерактивной перебазировке, когда строки, содержащие ключевое слово, удаляются).

Следующая функция nocommit в ~/.gitconfig достигает почти того, что я хочу, за исключением того, что создается новая результирующая ветвь.

nocommit = "!f() { \
    for i in `git log --oneline FETCH_HEAD.. |grep NOCOMMIT | awk '{ print $1 }'`; \
    do \
        git log -n1 --oneline $i; \
        git rebase --onto $i^ $i HEAD; \
    done; \
}; f"

Это также должно быть возможно сделать с помощью хука git push, но у нас уже есть три хука, которые я не хочу модифицировать.

Редактировать: решено с помощью этой команды (вдохновлено ответом Эндрю С):

GIT_EDITOR="sed -i '/NOCOMMIT/d'" git rebase -i @{upstream}

git
person badeip    schedule 20.09.2014    source источник
comment
Боюсь, это не гарантирует неинтерактивности. Всякий раз, когда вы удаляете фиксацию из истории, существует риск возникновения конфликтов, которые необходимо разрешать в интерактивном режиме.   -  person Pavel Šimerda    schedule 21.09.2014


Ответы (1)


Несколько комментариев.

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

Первую строку вашего скрипта, вероятно, лучше было бы написать как

for i in `git rev-list --grep=NOCOMMIT @{u}..HEAD`

Использование FETCH_HEAD не является хорошим способом ограничить количество коммитов, и наличие каналов для grep и awk не требуется.

Чтобы сделать его более перебазированным, вам нужно будет отслеживать ORIG_HEAD, извлекать новую ветку из git merge-base ORIG_HEAD ${u}, затем запускать коммиты от самого старого к самому новому (--reverse), выбирая все, в которых нет NOCOMMIT, а затем обновить ветку в конце.

Другим вариантом было бы обмануть интерактивную перебазировку, чтобы она делала то, что вы хотите, сохранив настройки вашего редактора и заменив их сценарием, который просто удалял строки, содержащие NOCOMMIT. Таким образом, у вас будет обычный вызов git rebase -i, но вместо того, чтобы получить окно редактора, sed просто удалит ненужные вам коммиты, и он продолжится.

person Andrew C    schedule 20.09.2014
comment
Указание альтернативного редактора для rebase -i кажется привлекательным, но по какой-то причине мне не удалось заставить его работать: GIT_EDITOR=grep -v NOCOMMIT git rebase -i HEAD~5 - person badeip; 21.09.2014
comment
grep не собирается сохранять полученный файл. попробуй sed -i '/NOCOMMIT/d' - person Andrew C; 21.09.2014