Git, переписать имена пользователей и электронные письма предыдущих коммитов

170

Я совершил кучу коммитов в проекте на Github, однако я понял, что не настроил правильную электронную почту и полное имя коммиттера на компьютере, который я сейчас использую, чтобы сделать свои коммиты, и, следовательно, аватар пользователя и адрес электронной почты не там

Как я могу переписать всю электронную почту и имена пользователей за последние коммиты?

JP Silvashy
источник
9
Возможный дубликат Как мне изменить автора коммита в git?
Givanse
Я испытал это после изменения адреса электронной почты в моей учетной записи GitHub. Помимо отправки изменений кода из локального репозитория git с помощью интерфейса командной строки git (а не рабочего стола GitHub), я также редактировал текстовые и управляемые файлы непосредственно из удаленного репозитория git с помощью веб-интерфейса GitHub. Новый адрес электронной почты распространяется только на коммиты, полученные в результате последних действий, а не на первые.
Роберт Джон

Ответы:

244

Вы можете добавить этот псевдоним:

git config alias.change-commits '!'"f() { VAR=\$1; OLD=\$2; NEW=\$3; shift 3; git filter-branch --env-filter \"if [[ \\\"\$\`echo \$VAR\`\\\" = '\$OLD' ]]; then export \$VAR='\$NEW'; fi\" \$@; }; f "

Чтобы изменить имя автора:

git change-commits GIT_AUTHOR_NAME "old name" "new name"

или по электронной почте только за последние 10 коммитов:

git change-commits GIT_AUTHOR_EMAIL "old@email.com" "new@email.com" HEAD~10..HEAD

Alias:

change-commits="!f() { VAR=$1; OLD=$2; NEW=$3; shift 3; git filter-branch --env-filter \"if [[ \\\"$`echo $VAR`\\\" = '$OLD' ]]; then export $VAR='$NEW'; fi\" \$@; }; f "

Источник: https://github.com/brauliobo/gitconfig/blob/master/configs/.gitconfig

brauliobo
источник
13
Также, git change-commits GIT_COMMITTER_EMAIL "old@example.com" "new@example.com"чтобы изменить адрес электронной почты коммиттера.
Лоран
20
исправлено: «eval: [[: not found» в ubuntu и добавление подтвержденияchange-commits = "!f() { VAR1=$1; VAR='$'$1; OLD=$2; NEW=$3; echo \"Are you sure for replace $VAR $OLD => $NEW ?(Y/N)\";read OK;if [ \"$OK\" = 'Y' ] ; then shift 3; git filter-branch --env-filter \"if [ \\\"${VAR}\\\" = '$OLD' ]; then export $VAR1='$NEW';echo 'to $NEW'; fi\" $@; fi;}; f "
qxo
9
git: 'change-commits' не является командой git. Смотрите «git --help». Означает, что вы не добавили псевдоним в вашу конфигурацию git. например, git config -e
Уэйн
3
Это только сделало дубликаты всех коммитов с электронной почтой, которую я хотел изменить. Не похоже переписать историю. Решение @Olivier Verdier сработало для меня.
Джейк Уилсон
7
Выполнение этого два раза подряд с разными входами приводит к:Cannot create a new backup. A previous backup already exists in refs/original/
theonlygusti
98

Смотрите здесь :

git filter-branch -f --env-filter \
"GIT_AUTHOR_NAME='Newname'; GIT_AUTHOR_EMAIL='newemail'; \
GIT_COMMITTER_NAME='committed-name'; GIT_COMMITTER_EMAIL='committed-email';" HEAD
Оливье Вердиер
источник
4
не изменит ли это имя автора для всех коммитов (всей истории) ветки?
hasen
2
Да, это изменило бы все коммиты на новую информацию об авторе.
ewall
9
Пожалуйста, помечайте вопросы как дубликаты, а не копируйте, вставляя ответ.
Givanse
2
Что делать, если я не указал старое имя или старый адрес электронной почты? мерзавец говорит: «пустой идентификатор <> не разрешен»
Griffan
Я выполнил эту команду, и теперь мое хранилище не будет отправлять или извлекать данные с сервера git.
Иисус Х
46

Если вы уже отправили некоторые из ваших коммитов в общедоступный репозиторий, вы не хотите делать это, или это сделает альтернативную версию истории мастера, которую могли бы использовать другие. «Не пересекать потоки ... Это было бы плохо ...»

Тем не менее, если это только коммиты, которые вы сделали в своем локальном репозитории, то обязательно исправьте это, прежде чем отправлять на сервер. Вы можете использовать git filter-branchкоманду с этой --commit-filterопцией, чтобы она редактировала только коммиты, соответствующие вашей неверной информации, например:

git filter-branch --commit-filter '
      if [ "$GIT_AUTHOR_EMAIL" = "wrong_email@wrong_host.local" ];
      then
              GIT_AUTHOR_NAME="Your Name Here (In Lights)";
              GIT_AUTHOR_EMAIL="correct_email@correct_host.com";
              git commit-tree "$@";
      else
              git commit-tree "$@";
      fi' HEAD
ewall
источник
5
Это прекрасно работает, тогда как ответ, отмеченный зеленым, не сработал
jmary
После этого можно очистить резервную копию git update-ref -d refs/original/refs/heads/master, см. < Stackoverflow.com/a/7654880/333403 >.
cннкол
К вашему сведению: если у вас есть несколько неправильных имен / адресов электронной почты, вам может потребоваться выполнить это несколько раз. Если это произойдет, он будет жаловаться на вас с этой ошибкой: A previous backup already exists in refs/original/в этом случае, запустите его заново, с новым письмом, и добавьте -fперед --commit-filter. Используйте по своему усмотрению. Обычно -fопасно обходиться без знания того, что он делает.
Чак
19

После применения ответа Оливье Вердиера:

git filter-branch -f --env-filter \
"GIT_AUTHOR_NAME='Newname'; GIT_AUTHOR_EMAIL='newemail'; \
GIT_COMMITTER_NAME='committed-name'; GIT_COMMITTER_EMAIL='committed-email';" HEAD

... протолкнуть измененную историю в исходное использование репозитория:

git push origin +yourbranch

Приведенная выше команда (обратите внимание на плюс) также принудительно переписывает историю в исходном репо. Используйте с осторожностью!

sarusso
источник
Работал у меня, также правильно переписал историю на происхождение.
Xeverous
10
Это собирается переписать ВСЕ коммиты - независимо от того, кто их написал. Используйте с осторожностью.
Бхавин Доши
14

https://help.github.com/articles/changing-author-info/

#!/bin/sh

git filter-branch --env-filter '

OLD_EMAIL="oldEmail@xxx-MacBook-Pro.local"
CORRECT_NAME="yourName"
CORRECT_EMAIL="yourEmail"

if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]
then
    export GIT_COMMITTER_NAME="$CORRECT_NAME"
    export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
fi
if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]
then
    export GIT_AUTHOR_NAME="$CORRECT_NAME"
    export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
fi
' --tag-name-filter cat -- --branches --tags

это полностью сработало для меня. После git push убедитесь, что вы видите обновление на веб-портале git. Если фиксация все еще не была связана с моей учетной записью, рядом с фиксацией показывалось уменьшенное изображение по умолчанию, и это не было отражено в моей временной шкале вклада, перейдите к URL фиксации и добавьте .patch в конце URL-адреса и проверьте имя и адрес электронной почты верны.

Jacccck
источник
Хотя это может теоретически ответить на вопрос, было бы предпочтительным включить сюда основные части ответа и предоставить ссылку для справки.
jhpratt
1
Это единственный переписывающий все ветки.
Бруно Целль
6

Для тех, кому нужна просто версия для копирования (кроме обновления писем и имён):

git config alias.change-commits '!'"f() { VAR=\$1; OLD=\$2; NEW=\$3; shift 3; git filter-branch --env-filter \"if [[ \\\"\$\`echo \$VAR\`\\\" = '\$OLD' ]]; then export \$VAR='\$NEW'; fi\" \$@; }; f "
git change-commits GIT_AUTHOR_NAME "<Old Name>" "<New Name>" -f
git change-commits GIT_AUTHOR_EMAIL <old@email.com> <new@email.com> -f
git change-commits GIT_COMMITTER_NAME "<Old Name>" "<New Name>" -f
git change-commits GIT_COMMITTER_EMAIL <old@email.com> <new@email.com> -f
Ник Кузня
источник
5
-bash:! f: событие не найдено
Saiyine
Скорее всего, проблема с терминалом, автоматически сбегающим
Андрей Савин,
3

Учитывая использование git-filter-branchявляется не требуется , чтобы сделать то же самое в GIT-фильтр-репо (возможно , потребуется установить его первый с pip install git-filter-repo):

git-filter-repo --name-callback 'return name.replace(b"OldName", b"NewName")' --email-callback 'return email.replace(b"old@email.com", b"new@email.com")'

Если репозиторий является оригинальным, без удаленного доступа, вам придется добавить --forceпринудительную перезапись. (Вы можете создать резервную копию вашего репо, прежде чем делать это.)

Если вы не хотите сохранять ссылки (они будут отображаться в истории веток Git GUI), вам придется добавить --replace-refs delete-no-add.

Дополнительные функции см. В разделе «Фильтрация имен и писем» .

PS Украдено и улучшено с https://stackoverflow.com/a/59591928/714907 .

Пагсли
источник