Как изменить автора, имя коммиттера и адрес электронной почты нескольких коммитов в Git?

2205

Я писал простой школьный компьютер script и вносил изменения в Git (в репо, которое было в моем pendrive, клонированном с моего компьютера дома). После нескольких коммитов я понял, что делаю вещи как пользователь root.

Есть ли способ изменить автора этих коммитов на мое имя?

  • 12
    Вопрос: сохраняет ли ветвь фильтра git SHA1 для предыдущих тегов, версий и объектов? Или изменение имени автора также изменит связанные SHA1?
  • 0
    Или вы можете попробовать использовать refs/replace/ механизм.
Показать ещё 7 комментариев
Теги:
version-control
git-rewrite-history
git-filter-branch

32 ответа

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

Изменение автора (или коммиттера) потребует повторной записи всей истории. Если вы в порядке с этим и считаете, что это стоит того, вы должны проверить git filter-branch. Страница руководства содержит несколько примеров, чтобы начать работу. Также обратите внимание, что вы можете использовать переменные среды для изменения имени автора, коммиттера, дат и т.д. - см. Раздел "Переменные среды" git man.

В частности, вы можете исправить все неправильные имена авторов и электронные письма для всех ветвей и тегов с помощью этой команды (источник: GitHub help):

#!/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
  • 531
    У Github есть публичный скрипт для этого help.github.com/articles/changing-author-info, и он отлично работает!
  • 28
    После выполнения скрипта вы можете удалить резервную ветку, выполнив «git update-ref -d refs / original / refs /head / master».
Показать ещё 16 комментариев
1538

Использование интерактивной ребазы

Вы могли бы сделать

git rebase -i -p <some HEAD before all of your bad commits>

Затем отметьте все ваши плохие коммиты как "редактирование" в файле rebase. Если вы также хотите изменить свой первый коммит, вам нужно вручную добавить его в первую строку в файле rebase (следуйте формату других строк). Затем, когда git попросит вас внести поправки в каждую фиксацию, сделайте

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

отредактируйте или просто закройте редактор, который открывается, а затем выполните

git rebase --continue

чтобы продолжить rebase.

Вы можете вообще пропустить открытие редактора, добавив --no-edit так что команда будет:

git commit --amend --author "New Author Name <[email protected]>" --no-edit && \
git rebase --continue

Одиночная фиксация

Как уже отмечали некоторые комментаторы, если вы просто хотите изменить последнее коммит, команда rebase не нужна. Просто сделайте

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

Это изменит автора на указанное имя, но коммиттер будет настроен на вашего настроенного пользователя в git config user.name и git config user.email. Если вы хотите установить коммиттер на то, что вы укажете, это установит как автора, так и коммиттера:

 git -c user.name="New Author Name" -c [email protected] commit --amend --reset-author

Примечание по обязательствам слияния

В моем первоначальном ответе был небольшой недостаток. Если между текущим HEAD и вашим <some HEAD before all your bad commits> есть какое-либо слияние, то git rebase будет сглаживать их (и, кстати, если вы используете запросы на выбор GitHub, в вашей история). Это может очень часто приводить к очень различной истории (поскольку дублирующиеся изменения могут быть "переустановлены" ), а в худшем случае это может привести к тому, что git rebase попросит вас разрешить сложные конфликты слияния (которые, вероятно, уже были разрешены в слиянии совершает). Решение состоит в том, чтобы использовать флаг -p для git rebase, который сохранит структуру слияния вашей истории. Маска для git rebase предупреждает, что использование -p и -i может привести к проблемам, но в разделе BUGS говорится: "Редактирование коммиттов и их переписывание сообщений фиксации должно работать нормально".

Я добавил -p в приведенную выше команду. Для случая, когда вы просто меняете последнее сообщение, это не проблема.

  • 2
    Это заняло бы целую вечность, если бы у вас было всего несколько сотен коммитов, чтобы выбраться.
  • 27
    Хотя отлично подходит для нечетного коммита - полезно, если вы соединяетесь и забыли сменить автора
Показать ещё 23 комментария
573

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

git filter-branch --commit-filter '
        if [ "$GIT_COMMITTER_NAME" = "<Old Name>" ];
        then
                GIT_COMMITTER_NAME="<New Name>";
                GIT_AUTHOR_NAME="<New Name>";
                GIT_COMMITTER_EMAIL="<New Email>";
                GIT_AUTHOR_EMAIL="<New Email>";
                git commit-tree "$@";
        else
                git commit-tree "$@";
        fi' HEAD

Обратите внимание: если вы используете эту команду в командной строке Windows, вам нужно использовать " вместо ':

git filter-branch --commit-filter "
        if [ "$GIT_COMMITTER_NAME" = "<Old Name>" ];
        then
                GIT_COMMITTER_NAME="<New Name>";
                GIT_AUTHOR_NAME="<New Name>";
                GIT_COMMITTER_EMAIL="<New Email>";
                GIT_AUTHOR_EMAIL="<New Email>";
                git commit-tree "$@";
        else
                git commit-tree "$@";
        fi" HEAD
  • 4
    Разве использование env-фильтра не является более простым решением? Не уверен, почему это получает больше голосов, тогда.
  • 3
    Тогда ссылка не работает. Как мы перенесем эти изменения в другой репозиторий?
Показать ещё 11 комментариев
526

Один вкладыш, но будьте осторожны, если у вас многопользовательский репозиторий - это изменит все фиксации на наличие того же (нового) автора и коммиттера.

git filter-branch -f --env-filter "GIT_AUTHOR_NAME='Newname'; GIT_AUTHOR_EMAIL='new@email'; GIT_COMMITTER_NAME='Newname'; GIT_COMMITTER_EMAIL='new@email';" HEAD

С строк в строке (что возможно в bash):

git filter-branch -f --env-filter "
    GIT_AUTHOR_NAME='Newname'
    GIT_AUTHOR_EMAIL='new@email'
    GIT_COMMITTER_NAME='Newname'
    GIT_COMMITTER_EMAIL='new@email'
  " HEAD
  • 0
    Минорным моментом является то, что экспорт на самом деле является излишним, хотя и не приносит вреда. например, git-filter-branch --env-filter "GIT_AUTHOR_NAME = 'Новое имя'; GIT_AUTHOR_EMAIL = 'New email' 'HEAD.
  • 16
    Да, но не забывайте имя / адрес электронной почты коммиттера. Для меня сработало git filter-branch -f --env-filter "GIT_AUTHOR_NAME='Newname'; GIT_AUTHOR_EMAIL='newemail'; GIT_COMMITER_NAME='Newname'; GIT_COMMITTER_EMAIL='newemail';" HEAD В противном случае git будет отслеживать старое имя как коммиттер!
Показать ещё 7 комментариев
219

Это происходит, когда вы не инициализировали $HOME/.gitconfig. Вы можете исправить это как:

git config --global user.name "you name"
git config --global user.email [email protected]
git commit --amend --reset-author

с версией git версии 1.7.5.4

  • 9
    Это действительно хорошо работает на последнем коммите. Красиво и просто. Не должно быть глобальное изменение, использование --local тоже работает
  • 47
    git commit --amend --reset-author --no-edit
Показать ещё 1 комментарий
172

Для одного фиксации:

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

(извлечено из ответа от ответчика)

  • 13
    но это только если это самый последний коммит
  • 3
    Согласно git help commit , git commit --amend меняет коммит на «вершине текущей ветви» (то есть HEAD). Обычно это самый последний коммит, но вы можете сделать его любым, если захотите, сначала проверив этот коммит с помощью git checkout <branch-name> или git checkout <commit-SHA> .
Показать ещё 3 комментария
166

В случае, если только самые мелкие коммиты имеют плохих авторов, вы можете сделать это все внутри git rebase -i с помощью команды exec и фиксации --amend следующим образом:

git rebase -i HEAD~6 # as required

который представляет вам редактируемый список коммитов:

pick abcd Someone else commit
pick defg my bad commit 1
pick 1234 my bad commit 2

Затем добавьте строки exec ... --author="..." после всех строк с плохими авторами:

pick abcd Someone else commit
pick defg my bad commit 1
exec git commit --amend --author="New Author Name <[email protected]>" -C HEAD
pick 1234 my bad commit 2
exec git commit --amend --author="New Author Name <[email protected]>" -C HEAD

сохранить и выйти из редактора (для запуска).

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

Благодаря @asmeurer для вдохновения.

  • 22
    Определенно потрясающе. Можете ли вы сократить его, установив user.name и user.email в локальной конфигурации репозитория, и тогда каждая строка будет только exec git commit --amend --reset-author -C HEAD ?
  • 4
    @Andrew --reset-author работает просто отлично.
Показать ещё 5 комментариев
113

Github имеет приятное решение, которое представляет собой следующую оболочку script:

#!/bin/sh

git filter-branch --env-filter '

an="$GIT_AUTHOR_NAME"
am="$GIT_AUTHOR_EMAIL"
cn="$GIT_COMMITTER_NAME"
cm="$GIT_COMMITTER_EMAIL"

if [ "$GIT_COMMITTER_EMAIL" = "[email protected]" ]
then
    cn="Your New Committer Name"
    cm="Your New Committer Email"
fi
if [ "$GIT_AUTHOR_EMAIL" = "[email protected]" ]
then
    an="Your New Author Name"
    am="Your New Author Email"
fi

export GIT_AUTHOR_NAME="$an"
export GIT_AUTHOR_EMAIL="$am"
export GIT_COMMITTER_NAME="$cn"
export GIT_COMMITTER_EMAIL="$cm"
'
  • 5
    Работал отлично. Просто нужно было выполнить git reset --hard HEAD^ пару раз в других локальных репозиториях, чтобы git reset --hard HEAD^ их на более раннюю версию, git pull исправленную версию, и здесь я без строк, содержащих unknown <[email protected]> (полюбил Git по умолчанию).
  • 1
    Я не могу толкать после этого. Должен ли я использовать "-f"?
Показать ещё 3 комментария
76

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

Но если вы действительно хотите это сделать, и вы находитесь в среде bash (без проблем в Linux, в Windows вы можете использовать git bash, который поставляется с установкой git), используйте git ветвь фильтра:

git filter-branch --env-filter '
  if [ $GIT_AUTHOR_EMAIL = bad@email ];
    then GIT_AUTHOR_EMAIL=correct@email;
  fi;
export GIT_AUTHOR_EMAIL'

Чтобы ускорить работу, вы можете указать диапазон изменений, которые вы хотите переписать:

git filter-branch --env-filter '
  if [ $GIT_AUTHOR_EMAIL = bad@email ];
    then GIT_AUTHOR_EMAIL=correct@email;
  fi;
export GIT_AUTHOR_EMAIL' HEAD~20..HEAD
  • 1
    Обратите внимание, что это оставит любые теги, указывающие на старые коммиты. --tag-name-filter cat - это опция " --tag-name-filter cat это работать".
  • 0
    @romkyns есть идеи, как изменить теги?
Показать ещё 1 комментарий
48

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

git commit --amend --reset-author

  • 0
    Для одного коммита, и если вы хотите указать свое имя пользователя, это самый простой способ.
  • 7
    Вы можете добавить --no-edit чтобы сделать это еще проще, так как обычно большинство людей хотят обновить только адрес электронной почты, а не сообщение о коммите.
Показать ещё 2 комментария
39

Это более продуманная версия версии @Brian:

Чтобы изменить автора и коммиттера, вы можете сделать это (с помощью строк в строке, которая возможна в bash):

git filter-branch --env-filter '
    if [ "$GIT_COMMITTER_NAME" = "<Old name>" ];
    then
        GIT_COMMITTER_NAME="<New name>";
        GIT_COMMITTER_EMAIL="<New email>";
        GIT_AUTHOR_NAME="<New name>";
        GIT_AUTHOR_EMAIL="<New email>";
    fi' -- --all

Вы можете получить одну из следующих ошибок:

  • Временная директория уже существует
  • Refs начиная с refs/original существует уже
    (это означает, что еще одна ветвь фильтра была запущена ранее в репозитории, а исходная ссылка на исходную запись резервируется в refs/original)

Если вы хотите принудительно выполнить прогон, несмотря на эти ошибки, добавьте флаг --force:

git filter-branch --force --env-filter '
    if [ "$GIT_COMMITTER_NAME" = "<Old name>" ];
    then
        GIT_COMMITTER_NAME="<New name>";
        GIT_COMMITTER_EMAIL="<New email>";
        GIT_AUTHOR_NAME="<New name>";
        GIT_AUTHOR_EMAIL="<New email>";
    fi' -- --all

Может понадобиться небольшое объяснение опции -- --all: она делает работу с фильтром на всех ревизиях на всех ссылках (включая все ветки). Это означает, например, что теги также переписываются и видны на перезаписанных ветвях.

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

  • 0
    Престижность за предоставление процедуры, которая изменяет фиксации на всех ссылках / ветках.
37

Вы можете использовать это как псевдоним, так что вы можете сделать:

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

или за последние 10 коммитов:

git change-commits GIT_AUTHOR_EMAIL "[email protected]" "[email protected]" HEAD~10..HEAD

Добавьте в ~/.gitconfig:

[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

Надеюсь, это полезно.

  • 0
    "git: 'change-commits' не является командой git. Смотрите 'git --help'."
  • 1
    вам нужно определить псевдоним ..
Показать ещё 2 комментария
22
  • run git rebase -i <sha1 or ref of starting point>
  • отметьте все коммиты, которые вы хотите изменить, с помощью edit (или e)
  • выполните следующие две команды, пока вы не обработаете все коммиты:

    git commit --amend --reuse-message=HEAD --author="New Author <[email protected]>" ; git rebase --continue

Это сохранит всю другую информацию о фиксации (включая даты). Параметр --reuse-message=HEAD запрещает запуск редактора сообщений.

21

Я использую следующее, чтобы переписать автора для всего репозитория, включая теги и все ветки:

git filter-branch --tag-name-filter cat --env-filter "
  export GIT_AUTHOR_NAME='New name';
  export GIT_AUTHOR_EMAIL='New email'
" -- --all

Затем, как описано в странице MAN ветки фильтра, удалите все оригинальные refs, сделанные под резервными копиями filter-branch (это разрушительно, сначала резервное копирование):

git for-each-ref --format="%(refname)" refs/original/ | \
xargs -n 1 git update-ref -d
  • 2
    Очень важно использовать --tag-name-filter cat . В противном случае ваши теги останутся в исходной цепочке коммитов. Другие ответы не упоминают об этом.
21

Я адаптировал этот решение, которое работает, проглатывая простой author-conv-file (формат такой же, как для git-cvsimport). Он работает, изменяя всех пользователей, как определено в author-conv-file для всех ветвей.

Мы использовали это совместно с cvs2git, чтобы перенести наш репозиторий с cvs на git.

то есть. Пример author-conv-file

john=John Doe <[email protected]>
jill=Jill Doe <[email protected]>

script:

 #!/bin/bash

 export $authors_file=author-conv-file

 git filter-branch -f --env-filter '

 get_name () {
     grep "^$1=" "$authors_file" |
     sed "s/^.*=\(.*\) <.*>$/\1/"
 }

 get_email () {
     grep "^$1=" "$authors_file" |
     sed "s/^.*=.* <\(.*\)>$/\1/"
 }

 GIT_AUTHOR_NAME=$(get_name $GIT_COMMITTER_NAME) &&
     GIT_AUTHOR_EMAIL=$(get_email $GIT_COMMITTER_NAME) &&
     GIT_COMMITTER_NAME=$GIT_AUTHOR_NAME &&
     GIT_COMMITTER_EMAIL=$GIT_AUTHOR_EMAIL &&
     export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL &&
     export GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL
 ' -- --all
  • 2
    теперь размещен как gist gist.github.com/863084
  • 0
    И расширенная версия сущности @ leif81: gist.github.com/1451142
Показать ещё 1 комментарий
18

Я нашел представленные версии способ агрессивными, особенно если вы совершаете исправления от других разработчиков, это по сути украдет их код.

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

Претензии к leif81 для всех вариантов.

#!/bin/bash

git filter-branch --env-filter '
if [ "$GIT_AUTHOR_NAME" = "<old author>" ];
then
    GIT_AUTHOR_NAME="<new author>";
    GIT_AUTHOR_EMAIL="<[email protected]>";
fi
if [ "$GIT_COMMITTER_NAME" = "<old committer>" ];
then
    GIT_COMMITTER_NAME="<new commiter>";
    GIT_COMMITTER_EMAIL="<[email protected]>";
fi
' -- --all
17
  • Измените фиксацию author name & email на Amend, затем замените old-commit with new-one:

    $ git checkout <commit-hash>                            # checkout to the commit need to modify  
    $ git commit --amend --author "name <[email protected]>" # change the author name and email
    
    $ git replace <old-commit-hash> <new-commit-hash>      # replace the old commit by new one
    $ git filter-branch -- --all                           # rewrite all futures commits based on the replacement                   
    
    $ git replace -d <old-commit-hash>     # remove the replacement for cleanliness 
    $ git push -f origin HEAD              # force push 
    
  • Другой способ Rebasing:

    $ git rebase -i <good-commit-hash>      # back to last good commit
    
    # Editor would open, replace 'pick' with 'edit' before the commit want to change author
    
    $ git commit --amend --author="author name <[email protected]>"  # change the author name & email
    
    # Save changes and exit the editor
    
    $ git rebase --continue                # finish the rebase
    
  • 2
    Очень хороший ответ. Мне нравится, что изменения обернуты с самого обновления, чтобы даже очистить коммиты git
15

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

Name you want <email you want> Name you don't want <email you don't want>

И с этого момента команды типа git shortlog будут считать эти два имени одинаковыми (если вы специально не скажете им). Подробнее см. http://schacon.github.com/git/git-shortlog.html.

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

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

9

Если вы являетесь единственным пользователем этого репозитория, вы можете переписать историю, используя git filter-branch ( как svick написал), или git fast-export/git fast-import плюс фильтр script (как описано в статье, на которую ссылается docgnome answer), или интерактивный rebase. Но любой из них изменил бы изменения с первого измененного обязательства; это означает трудность для любого, кто основывал свои изменения на своей ветке, предварительно переписывая.

ВОССТАНОВЛЕНИЕ

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

В качестве альтернативы они могут попробовать git rebase --pull, которые бы быстро перешлите, если в их репозитории не было никаких изменений, или пересоедините их ветку поверх переписанных коммитов (мы хотим избежать слияния, поскольку она будет сохранять pre -ревит приходит навсегда). Все это предполагает, что у них нет работы; используйте git stash, чтобы отменить изменения в противном случае.

Если другие разработчики используют ветки функций, и/или git pull --rebase не работает, например. потому что восходящий поток не настроен, они должны rebase их работа поверх записей после перезаписи. Например, после получения новых изменений (git fetch), для ветки master на основе /forked из origin/master необходимо запустить

$ git rebase --onto origin/master origin/master@{1} master

Здесь origin/master@{1} - состояние предварительной перезаписи (до извлечения), см. gitrevisions.


Альтернативным решением будет использование механизма refs/replace/, доступного в Git начиная с версии 1.6.5. В этом решении вы предоставляете замены для коммитов с неправильным адресом электронной почты; то кто-нибудь, кто забирает "ref" (что-то вроде fetch = +refs/replace/*:refs/replace/* refspec в соответствующем месте в их .git/config), будет получать замены прозрачно, а те, кто не извлекает эти ссылки, будут видеть старые коммиты.

Процедура выглядит примерно так:

  • Найти все коммиты с неправильным адресом электронной почты, например, используя

    $ git log [email protected] --all
    
  • Для каждого неправильного коммита создайте замену фиксации и добавьте его в базу данных объектов

    $ git cat-file -p <ID of wrong commit> | 
      sed -e 's/user@wrong\.email/[email protected]/g' > tmp.txt
    $ git hash-object -t commit -w tmp.txt
    <ID of corrected commit>
    
  • Теперь, когда вы скорректировали фиксацию в базе данных объектов, вы должны сообщить Git автоматически и прозрачно заменить неверный коммит, исправленный с помощью git replace:

    $ git replace <ID of wrong commit> <ID of corrected commit>
    
  • Наконец, перечислите всю замену, чтобы проверить, выполнена ли эта процедура

    $ git replace -l
    

    и проверьте, есть ли замены

    $ git log [email protected] --all
    

Вы можете, конечно, автоматизировать эту процедуру... ну, все, кроме использования git replace, который не имеет (пока) пакетного режима, поэтому вам придется использовать для этого цикл оболочки или заменить "вручную".

НЕ ИСПРАВЛЕНО! YMMV.

Обратите внимание, что при использовании механизма refs/replace/ вы можете столкнуться с некоторыми грубыми углами: он является новым и еще не очень хорошо протестированным.

6

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

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

git config user.name <good name>
git config user.email <good email>
git reset HEAD^
git stash
git reset HEAD^
git commit -a
git stash pop
git commit -a
5

Ваша проблема очень распространена. См. " Использование Mailmap для исправления списка авторов в Git"

Для простоты я создал script, чтобы облегчить процесс: git-changemail

После размещения этого script на вашем пути вы можете выпустить команды вроде:

  • Изменение совпадений авторов в текущей ветке

    $ git changemail -a [email protected] -n newname -m [email protected]
    
  • Измените сопоставления автора и коммиттера на <branch> и < branch2 > . Передайте -f в ветвь фильтра, чтобы разрешить переписывание резервных копий

    $ git changemail -b [email protected] -n newname -m [email protected] -- -f &lt;branch> &lt;branch2>
    
  • Показывать существующих пользователей в режиме репо

    $ git changemail --show-both
    

Кстати, после внесения изменений очистите резервную копию из ветки фильтра с помощью git-backup-clean

  • 1
    когда я запускаю вашу команду, она говорит: «Неустранимый: невозможно выполнить git-changemail: разрешение запрещено»
5

Сегодня мы столкнулись с проблемой, когда символ UTF8 в имени автора вызывал проблемы на сервере сборки, поэтому нам пришлось переписать историю, чтобы исправить это. Были предприняты следующие шаги:

Шаг 1: измените свое имя пользователя в git для всех будущих коммитов в соответствии с инструкциями здесь: https://help.github.com/articles/setting-your-username-in-git/

Шаг 2. Запустите следующие bash script:

#!/bin/sh

REPO_URL=ssh://path/to/your.git
REPO_DIR=rewrite.tmp

# Clone the repository
git clone ${REPO_URL} ${REPO_DIR}

# Change to the cloned repository
cd ${REPO_DIR}

# Checkout all the remote branches as local tracking branches
git branch --list -r origin/* | cut -c10- | xargs -n1 git checkout

# Rewrite the history, use a system that will preseve the eol (or lack of in commit messages) - preferably Linux not OSX
git filter-branch --env-filter '
OLD_EMAIL="[email protected]"
CORRECT_NAME="New Me"

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

# Force push the rewritten branches + tags to the remote
git push -f

# Remove all knowledge that we did something
rm -rf ${REPO_DIR}

# Tell your colleagues to `git pull --rebase` on all their local remote tracking branches

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

У нас возникли проблемы с запуском этого в OS X, поскольку он каким-то образом перепутал концы строк в сообщениях фиксации, поэтому нам пришлось повторно запустить его на машине Linux после этого.

5

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

Информация об коммитерах не отображается в большинстве мест, но вы можете увидеть ее с помощью git log -1 --format=%cn,%ce (или использовать show вместо log, чтобы указать конкретную фиксацию).

При изменении автора вашего последнего коммита так же просто, как git commit --amend --author "Author Name <[email protected]>", нет однострочного или аргумента, чтобы сделать то же самое с информацией об участниках.

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

git config user.email [email protected] 
git commit --amend
  • 0
    Обратите внимание, что старое значение все еще находится в нескольких местах в path\to\repo\.git . Я еще не уверен, что вам нужно сделать, чтобы полностью исключить это. К сожалению, исправления (?) Не стираются.
5

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

pick a07cb86 Project tile template with full details and styling
x git commit --amend --reset-author -Chead
  • 3
    Проблема в том, что другие метаданные фиксации (например, дата и время) также изменяются. Я только что выяснил это трудным путем ;-) .
5

Если вы используете Eclipse с EGit, то есть довольно простое решение.
Предположение: вы совершили ошибку в локальном ветки local_master_user_x, который не может быть перенесен на "ведущий" удаленной ветки из-за недопустимого пользователя.

  • Оформить проверку удаленной ветки "master"
  • Выберите проекты/папки/файлы, для которых "local_master_user_x" содержит изменения.
  • Щелкните правой кнопкой мыши - Заменить на - Ветвь - 'local_master_user_x'
  • Завершите эти изменения снова, на этот раз как правильный пользователь и в локальную ветвь "master"
  • Push to remote 'master'
4

Самый быстрый и простой способ сделать это - использовать аргумент --exec git rebase:

git rebase -i -p --exec 'git commit --amend --reset-author --no-edit'

Это создаст список дел, который выглядит так:

pick ef11092 Blah blah blah
exec git commit --amend --reset-author --no-edit
pick 52d6391 Blah bloh bloo
exec git commit --amend --reset-author --no-edit
pick 30ebbfe Blah bluh bleh
exec git commit --amend --reset-author --no-edit
...

и это будет работать автоматически, что работает, когда у вас есть сотни коммитов.

2

Если вы являетесь единственным пользователем этого репо, или вы не заботитесь о возможном нарушении репо для других пользователей, тогда да. Если вы подтолкнули эти коммиты, и они существуют там, где где-то еще можно получить к ним доступ, тогда нет, если только вы не заботитесь о том, чтобы нарушать репозиции других людей. Проблема заключается в изменении этих коммитов, вы будете генерировать новые SHA, которые заставят их рассматривать как разные коммиты. Когда кто-то пытается втянуть эти измененные коммиты, история отличается и kaboom.

Эта страница http://inputvalidation.blogspot.com/2008/08/how-to-change-git-commit-author.html описывает, как это сделать. (Я не пробовал это так YMMV)

  • 0
    Таким образом, не существует безопасного способа переписать user.email. Не взрывая всех остальных. Я знал, что переписывать историю было плохой идеей, я просто думал, что может быть чистый способ сделать это безопасно. Благодарю.
  • 0
    @mediaslave: попробуйте refs/replace/ механизм.
Показать ещё 1 комментарий
1

Я хочу добавить свой пример. Я хочу создать bash_function с заданным параметром.

это работает в mint-linux-17.3

# $1 => email to change, $2 => new_name, $3 => new E-Mail

function git_change_user_config_for_commit {

 # defaults
 WRONG_EMAIL=${1:-"[email protected]"}
 NEW_NAME=${2:-"your name"}
 NEW_EMAIL=${3:-"[email protected]"}

 git filter-branch -f --env-filter "
  if [ \$GIT_COMMITTER_EMAIL = '$WRONG_EMAIL' ]; then
    export GIT_COMMITTER_NAME='$NEW_NAME'
    export GIT_COMMITTER_EMAIL='$NEW_EMAIL'
  fi
  if [ \$GIT_AUTHOR_EMAIL = '$WRONG_EMAIL' ]; then
    export GIT_AUTHOR_NAME='$NEW_NAME'
    export GIT_AUTHOR_EMAIL='$NEW_EMAIL'
  fi
 " --tag-name-filter cat -- --branches --tags;
}
0

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

git rebase -i HEAD~4 -x "git commit --amend --author 'Author Name <[email protected]>' --no-edit"

ЗАМЕТКИ

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

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

pick 897fe9e simplify code a little
exec git commit --amend --author 'Author Name <[email protected]>' --no-edit
pick abb60f9 add new feature
exec git commit --amend --author 'Author Name <[email protected]>' --no-edit
pick dc18f70 bugfix
exec git commit --amend --author 'Author Name <[email protected]>' --no-edit

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

0

Попробуйте это. Он будет делать то же, что и выше, но интерактивно.

bash <(curl -s  https://raw.githubusercontent.com/majdarbash/git-author-change-script/master/run.sh)

Ссылка: https://github.com/majdarbash/git-author-change-script

0
git rebase -i YOUR_FIRTS_COMMIT_SHA^

while true; do git commit --amend --author="Name Surname <[email protected]>" --no-edit && git rebase --continue; done

Нажмите ^ С# после завершения переадресации (цикл будет продолжать обновлять последнюю фиксацию)

-2

Это не ответ на ваш вопрос, а скорее script, который вы можете использовать, чтобы избежать этого в будущем. Он использует глобальные перехватчики, доступные с Git версия 2.9, чтобы проверить вашу конфигурацию электронной почты на основе вашего каталога:

#!/bin/sh
PWD=`pwd`
if [[ $PWD == *"Ippon"* ]] # 1)
then
  EMAIL=$(git config user.email)
  if [[ $EMAIL == *"Work"* ]] # 2)
  then
    echo "";
  else
    echo "Email not configured to your Work email in the Work directory.";
    git config user.email "[email protected]"
    echo "Git email configuration has now been changed to \"$(git config user$
    echo "\nPlease run your command again..."
    echo ''
    exit 1
  fi;
elif [[ $PWD == *"Personal"* ]]
then
  EMAIL=$(git config user.email)
  if [[ $EMAIL == "[email protected]" ]]
  then
    echo "";
  else
    echo "Email is not configured to your personal account in the Personal di$
    git config user.email "[email protected]"
    echo "Git email configuration has now been changed to \"$(git config user$
    echo "\nPlease run your command again..."
    echo ''
    exit 1;
  fi;
fi; 

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

  • 1
    Если ваш ответ начинается с «Это не ответ на ваш вопрос» ...

Ещё вопросы

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