Git Сквош по автору - весь автор совершает одно фиксирование
Я пытаюсь скворовать много коммитов в один, проблема в том, что мне нужно сделать это по автору (имя или адрес электронной почты).
Случай:
Допустим, у меня есть ветвь с именем feature-a, в этой ветки у меня много коммитов для многих авторов. Как я могу скворовать все коммиты от автора (например, по электронной почте) в один коммит. Я хочу сделать это, чтобы объединить все авторские коммиты в мастер.
Любая помощь здесь?
Заранее спасибо
Ответы
Ответ 1
Будьте осторожны, переписывая историю
Конечный результат, который вы хотите, может быть возможен, если вы создаете ветки для каждого автора, cherry-pick коммиты каждого автора в правильную ветвь, а затем раздавить эти изменения. Тем не менее, я не думаю, что это сработает, если эти обязательства будут значимо зависеть друг от друга.
Если у вас есть серия коммитов:
Author1 Author2 Author1
version1 ---commit---> version2 ---commit---> version3 ---commit--->...
Если вы попытаетесь извлечь изменения из Author2 и применить их к версии 1, то есть хороший шанс, что это не будет иметь смысла (например, если Author2 изменяет код, созданный Author1).
Ответ 2
С учетом Kenkron оговорок вы можете сделать следующее:
SORTED_GIT_LOGS=$(git log --pretty="format:%an %H" master..feature_a | sort -g | cut -d' ' -f2); \
IFS=$(echo -en "\n\b"); for LOG in $SORTED_GIT_LOGS; do \
git cherry-pick $LOG; \
done | less
git log --pretty="format:%an %H" master..feature_a | sort -g
будет сортировать журналы feature_a
commits (а не те из master
из-за синтаксиса master..feature_a
)
Вам все равно нужно сделать интерактивную переадресацию для сквоша (теперь упорядоченного по автору) совершает на master
.
Ответ 3
Мне нужно было сделать подобный переписывание на ненужном большом хранилище, в то время как репо было отключено. Подход, который я использовал, заключался в автоматическом "интерактивном" переадресации с использованием GIT_SEQUENCE_EDITOR
, который рассматривается в этом ответе @james-foucar и @pfalcon.
Чтобы это хорошо работало, мне было лучше сначала удалить слияния из раздела переписываемой истории. Для моего собственного случая это было сделано с помощью большого количества git rebase --onto
, которое подробно рассматривается в других вопросах в StackOverflow.
Я создал small script generate-similiar-commit-squashes.sh
для создания команд pick
и squash
, чтобы последовательные подобные коммиты быть раздавленным. Я использовал author-date-and-shortlog для сопоставления с подобными коммитами, но вам нужен только автор (у моего gist есть комментарий о том, как сделать его совпадающим только с автором).
$ generate-similiar-commit-squashes.sh > /tmp/git-rebase-todo-list
Выход выглядит как
...
pick aaff1c556004539a54a7a33ce2fb859af0c4238c [email protected]
squash aa190ea2323ece42f1cd212041bf61b94d751d5c [email protected]
pick aab8c98981a8d824d2bc0d5278d59bc1a22cc7b0 [email protected]_config.yml
Репозиторий также был полон самовосстановления с тем же сообщением "Обновить xyz". Когда раздавили, они привели к пустым коммитам.
У коммитов, которые были слияния, были одинаковые сообщения фиксации. git rebase -i
предлагает пересмотренное сообщение фиксации со всеми сжатыми сообщениями о фиксации, которые были бы повторяющимися. Чтобы решить эту проблему, я использовал небольшой perl script из этого ответа, чтобы удалить повторяющиеся строки из сообщения фиксации, предлагаемого git rebase
. Это лучше в файле, так как оно будет использоваться в переменной оболочки.
$ echo 'print if ! $x{$_}++' > /tmp/strip-seen-lines.pl
Теперь для последнего шага:
$ GIT_EDITOR='perl -i -n -f /tmp/strip-seen-lines.pl ' \
GIT_SEQUENCE_EDITOR='cat /tmp/git-rebase-todo-list >' \
git rebase --keep-empty -i $(git rev-list --max-parents=0 HEAD)
Несмотря на использование --keep-empty
, git
несколько раз жаловался на этот процесс о пустых коммитах. Это вывело бы меня на консоль с неполным git rebase
. Чтобы пропустить пустую транзакцию фиксации и возобновления, необходимы две команды (довольно часто в моем случае).
$ git reset HEAD^
$ GIT_EDITOR='perl -i -n -f /tmp/strip-seen-lines.pl ' git rebase --continue
Снова, несмотря на --keep-empty
, я обнаружил, что не имел пустых коммитов в последней истории git, поэтому сброс выше удалил их все. Я предполагаю, что что-то не так с моей версией git, версии 2.14.1. Обработка ~ 10000 таких как это заняла чуть более 10 минут на дерьмовом ноутбуке.