Как изменить несколько коммитов в Git, чтобы сменить автора

180

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

Я смотрел на git resetи git commit -C <id> --reset-author, но я не думаю, что я на правильном пути.

pauldoo
источник
1
Другая причина, по которой вы можете захотеть изменить свойство электронной почты, - это ошибка github: remote: error: GH007: Your push would publish a private email address.... `! [удалено отклонено] master -> master (push отклонено из-за ограничений конфиденциальности электронной почты) `.
18:15
Также см. Stackoverflow.com/q/750172/1340631 .
Scai

Ответы:

232

Перебазировать / изменить кажется неэффективным, когда у вас под рукой есть сила ответвления фильтра:

git filter-branch --env-filter 'if [ "$GIT_AUTHOR_EMAIL" = "incorrect@email" ]; then
     GIT_AUTHOR_EMAIL=correct@email;
     GIT_AUTHOR_NAME="Correct Name";
     GIT_COMMITTER_EMAIL=$GIT_AUTHOR_EMAIL;
     GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; fi' -- --all

(разделить на несколько строк для ясности, но не обязательно)

Не забудьте проверить результат, когда закончите, чтобы убедиться, что вы не изменили ничего, что не хотели!

Cascabel
источник
возражаете объяснить это немного больше? не уверен, что такое ветвь фильтра
Макс Плинер
1
@maxpleaner git filter-branch --helpдовольно прост :)
alediaferia
3
см. также help.github.com/articles/changing-author-info , который также добавляет --tag-name-filter catдля filter-branchтого, чтобы перенести теги в новую историю. --branches --tagsВместо этого он также использует --all, который переписывает только историю ветвей и тегов и оставляет других в refsпокое (хотя это, вероятно, не имеет большого значения, если, например, вы не используете git-notes)
Тобиас Кинцлер,
12
чтобы выполнить это только на двух последних -- --allHEAD~1..HEAD
коммитах
1
@ nmz787 Сколько журналов отображается, если вы делаете git log HEAD~2..HEAD?
Джон
148

Интерактивный подход к перебазированию довольно хорош, когда используется в сочетании с exec. Вы можете запустить любую команду оболочки для определенного коммита или всех коммитов в ребазе.

Сначала установите ваши настройки git author

git config --global user.name "John Doe"
git config --global user.email johndoe@example.com

Затем сбросить автора для всех коммитов после данного SHA

git rebase -i YOUR_SHA -x "git commit --amend --reset-author -CHEAD"

Откроется ваш редактор, чтобы подтвердить изменения. Все, что вам нужно сделать, это сохранить и выйти, и он будет проходить каждый коммит и запускать команду, указанную в флаге -x.

Согласно приведенному ниже комментарию @ Dave, вы также можете сменить автора, сохранив при этом оригинальные временные метки:

git rebase -i YOUR_SHA -x "git commit --amend --author 'New Name <new_address@example.com>' -CHEAD"
Alex
источник
3
Спасибо, что познакомили меня с опцией -x. Это довольно круто! для опции -i я использовал HEAD ~ 4, чтобы исправить свой адрес электронной почты в моих последних 4 коммитах. работал как шарм.
Брэд Хейн
2
Это гораздо проще, чем filter-branchесли вы просто хотите исправить свои последние коммиты :). Тем не менее, обратите внимание, что это изменяет временную метку коммитов.
Луатор
24
Чтобы изменить автора, но сохранить исходные метки времени, используйтеgit rebase -i YOUR_SHA -x "git commit --amend --author 'New Name <new_address@example.com>' -CHEAD"
Dave
2
@Connor git logтакже показывал для меня старое авторство, но git status правильно идентифицировал новые коммиты, и после принудительного нажатия они были, как я и предполагал.
Дэн М.
6
Чтобы перебазировать все коммиты, включая root, используйте: git rebase -i --root …вместо передачи SHA.
gfullam
80

Чтобы изменить автора только для последнего коммита:

git commit --amend --author 'Author Name <author.name@mail.com>' --no-edit

Предположим, вы хотите изменить автора только для последних N коммитов:

git rebase -i HEAD~4 -x "git commit --amend --author 'Author Name <author.name@mail.com>' --no-edit"

НОТЫ

  • --no-editфлаг убеждаетсяgit commit --amend не требует дополнительного подтверждения
  • когда вы используете git rebase -i, вы можете вручную выбрать коммиты, где сменить автора,

файл, который вы редактируете, будет выглядеть так:

pick 897fe9e simplify code a little
pick abb60f9 add new feature
exec git commit --amend --author 'Author Name <author.name@mail.com>' --no-edit
pick dc18f70 bugfix
Крис Мэйс
источник
1
для всех коммитов от root. git rebase -i --root UPTO_COMMIT_SHA -x "git commit --amend --author 'NEW_CHANGE' --no-edit"
Ашиш Неги,
1
Я рекомендую добавить --rebase-merges(короткий -r) параметр, чтобы сохранить топологию вашей ветви нетронутой, если она содержит некоторые слияния.
Donquixote
4

Этот метод был задокументирован github для этой цели. Шаги:

  1. Откройте терминал и сделайте голый клон своего репо
git clone --bare https://github.com/user/repo.git
cd repo
  1. Редактировать следующий скрипт (замена OLD_EMAIL, CORRECT_EMAILи CORRECT_NAME)
#!/bin/sh

git filter-branch --env-filter '
OLD_EMAIL="your-old-email@example.com"
CORRECT_NAME="Your Correct Name"
CORRECT_EMAIL="your-correct-email@example.com"
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
  1. Скопируйте / вставьте скрипт в свой терминал и нажмите Enter, чтобы запустить его.
  2. Нажмите ваши изменения с, git push --force --tags origin 'refs/heads/*'и все готово!
stevec
источник
Я следовал тем же инструкциям на GitHub, на которые вы ссылались, и GitHub выглядит прямо сейчас. Тем не менее, я новичок в Git и не знаю, как синхронизировать мое локальное хранилище после этого. Когда я тяну, я получаю ту же ошибку «отказ от слияния несвязанных историй», упомянутую в другом ответе. Я думаю, что мне нужно сделать упор на эту новую историю коммитов, но я очень ценю более конкретные шаги.
загадка
@enigment Если вы довольны репо, как это делается на GitHub, вы можете удалить (или, возможно, переместить в другое место) папку, которую вы локально и просто клонировать из
GitHub
Спасибо, я знаю, но это не похоже на идиоматический способ GitHub / Git.
загадка
2

Я считаю, что вы ищете git rebase --interactive

Это позволяет вам выполнить сброс до определенного коммита, а затем перейти к изменению истории добавления или группировки коммитов.

Здесь у вас есть объяснение https://web.archive.org/web/20100213104931/http://blog.madism.org/index.php/2007/09/09/138-git-awsome-ness-git-rebase -interactive

Фернандо Диас Гарридо
источник
0

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

git reset HEAD~ (отменить последний коммит)

git config --global user.name "Your Name"

git config --global user.email you@example.com

git commit -m "message"

Эдисон
источник