Як змінити ім'я автора та виконавця та електронну пошту декількох комісій у Git?


2391

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

Чи є спосіб змінити автора цих зобов’язань на моє ім’я?


13
Питання: чи використовує гіт-фільтр-філія зберігає SHA1 для попередніх тегів, версій та об’єктів? Або зміна сили імені автора також змінить пов'язані SHA1?
AndyL

36
Хеші зміниться так
Недоступно

3
Дотично я створив невеликий сценарій, який остаточно виправив для мене першопричину. gist.github.com/tripleee/16767aa4137706fd896c
tripleee

2
@impinball Вік питання навряд чи актуальний. Створення нового дубліката питання не викликає сумнівів. Я гадаю, що я міг би створити питання, яке благає цієї конкретної відповіді, але я зовсім не впевнений, що він отримає все так багато наочності. Це не так, як тут не вистачає питань щодо Git ... Рада, що я можу допомогти.
tripleee

8
GitHub мають спеціальний сценарій для цього: help.github.com/articles/changing-author-info
Тимур

Відповіді:


1210

Ця відповідь використовує git-filter-branch, для чого документи тепер попереджають це:

git filter-branch має безліч підводних каменів, які можуть створити не очевидні мангляни, призначені для перезапису історії (і можуть залишити вам мало часу для дослідження таких проблем, оскільки він має такі неприємні показники). Ці проблеми щодо безпеки та експлуатаційних якостей не можуть бути виправлені назад, тому їх використання не рекомендується. Будь ласка, використовуйте альтернативний інструмент фільтрації історії, такий як git filter-repo . Якщо вам все-таки потрібно використовувати гіт-фільтр-гілку, уважно прочитайте БЕЗПЕЧЕННЯ (та ВДІЙНІСТЬ ), щоб дізнатися про наземні міни фільтр-гілки, а потім пильно уникайте якомога більшого числа перерахованих там небезпек.

Зміна автора (або виконавця) вимагала б переписати всю історію. Якщо ви з цим все гаразд і думаєте, що воно того варте, то слід перевірити git filter-branch . Сторінка man містить кілька прикладів для початку роботи Також зауважте, що ви можете використовувати змінні середовища, щоб змінити прізвище автора, виконавця, дати тощо - див. Розділ "Змінні середовища" на сторінці git man .

Зокрема, за допомогою цієї команди ви можете виправити всі неправильні імена автора та електронні листи для всіх гілок та тегів (джерело: довідка GitHub ):

#!/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

610
Github має відкритий скрипт для цієї довідки.github.com/articles/changing-author-info, і це чудово працює!
defvol

34
Після виконання сценарію ви можете видалити гілку резервного копіювання, виконавши "git update-ref -d refs / original / refs / heads / master".
DR

7
@rodowi, він копіює всі мої зобов'язання.
Рафаель Баррос

6
@RafaelBarros інформація про автора (як і будь-що інше в історії) є частиною ключа ключа sha. Будь-які зміни в історії - це перезапис, що призводить до нових ідентифікаторів для всіх комітетів. Тому не переписуйте репортаж на спільний доступ або переконайтесь, що всі користувачі знають про це ...
johannes

20
Вирішено за допомогоюgit push --force --tags origin HEAD:master
mcont

1577

ПРИМІТКА. Ця відповідь змінює SHA1, тому подбайте про використання її на гілці, яка вже була натиснута. Якщо ви хочете лише виправити написання імені або оновити стару електронну пошту, git дозволяє це робити без використання переписування історії .mailmap. Дивіться іншу мою відповідь .

Використання інтерактивної бази даних

Ви могли б зробити

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

Потім позначте всі ваші погані зобов'язання як "редагувати" у файлі ребазу. Якщо ви також хочете змінити свою першу комісію, вам доведеться її вручну додати як перший рядок у файлі ребазування (дотримуйтесь формат інших рядків). Потім, коли git попросить вас внести зміни до кожної комісії, зробіть це

 git commit --amend --author "New Author Name <email@address.com>" 

відредагуйте або просто закрийте редактор, який відкриється, а потім зробіть

git rebase --continue

щоб продовжити ребазу.

Ви можете повністю пропустити редактор тут, додавши --no-edit так, що команда буде:

git commit --amend --author "New Author Name <email@address.com>" --no-edit && \
git rebase --continue

Єдиний комітет

Як зауважили деякі коментатори, якщо ви просто хочете змінити останню комісію, команда rebase не потрібна. Просто роби

 git commit --amend --author "New Author Name <email@address.com>"

Це змінить автора на вказане ім'я, але компітер буде встановлено вашим налаштованим користувачем у git config user.nameта git config user.email. Якщо ви хочете встановити програму на щось, що ви вказали, це встановить як автора, так і виконавця:

 git -c user.name="New Author Name" -c user.email=email@address.com 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до вищевказаної команди. У випадку, коли ви просто змінюєте останню комісію, це не проблема.



32
+1 за згадку про те, що використовується для типового виправлення з помилкою: git commit --amend --author = ім'я користувача
Nathan Kidd

12
Це ідеально. Найпоширенішим моїм випадком є ​​те, що я сідаю за інший комп'ютер і забуваю налаштувати автора, і, як правило, потрібно <5 комірок або так виправити.
Zitrax

57
git commit --amend --reset-authorтакож працює один раз user.nameі user.emailналаштовано правильно.
пт

14
Перезапишіть інформацію про автора про всі комісії після <commit>використання user.nameта user.emailвід ~/.gitconfig: запустити git rebase -i <commit> --exec 'git commit --amend --reset-author --no-edit', зберегти, вийти. Не потрібно редагувати!
ntc2

588

Ви також можете зробити:

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-фільтр простіше рішення? Тоді не впевнений, чому це набирає більше голосів.
stigkj

3
Потім посилання розривається. Як ми переносимо ці зміни до іншого сховища?
Рассел

28
env-filter змінить усі коміти. Це рішення дозволяє умовно.
користувач208769

5
"A previous backup already exists in refs/original/ Force overwriting the backup with -f"Вибачте, але там, де- -fдва флаги будуть виконувати цей сценарій два рази. Насправді це відповідь Брайана, вибачте за порушення, одразу після того, як фільтр-гілка буде рішенням.
hhh

2
@ user208769 env-filter також дозволяє умовно; подивіться на мою відповідь :-)
stigkj

558

Один лайнер, але будьте обережні, якщо у вас є багатокористувацьке сховище - це змінить усі зобов’язання мати одного і того ж (нового) автора та виконавця.

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

Незначна точка експорту насправді зайва, хоча це не шкодить. наприклад, git-filter-branch --env-filter "GIT_AUTHOR_NAME = 'Нове ім'я"; GIT_AUTHOR_EMAIL = "Нова електронна пошта" "HEAD.
Алек Гек

4
Чому він переписує всі коміти, якщо ви вказуєте HEADв кінці команди?
Нік Волинкін

1
Це не працює для мого сховища Bitbucket, будь-яка ідея? Я виконую git push --force --tags origin 'refs/heads/*'після
заповіту

1
Для цього натисніть команду:$git push --force --tags origin 'refs/heads/master'
HARSH NILESH PATHAK

1
Акуратний; це також зберігає старі часові позначки.
DharmaTurtle

221

Це трапляється, коли у вас немає ініціалізації $ HOME / .gitconfig. Ви можете виправити це як:

git config --global user.name "you name"
git config --global user.email you@domain.com
git commit --amend --reset-author

тестовано на git версії 1.7.5.4


9
Це дуже добре працює на останньому зобов'язанні. Приємно і просто. Не повинно бути глобальної зміни, використовуючи і --localтвори
Бен

Цей був для мене найбільшим переможцем! git commit --amend --reset-author --no-editКоманда особливо корисна , якщо ви створили фіксації з інформацією про невірне автора, а потім встановити правильний автор після-фактум через git config. Зберегли мій $$ саме зараз, коли мені довелося оновити електронну пошту.
ecbrodie

187

Для однієї комісії:

git commit --amend --author="Author Name <email@address.com>"

(витягнуто з відповіді асмерера)


14
але це лише в тому випадку, якщо це остання фіксація
Річард

4
Відповідно git help commit, git commit --amendзміни комітету на "вістря поточної гілки" (це HEAD). Зазвичай це найновіша фіксація, але ви можете зробити її будь-яку вподобану команду, попередньо ознайомившись із цим git checkout <branch-name>або git checkout <commit-SHA>.
Rory O'Kane

12
Але якщо ви це зробите, усі зобов’язання, які вже мають це вчинення як батьків, вказуватимуть на неправильне виконання. Краще використовувати фільтр-гілку в цей момент.
Джон Гітцен

3
@JohnGietzen: Ви можете перезавантажити комісії назад на той, що змінився, щоб виправити це. Однак, якщо ви робите> 1 фіксацію, то, як було сказано, фільтр-гілка буде, мабуть, набагато простішим.
Танатос

5
Зауважте, що ці зміни виконуються лише у зобов'язаннях, authorа не над тимcommitter
Нік Волинкін

179

У випадку, коли лише кілька перших комітетів мають поганих авторів, ви можете зробити все це всередині, git rebase -iвикористовуючи execкоманду та команду --amend:

git rebase -i HEAD~6 # as required

який пропонує вам редагувати список комітетів:

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

Потім додайте exec ... --author="..."рядки після всіх рядків з поганими авторами:

pick abcd Someone else's commit
pick defg my bad commit 1
exec git commit --amend --author="New Author Name <email@address.com>" -C HEAD
pick 1234 my bad commit 2
exec git commit --amend --author="New Author Name <email@address.com>" -C HEAD

збереження та вихід редактора (для запуску).

Це рішення може бути довшим, ніж деякі інші, але воно є дуже керованим - я точно знаю, що робить це.

Дякуємо @asmeurer за натхнення.


26
Виразно приголомшливий. Чи можете ви скоротити його, встановивши user.name та user.email у локальній конфігурації репо, і тоді кожен рядок є лише exec git commit --amend --reset-author -C HEAD?
Андрій

1
Канонічна відповідь: використовувати фільтр-гілка, щойно видалені для мене refs / heads / master. Тож +1 вашому контрольованому рішення, яке можна редагувати. Дякую!
jmtd

Чому ви починаєте Someone else's commitзамість цього my bad commit 1? Я просто спробував HEAD^^внести зміни в останні 2 коміти, і це спрацювало чудово.
fredoverflow

3
На зміну git rebase -i HEAD^^^^^^вам також можна написатиgit rebase -i HEAD~6
Патрік Шлютер

1
Зауважте, що це змінює часову позначку комітетів. Дивіться stackoverflow.com/a/11179245/1353267 щодо повернення до правильних часових позначок
Samveen

111

У Github є гарне рішення , яке полягає в наступному скрипті оболонки:

#!/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" = "your@email.to.match" ]
then
    cn="Your New Committer Name"
    cm="Your New Committer Email"
fi
if [ "$GIT_AUTHOR_EMAIL" = "your@email.to.match" ]
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 pull- змінив версію, і ось я без будь-яких рядків, що містять unknown <stupid-windows-user@.StupidWindowsDomain.local>(я полюбив дефолт у Git).
Алан Плюм

1
Я не можу просуватися після цього. Чи потрібно використовувати "-f"?
Монітор риб

9
Я так і зробив git push -f. Також місцеві репости повинні бути повернені після цього.
Монітор риб

Якщо вам потрібно запустити скрипт оболонки на певній гілці, ви можете змінити останній рядок на: "'master..your-branch-name" (припускаючи, що ви розгалужені master).
Роберт Каїч

Клацніть на посилання <приємне рішення>, оскільки сценарій оновлювався
gxpr

82

Як згадувалося в доcgnome, історія переписування є небезпечною і порушує сховища інших людей.

Але якщо ви дійсно хочете це зробити, і ви перебуваєте в середовищі bash (без проблем в Linux, в Windows, ви можете використовувати git bash, який передбачено встановленням git), використовуйте git filter-branch :

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

2
Зауважте, що це дозволить залишити будь-які теги, що вказують на старі коміти. --tag-name-filter cat- це варіант «змусити його працювати».
Роман Старков

@romkyns будь-яка ідея про те, як змінити теги?
Нік Волинкін

@NickVolynkin Так, ви вказуєте --tag-name-filter cat. Це дійсно повинно було бути поведінкою за замовчуванням.
Роман Старков

48

Коли ви переймаєте незареєстроване зобов’язання у іншого автора, існує простий спосіб впоратися з цим.

git commit --amend --reset-author


1
Для однієї комісії, і якщо ви хочете поставити своє ім'я користувача, це найпростіший спосіб.
Педро Беневідес

7
Ви можете додати --no-editце ще простіше, оскільки, як правило, більшість людей захочуть оновити лише електронну адресу, а не повідомлення про фіксацію
PlagueHammer

Чи можете ви, будь ласка, поділитися командою git лише для того, щоб оновити електронну пошту / ім’я користувача останнього комітету новим
adi

Ви пробували це? Це має бути побічним ефектом цього, якщо не stackoverflow.com/a/2717477/654245 виглядає як хороший шлях.
Райанмт

46

Ви можете використовувати цей псевдонім, щоб ви могли:

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

Додати до ~ / .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

Сподіваюся, це корисно.


"git:" change-commits "не є командою git. Див." git --help "."
Native_Mobile_Arch_Dev

Після цієї команди та синхронізації з master всі дублі в історії копіюються! Навіть інших користувачів :(
Володимир

@ Володимир, що очікується, будь ласка, вивчіть історію зміни в git
brauliobo

39

Це більш досконала версія @ Брайана:

Щоб змінити автора і виконавця, ви можете зробити це (з рядками в рядку, що можливо в 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

Ви можете отримати одну з цих помилок:

  1. Тимчасовий каталог вже існує
  2. Посилання, що починаються з 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замість цього, що означає фільтрувати всі зміни лише на поточній гілці . І тоді жодних тегів (або інших посилань) не буде існувати у переписаній гілці.


Kudos для надання процедури, яка змінюється, бере на себе всі реф / гілки.
Джонні Юта

25

Однією команди , щоб змінити автор за останні 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
exec git commit --amend --author 'Author Name <author.name@mail.com>' --no-edit
pick abb60f9 add new feature
exec git commit --amend --author 'Author Name <author.name@mail.com>' --no-edit
pick dc18f70 bugfix
exec git commit --amend --author 'Author Name <author.name@mail.com>' --no-edit

Потім ви все ще можете змінити деякі рядки, щоб побачити, де ви хочете змінити автора. Це дає вам гарне середнє місце між автоматизацією та керуванням: ви бачите кроки, які будуть виконуватися, і як тільки ви збережете все, буде застосовано відразу.


Дивовижно! Дякую!
Пабло Лаллоні

Я використав HEAD ~ 8, і це показує набагато більше, ніж за останні 8 комітів.
Брайан Брайс

1
@BryanBryce, якщо брати участь у злитті, справи ускладнюються :)
Chris Maes

@ChrisMaes Ага, я бачу, що відбувається. Я не хочу возитися з тими, просто на гілці, на якій я.
Брайан Брайс

У такому випадку, якби ви розлучилися з майстром, ви могли:git rebase -i master -x ...
Кріс Мейс

23
  1. бігати git rebase -i <sha1 or ref of starting point>
  2. позначте всі комісії, які ви хочете змінити edit(або e)
  3. циклічні наступні дві команди, поки ви не обробите всі коміти:

    git commit --amend --reuse-message=HEAD --author="New Author <new@author.email>" ; git rebase --continue

Це дозволить зберегти всю іншу інформацію про здійснення комісій (включаючи дати). Ця --reuse-message=HEADопція не дозволяє запускати редактор повідомлень.


23

Я використовую наступне, щоб переписати автора для цілого сховища, включаючи теги та всі гілки:

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

Потім, як описано на сторінці MAN із відділення фільтр , видаліть усі оригінальні дані, створені з резервної копії filter-branch(це деструктивне, спочатку резервне копіювання):

git for-each-ref --format="%(refname)" refs/original/ | \
xargs -n 1 git update-ref -d

2
Це дуже важливо використовувати --tag-name-filter cat. Інакше ваші теги залишаться у вихідному ланцюжку комітетів. Інші відповіді про це не згадують.
jeberle

21

Я адаптував це рішення, яке працює, вводячи простий author-conv-file(формат такий же, як і для git-cvsimport ). Він працює, змінюючи всіх користувачів, як визначено вauthor-conv-file усіх галузях.

Ми використовували це спільно з тим, cvs2gitщоб перенести наш сховище із cvs в git.

тобто Зразок author-conv-file

john=John Doe <john.doe@hotmail.com>
jill=Jill Doe <jill.doe@hotmail.com>

Сценарій:

 #!/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

Дякую, мені цікаво, чому це не основна функція git (або git-svn). Це можна зробити за допомогою прапора для клона git svn, але не в git filter-branch ...
Даніель Гершкович

20

Я мушу зазначити, що якщо єдиною проблемою є те, що автор / електронний лист відрізняється від вашого звичайного, це не проблема. Правильне виправлення полягає у створенні файла, який називається .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 для отримання додаткової інформації.

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

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


18

Я знайшов представлені версії способами агресивних, особливо якщо ви робите патчі від інших розробників, це по суті вкраде їх код.

Версія нижче працює у всіх відділеннях та змінює автора та коментаря окремо, щоб запобігти цьому.

Куди до leif81 для всіх варіантів.

#!/bin/bash

git filter-branch --env-filter '
if [ "$GIT_AUTHOR_NAME" = "<old author>" ];
then
    GIT_AUTHOR_NAME="<new author>";
    GIT_AUTHOR_EMAIL="<youmail@somehost.ext>";
fi
if [ "$GIT_COMMITTER_NAME" = "<old committer>" ];
then
    GIT_COMMITTER_NAME="<new commiter>";
    GIT_COMMITTER_EMAIL="<youmail@somehost.ext>";
fi
' -- --all

18
  1. Змініть фіксацію 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 <author@email.com>" # 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 
    
  2. Інший спосіб 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 <author@email.com>"  # change the author name & email
    
    # Save changes and exit the editor
    
    $ git rebase --continue                # finish the rebase
    

2
Дуже приємна відповідь. Мені подобається, що зміни завершуються з самого оновлення до навіть прибирання git фіксує
Aleks

12

Найшвидший, найпростіший спосіб зробити це - використовувати аргумент --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
...

і це працюватиме все автоматично, що працює, коли у вас є сотні комітетів.


9

Якщо ви єдиний користувач цього репозиторію, ви можете переписати історію, використовуючи або git filter-branch(як написав svick ), або git fast-export/ git fast-importплюс сценарій фільтра (як описано у статті, на який посилається у відповіді доктгнома ), або інтерактивну ребазу . Але будь-яка з них змінила б перегляд з першого зміненого зобов'язання далі; це означає неприємності для будь-кого, хто базував свої зміни на вашій гілці попередньо переписати.

ВІДНОВЛЕННЯ

Якби інші розробники не базували свою роботу на попередньо переписаній версії, найпростішим рішенням було б повторне клонування (клонування знову).

Крім того, вони можуть спробувати git rebase --pull, які б перемоталися вперед, якби в їх сховищі не було змін, або перезавантажити свою гілку поверх переписаних комітетів (ми хочемо уникнути злиття, оскільки це би зберегло попередньо перезаписані комісії назавжди). Все це за умови, що вони не закінчили роботи; використанняgit stash для приховування змін в іншому випадку.

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

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

Тут origin/master@{1}попередньо переписують стан (до вибірки), см gitrevisions .


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

Процедура йде приблизно так:

  1. Знайдіть усі комісії з неправильною електронною поштою, наприклад, використовуючи

    $ git log --author=user@wrong.email --all
    
  2. Для кожної неправильної комісії створіть заміну заміни та додайте її до бази даних об’єктів

    $ git cat-file -p <ID of wrong commit> | 
      sed -e 's/user@wrong\.email/user@example.com/g' > tmp.txt
    $ git hash-object -t commit -w tmp.txt
    <ID of corrected commit>
    
  3. Тепер, коли ви виправили фіксацію в об’єктній базі даних, ви повинні сказати git автоматично та прозоро замінити неправильну git replaceкоманду виправленою командою за допомогою команди:

    $ git replace <ID of wrong commit> <ID of corrected commit>
    
  4. Нарешті, перерахуйте всю заміну, щоб перевірити, чи вдалася ця процедура

    $ git replace -l
    

    і перевірити, чи відбувається заміна

    $ git log --author=user@wrong.email --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

Якщо ви використовуєте Eclipse з EGit, то є досить просте рішення.
Припущення: у вас є місце в локальній гілці 'local_master_user_x', яку не можна перенести до віддаленої гілки 'master' через недійсного користувача.

  1. Оформити замовлення віддаленого відділення "master"
  2. Виберіть проекти / папки / файли, для яких "local_master_user_x" містить зміни
  3. Клацніть правою кнопкою миші - Замінити на - Відділення - "local_master_user_x"
  4. Знову внесіть ці зміни, на цей раз як правильний користувач, і перейдіть до локальної гілки 'master'
  5. Натисніть на "віддалений"

5

Використовуючи інтерактивну базу даних, ви можете розміщувати команду поправки після кожного вчинення, яке потрібно змінити. Наприклад:

pick a07cb86 Project tile template with full details and styling
x git commit --amend --reset-author -Chead

3
Проблема в цьому полягає в тому, що інші метадані фіксації (наприклад, дата та час) також внесені зміни. Я щойно виявив це важким шляхом ;-).
півзахисник

5

Зверніть увагу , що Git зберігає два різних адреси електронної пошти, один за комміттер (особа, які вчинили зміни) і ще один для автора (людина , яка написала зміна).

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

Зміна автора останнього зобов’язання є настільки ж простим, як git commit --amend --author "Author Name <email@example.com>" , немає жодного вкладиша або аргументу, який би зробив те саме з інформацією про виконавця.

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

git config user.email my_other_email@example.com 
git commit --amend

Зауважте, що старе значення все ще знаходиться в кількох місцях у path\to\repo\.git. Я ще не впевнений, що вам потрібно зробити, щоб повністю викреслити це. На жаль, зміни, на жаль (?) Не здаються.
ruffin

5

Сьогодні у нас виникла проблема, коли символ UTF8 в імені автора спричиняв проблеми на сервері збірки, тому нам довелося переписати історію, щоб виправити це. Вжиті кроки:

Крок 1: Змініть своє ім'я користувача в git для всіх майбутніх комісій, згідно з інструкціями тут: https://help.github.com/articles/setting-your-username-in-git/

Крок 2: Запустіть такий сценарій bash:

#!/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="me@something.com"
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

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

У нас виникли проблеми з запуском цього на OS X, оскільки він якимось чином переплутав закінчення рядків у повідомленнях комітів, тому нам довелося потім запустити його на машині Linux.


5

Ваша проблема справді поширена. Див. " Використання пошти для виправлення списку авторів у Git "

Для простоти я створив сценарій, щоб полегшити процес: git-changemail

Поклавши цей сценарій на свій шлях, ви можете видавати команди типу:

  • Змінення відповідностей авторів у поточній галузі

    $ git changemail -a old@email.com -n newname -m new@email.com
    
  • Змініть відповідність між автором і виконавцем на <branch> і <branch2>. Перейдіть -fдо відділення фільтрів, щоб дозволити перезапис резервних копій

    $ git changemail -b old@email.com -n newname -m new@email.com -- -f &lt;branch> &lt;branch2>
    
  • Показати існуючих користувачів на репо

    $ git changemail --show-both
    

До речі, після внесення змін очистіть резервну копію з гілки фільтрів за допомогою: git-backup-clean


1
коли я запускаю вашу команду, вона говорить "фатально: не можна виконати" git-changemail ": дозвіл відхилено"
Govind


3

Я також хочу додати свій Приклад. Я хочу створити функцію bash_ з заданим параметром.

це працює в 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:-"you_wrong_mail@hello.world"}
 NEW_NAME=${2:-"your name"}
 NEW_EMAIL=${3:-"new_mail@hello.world"}

 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;
}

2

Якщо ви єдиний користувач цього репо або не переймаєтесь можливим порушенням репо для інших користувачів, то так. Якщо ви натиснули ці комісії, і вони існують там, де ще десь вони можуть отримати доступ до них, тоді ні, якщо тільки вам не байдуже порушувати репост інших людей. Проблема полягає в тому, що, змінивши ці зобов'язання, ви будете генерувати нові SHA, що спричинить їх трактування як різні зобов'язання. Коли хтось інший намагається втягнутись у ці змінені комісії, історія інша і кабум.

На цій сторінці http://inputvalidation.blogspot.com/2008/08/how-to-change-git-commit-author.html описано, як це зробити. (Я не пробував цього так YMMV)


Отже, не існує безпечного способу переписати user.email. Не обдуваючи всіх інших. Я знав, що історія переписування - погана ідея, я просто думав, що може бути чистий спосіб зробити це безпечно. Дякую.
manumoomoo

@mediaslave: Спробуйте refs/replace/механізм.
Якуб Нарбський

meta.stackexchange.com/a/8259/184684 - також, підсумовуйте посилання, щоб перетворити їх на відповіді.
ruffin
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.