Как изменить автора коммита для одного конкретного коммита?

1642

Я хочу сменить автора одного конкретного коммита в истории. Это не последний коммит.

Я знаю об этом вопросе - как мне изменить автора коммита в git?

Но я думаю о чем-то, где я идентифицирую коммит по хешу или короткому хешу.

Теги:
git-commit

9 ответов

2672
Лучший ответ

Интерактивная перебазировка с точки ранее в истории, чем коммит, который вам нужно изменить (git rebase -i <earliercommit>). В списке коммитов, которые были перебазированы, измените текст с pick на edit рядом с хэшем того, который вы хотите изменить. Затем, когда git предложит вам изменить коммит, используйте это:

git commit --amend --author="Author Name <[email protected]>"

Например, если ваша история коммитов ABCDE-f с F качестве HEAD, и вы хотите сменить автора C и D, то вы бы...

  1. Укажите git rebase -i B (вот пример того, что вы увидите после выполнения команды git rebase -i B)
    • если вам нужно отредактировать A, используйте git rebase -i --root
  2. изменить строки для C и D от pick до edit
  3. Как только начался ребаз, он сначала остановится на C
  4. Вы должны сделать git commit --amend --author="Author Name <[email protected]>"
  5. Затем git rebase --continue
  6. Это снова остановится на D
  7. Затем вы должны снова git commit --amend --author="Author Name <[email protected]>"
  8. git rebase --continue
  9. Перебазирование будет завершено.
  10. Используйте git push -f чтобы обновить ваш источник обновленными коммитами.
  • 65
    Хороший ответ, но для начинающих: сначала найдите коммит, предшествующий тому, который вы хотите изменить, а затем выполните git rebase -i <commit>
  • 5
    @Mathew Byrne Или укажите a1b3c3d4 ^ для ссылки на предыдущий коммит.
Показать ещё 40 комментариев
369

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

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

Следующее проверено и работает, в отличие от связанного ответа. Предположим для ясности изложения, что 03f482d6 - это коммит, автора которого мы пытаемся заменить, а 42627abe - это коммит с новым автором.

  1. Оформите коммит, который мы пытаемся изменить.

    git checkout 03f482d6
    
  2. Заставьте автора изменить.

    git commit --amend --author "New Author Name <New Author Email>"
    

    Теперь у нас есть новый коммит с хешем, равным 42627abe.

  3. Оформить заказ оригинальной ветке.

  4. Замените старый коммит на новый локально.

    git replace 03f482d6 42627abe
    
  5. Переписать все будущие коммиты на основе замены.

    git filter-branch -- --all
    
  6. Удалите замену для чистоты.

    git replace -d 03f482d6
    
  7. Нажмите на новую историю (используйте только --force, если приведенное ниже не удается, и только после проверки работоспособности с помощью git log и/или git diff).

    git push --force-with-lease
    

Вместо 4-6 вы можете просто перейти на новый коммит:

git rebase -i 42627abe
  • 9
    Пожалуйста, поместите туда примечание, чтобы повторно оформить первоначальную ветку после шага 2.
  • 1
    @ Бенджамин, это не было необходимо, когда я это сделал. Уверены ли вы?
Показать ещё 25 комментариев
157

Документация Github содержит a script, который заменяет информацию коммиттера для всех коммитов в ветке.

#!/bin/sh

git filter-branch --env-filter '

OLD_EMAIL="[email protected]"
CORRECT_NAME="Your Correct Name"
CORRECT_EMAIL="[email protected]"

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
  • 7
    Это меняет все коммиты, а не только один. Забавно, я сделал это менее 30 минут назад.
  • 0
    Когда я нашел этот ответ после прочтения предыдущих, я подумал, что стоит попробовать и вуаля, он сделал свою работу. Однако в моем случае это изменило имя коммиттера только при начальной фиксации. Кстати, раньше я пробовал идеи из первого ответа. Возможно, это как-то повлияло на систему.
Показать ещё 5 комментариев
82
  • Сбросьте ваш адрес электронной почты в конфигурации:

    git config --global user.email [email protected]

  • Теперь сбросьте автора вашего коммита без необходимости редактирования:

    git commit --amend --reset-author --no-edit

  • 1
    Нет, это не так. Посмотрите на OP: It's not last commit. Так как бы они amend это?
  • 1
    Это здорово, обидно, но только последний коммит. К счастью, он мне понадобился на последних двух, так что просто сделал git reset HEAD~ , запустил предложенные строки, а затем снова сделал следующий коммит вручную. Сработало нормально!
Показать ещё 1 комментарий
69

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

git commit --amend --author="Author Name <[email protected]>"

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

Запустите перезагрузку с помощью git rebase -i. Он покажет вам что-то вроде этого.

Изображение 7505

Измените ключевое слово pick на edit для коммитов, которые вы хотите изменить имя автора.

Изображение 7506

Затем закройте редактор. Для новичков нажмите Escape, затем введите :wq и нажмите Enter.

Тогда вы увидите свой терминал, как будто ничего не произошло. На самом деле вы находитесь в середине интерактивной перестановки. Теперь пришло время изменить ваше имя автора фиксации, используя команду выше. Он снова откроет редактор. Закройте и продолжите перезагрузку с помощью git rebase --continue. Повторите то же самое для количества фиксации, которое вы хотите отредактировать. Вы можете убедиться, что интерактивная сводка закончилась, когда вы получили сообщение No rebase in progress?.

49

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

В качестве предлога для опроса git filter-branch я написал script, чтобы переписать имя автора и/или авторскую электронную почту для данной фиксации:

#!/bin/sh

#
# Change the author name and/or email of a single commit.
#
# change-author [-f] commit-to-change [branch-to-rewrite [new-name [new-email]]]
#
#     If -f is supplied it is passed to "git filter-branch".
#
#     If <branch-to-rewrite> is not provided or is empty HEAD will be used.
#     Use "--all" or a space separated list (e.g. "master next") to rewrite
#     multiple branches.
#
#     If <new-name> (or <new-email>) is not provided or is empty, the normal
#     user.name (user.email) Git configuration value will be used.
#

force=''
if test "x$1" = "x-f"; then
    force='-f'
    shift
fi

die() {
    printf '%s\n' "$@"
    exit 128
}
targ="$(git rev-parse --verify "$1" 2>/dev/null)" || die "$1 is not a commit"
br="${2:-HEAD}"

TARG_COMMIT="$targ"
TARG_NAME="${3-}"
TARG_EMAIL="${4-}"
export TARG_COMMIT TARG_NAME TARG_EMAIL

filt='

    if test "$GIT_COMMIT" = "$TARG_COMMIT"; then
        if test -n "$TARG_EMAIL"; then
            GIT_AUTHOR_EMAIL="$TARG_EMAIL"
            export GIT_AUTHOR_EMAIL
        else
            unset GIT_AUTHOR_EMAIL
        fi
        if test -n "$TARG_NAME"; then
            GIT_AUTHOR_NAME="$TARG_NAME"
            export GIT_AUTHOR_NAME
        else
            unset GIT_AUTHOR_NAME
        fi
    fi

'

git filter-branch $force --env-filter "$filt" -- $br
  • 0
    +1 спасибо. assemblymb git repo, по-видимому, не меняет все ссылки на авторов в веб-представлении репозитория, но результаты «git pull / clone», похоже, работают нормально.
  • 0
    Отличное решение, так как оно изменяет только то, что предназначено, а не другие поля, такие как дата фиксации.
Показать ещё 6 комментариев
12

При выполнении git rebase -i есть этот интересный бит в документе:

Если вы хотите сбросить две или более коммитов в одну, замените команду "pick" на вторую и последующую фиксацию с помощью "squash" или "fixup". Если у коммитов были разные авторы, сложенный фиксаж будет приписан автору первого коммита. Предлагаемое сообщение фиксации для сложенного фиксации представляет собой конкатенацию сообщений фиксации первого фиксации и команд с командой "squash", но опускает сообщения фиксации коммитов с помощью команды "fixup".

  • Если у вас есть история A-B-C-D-E-F,
  • и вы хотите изменить commits B и D (= 2 коммиты),

то вы можете сделать:

  • git config user.name "Correct new name"
  • git config user.email "[email protected]"
  • создавать пустые коммиты (по одному для каждого фиксации):
    • вам нужно сообщение для целей переадресации
    • git commit --allow-empty -m "empty"
  • запустите операцию перезагрузки
    • git rebase -i B^
    • B^ выбирает родительский элемент B.
  • вам нужно поместить один пустой commit до для каждой фиксации для изменения
  • вам нужно изменить pick на squash для них.

Пример того, что git rebase -i B^ даст вам:

pick sha-commit-B some message
pick sha-commit-C some message
pick sha-commit-D some message
pick sha-commit-E some message
pick sha-commit-F some message
# pick sha-commit-empty1 empty
# pick sha-commit-empty2 empty

измените это на:

# change commit B author
pick sha-commit-empty1 empty
squash sha-commit-B some message
# leave commit C alone
pick sha-commit-C some message
# change commit D author
pick sha-commit-empty2 empty
squash sha-commit-D some message
# leave commit E-F alone
pick sha-commit-E some message
pick sha-commit-F some message

Он предложит вам отредактировать сообщения:

# This is a combination of 2 commits.
# The first commit message is:

empty

# This is the 2nd commit message:

...some useful commit message there...

и вы можете просто удалить первые несколько строк.

11

Есть еще один шаг к Янтарный ответ, если вы используете централизованный репозиторий:

git push -f, чтобы принудительно обновить центральный репозиторий.

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

6

Зафиксировать перед:

Изображение 7507

Чтобы исправить автора для всех коммитов, вы можете применить команду из @Amber answer:

git commit --amend --author="Author Name <[email protected]>"

Или, чтобы повторно использовать свое имя и адрес электронной почты, вы можете просто написать:

git commit --amend --author=Eugen

Фиксация после команды:

Изображение 7508

Например, чтобы изменить все, начиная с 4025621:

Изображение 7509

Ты должен бежать:

git rebase --onto 4025621 --exec "git commit --amend --author=Eugen" 4025621

Примечание. Чтобы включить автора с пробелами, такими как имя и адрес электронной почты, автор должен быть заключен в кавычки. Например:

git rebase --onto 4025621 --exec "git commit --amend --author=\"Foo Bar <[email protected]>\"" 4025621

или добавьте этот псевдоним в ~/.gitconfig:

[alias]
    reauthor = !bash -c 'git rebase --onto $1 --exec \"git commit --amend --author=$2\" $1' --

А затем запустите:

git reauthor 4025621 Eugen
  • 0
    Чтобы убедиться, что команда работает git shortlog -e -s , я просмотрел вывод git shortlog -e -s .
  • 1
    Это ответ, который лучше всего послужил моим целям, спасибо. И поскольку я просто хотел изменить свой адрес электронной почты, я мог запустить с --exec = "git commit --amend --reset-author" после обновления моего .git / config.
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню