Git'teki birden çok taahhüdün yazarını ve değiştiren adını ve e-postasını nasıl değiştirebilirim?


2391

Okul bilgisayarında basit bir senaryo yazıyordum ve Git'teki değişiklikleri (pendrive'ımdaki bir repoda, evdeki bilgisayarımdan klonlanmış) yapıyordum. Birkaç işlemden sonra kök kullanıcı olarak bir şeyler yaptığımı fark ettim.

Bu taahhütlerin yazarını benim adımla değiştirmenin bir yolu var mı?


13
Soru: git filtre-dalını kullanmak önceki etiketler, versiyonlar ve nesneler için SHA1'leri koruyor mu? Yoksa yazarın isim kuvvetini değiştirmek ilişkili SHA1'leri de değiştirir mi?
AndyL

36
Hashes evet değişecek
Müsait değil

3
Teğet olarak, sonunda benim için temel nedeni düzelten küçük bir senaryo oluşturdum. gist.github.com/tripleee/16767aa4137706fd896c
üçlü

2
@impinball Sorunun yaşı pek alakalı değil. Yeni bir yinelenen soru oluşturmak söz konusu değil. Sanırım bu özel yanıtı isteyen bir soru yaratabilirim, ancak bu kadar görünürlüğe sahip olacağına tamamen ikna olmadım. Burada Git sorularının sıkıntısı yok gibi ... Zaten yardım edebildiğim için mutluyum.
üçlü

Yanıtlar:


1211

Bu cevap kullanımları git-filter-branchiçin de docs şimdi bu uyarı vermek:

git filter-branch, hedeflenen tarih yeniden yazımının belirgin olmayan manglinglerini üretebilen (ve bu tür bir dipsiz performansa sahip olduğu için bu tür sorunları araştırmak için size çok az zaman bırakabilecek) çok sayıda tuzağa sahiptir. Bu güvenlik ve performans sorunları geriye dönük olarak uyumlu şekilde sabitlenemez ve bu nedenle kullanılması önerilmez. Lütfen git filter-repo gibi alternatif bir geçmiş filtreleme aracı kullanın . Git filtre dalını kullanmaya devam etmeniz gerekiyorsa, lütfen filtre dalının kara mayınları hakkında bilgi edinmek için lütfen GÜVENLİK (ve PERFORMANS ) bölümünü dikkatlice okuyun ve orada listelenen tehlikelerden mümkün olduğunca makul bir şekilde kaçının.

Yazarın (ya da değiştiricinin) değiştirilmesi, tüm tarihin yeniden yazılmasını gerektirir. Bu konuda iyiyseniz ve buna değer olduğunu düşünüyorsanız, git filter-branch'u kontrol etmelisiniz . Man sayfası, başlamanıza yardımcı olacak birkaç örnek içerir. Ayrıca, yazarın adını, değiştiricisini, tarihlerini vb. Değiştirmek için ortam değişkenlerini kullanabileceğinizi unutmayın - git man sayfasının "Ortam Değişkenleri" bölümüne bakın .

Özellikle, bu komutla tüm dallar ve etiketler için tüm yanlış yazar adlarını ve e-postalarını düzeltebilirsiniz (kaynak: GitHub help ):

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

611
Github'un bu help.github.com/articles/changing-author-info için herkese açık bir senaryosu var ve harika çalışıyor!
Haziran'da defvol

34
Komut dosyasını yürüttükten sonra "git update-ref -d refs / original / refs / heads / master" komutunu kullanarak yedekleme dalını kaldırabilirsiniz.
DR

7
@rodowi, tüm taahhütlerimi çoğaltır.
Rafael Barros

6
@RafaelBarros yazar bilgisi (tıpkı tarihteki her şey gibi) taahhüdün sha anahtarının bir parçasıdır. Geçmişteki herhangi bir değişiklik, tüm taahhütler için yeni kimliklere yol açan bir yeniden yazmadır. Paylaşılan bir repo üzerinde yeniden yazmayın veya tüm kullanıcıların bunun farkında olduğundan emin olun ...
johannes

20
Çözüldügit push --force --tags origin HEAD:master
mcont

1577

NOT: Bu cevap SHA1'leri değiştirir, bu yüzden daha önce itilmiş olan bir dalda kullanmaya dikkat edin. Yalnızca bir adın yazımını düzeltmek veya eski bir e-postayı güncellemek istiyorsanız git, bunu geçmişi yeniden yazmadan yapabilirsiniz .mailmap. Diğer cevabımı gör .

Etkileşimli Rebase Kullanımı

Yapabilirsin

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

Ardından, tüm kötü taahhütlerinizi rebase dosyasında "düzenle" olarak işaretleyin. İlk taahhüdünüzü de değiştirmek istiyorsanız, rebase dosyasında ilk satır olarak manuel olarak eklemeniz gerekir (diğer satırların biçimini izleyin). Sonra git, sizden her taahhütte değişiklik yapmanızı istediğinde,

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

açılan düzenleyiciyi düzenleyin veya kapatın ve ardından

git rebase --continue

Rebase'e devam etmek.

--no-edit Komutun şu şekilde olması için editörü ekleyerek burada açmayı atlayabilirsiniz :

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

Tek İşlem

Bazı yorumcuların belirttiği gibi, sadece en son taahhüdü değiştirmek istiyorsanız, rebase komutu gerekli değildir. Sadece yap

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

Bu belirtilen isme yazar değişecek, ama committer yapılandırılmış kullanıcıya ayarlanacaktır git config user.nameve git config user.email. Committer'ı belirttiğiniz bir şeye ayarlamak istiyorsanız, bu hem yazarı hem de committer'ı ayarlar:

 git -c user.name="New Author Name" -c user.email=email@address.com commit --amend --reset-author

Birleştirme Taahhütleri Hakkında Not

Orijinal yanıtımda hafif bir kusur vardı. Akım HEADile sizin arasında birleştirme taahhütleri varsa <some HEAD before all your bad commits>, git rebasebunları düzleştirir (ve bu arada, GitHub çekme isteklerini kullanırsanız, geçmişinizde bir ton birleştirme taahhütleri olacaktır). Bu genellikle çok farklı bir geçmişe yol açabilir (yinelenen değişiklikler "yeniden temel alınabilir") ve en kötü durumda, git rebasebirleştirme işlemlerinde büyük olasılıkla çözülmüş olan zor birleştirme çakışmalarını çözmenizi isteyebilir. Çözüm, tarihinizin birleştirme yapısını koruyacak -pbayrağı kullanmaktır git rebase. Manpage, kullanımı ve sorunlara yol açabileceği git rebasekonusunda uyarır , ancak-p-iBUGS "Taahhütlerin düzenlenmesi ve taahhüt mesajlarının yeniden düzenlenmesi işe yaramalıdır."

-pYukarıdaki komuta ekledim . En son taahhüdü değiştirdiğiniz durumda, bu bir sorun değildir.


27
Yine de tek taahhüt için harika - eğer eşleştiriyorsanız ve yazarı değiştirmeyi unutursanız yararlı
mloughran

32
Tipik tek hata düzeltmesi için kullanıcı tabanından bahsettiği için +1: git commit --amend --author = kullanıcı adı
Nathan Kidd

12
Bu mükemmel, en yaygın kullanımım, başka bir bilgisayarda oturup yazar kurmayı unutmam ve bu nedenle genellikle <5 taahhütte bulunmam.
Zitrax

57
git commit --amend --reset-authorayrıca bir kez çalışır user.nameve user.emaildoğru yapılandırılır.
Puan

14
Sonuçta kaydedilmesini üzerinde yazar bilgisi yeniden yazma <commit>kullanarak user.nameve user.emailgelen ~/.gitconfigvadede: git rebase -i <commit> --exec 'git commit --amend --reset-author --no-edit'çıkın kaydet. Düzenlemeye gerek yok!
ntc2

588

Ayrıca şunları da yapabilirsiniz:

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

Bu komutu Windows komut isteminde kullanıyorsanız, aşağıdakiler "yerine kullanmanız gerekir ':

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-filter kullanmak daha kolay bir çözüm değil mi? Bunun neden daha fazla oy aldığından emin değilim.
stigkj

3
Sonra bağlantı koptu. Bu değişiklikleri başka bir havuza nasıl gönderebiliriz?
Russell

28
env-filter tüm taahhütleri değiştirecektir. Bu çözüm koşullu bir izin verir.
user208769

5
"A previous backup already exists in refs/original/ Force overwriting the backup with -f"üzgünüm ama -f-flag bu betiği iki kez yürütürken nereye gidecek. Aslında bu Brian'ın cevabında, filtre branşının çözümünden hemen sonra rahatsızlıktan dolayı özür dilerim.
hhh

2
@ user208769 env-filter ayrıca koşullu bir izin verir; cevabım bak :-)
stigkj

559

Bir astar, ancak çok kullanıcılı bir deponuz varsa dikkatli olun - bu, tüm taahhütleri aynı (yeni) yazar ve komisyoncuya sahip olacak şekilde değiştirecektir .

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

Dizedeki satır aralıklarıyla (bash'da mümkündür):

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

Küçük bir nokta, ihracat hiçbir zarar vermese de aslında gereksizdir. örneğin git-filter-branch --env-filter "GIT_AUTHOR_NAME = 'Yeni ad'; GIT_AUTHOR_EMAIL = 'Yeni e-posta'" HEAD.
Alec the Geek

4
HEADKomutun sonunda belirtirseniz neden tüm işlemleri yeniden yazıyor ?
Nick Volynkin

1
Bu benim bitbucket depom için işe yaramıyor, herhangi bir fikir? git push --force --tags origin 'refs/heads/*'
Tavsiye edilen

1
Bunun için itme komutu:$git push --force --tags origin 'refs/heads/master'
HARSH NILESH PATHAK

1
Temiz; bu eski zaman damgalarını da korur.
DharmaTurtle

221

Başlatılmış bir $ HOME / .gitconfig dosyası olmadığında olur. Bunu şu şekilde düzeltebilirsiniz:

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

git sürüm 1.7.5.4 ile test edildi


9
Bu son taahhütte gerçekten iyi çalışıyor. Güzel ve basit. Küresel bir değişiklik olmak zorunda değil , --localişleri de kullanıyor
Ben

Bu benim için büyük kazanan oldu! git commit --amend --reset-author --no-editKomut sonra, yanlış yazar bilgileri ile kaydedilmesini yarattı olaydan sonra aracılığı doğru yazar ayarlarsanız özellikle yararlıdır git config. E-postamı güncellemek zorunda kaldığımda şimdi bir $$ kaydetti.
ecbrodie

187

Tek bir taahhüt için:

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

(hissedarın cevabından çıkarılmıştır)


14
ancak bu sadece en son taahhüt ise
Richard

4
Göre git help commit, git commit --amend(KAFA olan) “mevcut dalın ucundan” de tamamlama değişir. Bu normalde en son taahhüttür, ancak önce veya ile olan taahhütleri kontrol ederek istediğiniz herhangi bir taahhütte bulunabilirsiniz . git checkout <branch-name>git checkout <commit-SHA>
Rory O'Kane

12
Ancak bunu yaparsanız, ebeveyn olarak bu taahhüde sahip olan tüm taahhütler yanlış taahhüdü işaret edecektir. Bu noktada filtre dalı kullanmak daha iyidir.
John Gietzen

3
@JohnGietzen: Taahhütleri düzeltmek için değiştirilene geri verebilirsiniz. Ancak,> 1 taahhütte bulunuyorsanız, belirtildiği gibi, filtre dalı muhtemelen çok daha kolay olacaktır.
Thanatos

5
Bu değişiklik sadece taahhüt authorve değilcommitter
Nick Volynkin

179

Sadece en iyi birkaç komisyonun kötü yazarları olması durumunda, bunu komut ve taahhüt git rebase -ikullanarak aşağıdaki gibi yapabilirsiniz:exec--amend

git rebase -i HEAD~6 # as required

size düzenlenebilir taahhüt listesi sunar:

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

Ardından exec ... --author="..."kötü yazarlı tüm satırlardan sonra satır ekleyin :

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

kaydedin ve düzenleyiciden çıkın (çalıştırmak için).

Bu çözüm diğerlerinden daha uzun sürebilir, ancak oldukça kontrol edilebilir - Ne işe yaradığını tam olarak biliyorum.

İlham için @asmeurer'a teşekkürler.


26
Kesinlikle harika. Reponun yerel yapılandırmasında user.name ve user.email öğelerini ayarlayarak kısaltabilir misiniz ve her satır yalnızca exec git commit --amend --reset-author -C HEAD?
Andrew

1
Kanonik cevap, filtre dalı kullanmak için, sadece benim için refs / heads / master sildi. Yani kontrol edilebilir, düzenlenebilir çözümünüze + 1'leyin. Teşekkürler!
jmtd

Neden birlikte başlarım Someone else's commityerine my bad commit 1? Sadece HEAD^^son 2 taahhüdü değiştirmeye çalıştım ve mükemmel çalıştı.
fredoverflow

3
Bunun yerine git rebase -i HEAD^^^^^^yazabilirsinizgit rebase -i HEAD~6
Patrick Schlüter

1
Bu işlemin taahhütlerin zaman damgasını değiştirdiğini lütfen unutmayın. Doğru zaman damgalarına
dönmek

111

Github, aşağıdaki kabuk betiği olan güzel bir çözüme sahiptir :

#!/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
Mükemmel çalıştı. Sadece daha git reset --hard HEAD^önceki bir sürüme ulaşmak için diğer yerel depolarda birkaç kez vardı git pull, değiştirilmiş sürümü, ve burada içeren herhangi bir satır olmadan unknown <stupid-windows-user@.StupidWindowsDomain.local>(git'in varsayılan aşk var).
Alan Plum

1
Bundan sonra zorlayamam. "-F" kullanmak zorunda mıyım?
Balık Monitörü

9
Yaptım git push -f. Ayrıca bundan sonra yerel depoların yeniden oluşturulması gerekir.
Balık Monitörü

Kabuk betiğini belirli bir dalda çalıştırmanız gerekiyorsa, son satırı şu şekilde değiştirebilirsiniz: "'master..your-branch-name" (master'ın dallanmış olduğunuzu varsayarak).
Robert Kajic

Komut dosyası güncellendiğinde <nice solution> bağlantısına tıklayın
gxpr

82

Belgeselde de belirtildiği gibi, yeniden yazma tarihi tehlikelidir ve diğer insanların depolarını kıracaktır.

Ancak bunu gerçekten yapmak istiyorsanız ve bir bash ortamındaysanız (Linux'ta sorun yok, Windows'ta, git kurulumu ile sağlanan git bash'ı kullanabilirsiniz) git filter-branch kullanın :

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

İşleri hızlandırmak için, yeniden yazmak istediğiniz bir dizi düzeltme belirtebilirsiniz:

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
Bunun eski taahhütleri gösteren etiketleri bırakacağını unutmayın. --tag-name-filter cat"çalışmasını sağla" seçeneğidir.
Roman Starkov

@romkyns etiketleri nasıl değiştireceğiniz hakkında bir fikriniz var mı?
Nick Volynkin

@NickVolynkin Evet, siz belirleyin --tag-name-filter cat. Bu gerçekten varsayılan davranış olmalı.
Roman Starkov

48

Başka bir yazardan birleştirilmemiş bir taahhüt devralırken, bunu ele almanın kolay bir yolu vardır.

git commit --amend --reset-author


1
Tek bir taahhüt için ve kullanıcı adınızı koymak istiyorsanız, bu en kolay yoldur.
Pedro Benevides

7
Bunu --no-editdaha da kolaylaştırmak için ekleyebilirsiniz , çünkü çoğu insan taahhüt mesajını değil yalnızca e-posta adresini güncellemek isteyecektir
PlagueHammer

Son komutun e-posta / kullanıcı adını yenisiyle güncellemek için lütfen git komutunu paylaşabilir misiniz
adi

Bunu denedin mi? Bunun bir yan etkisi olmalı, değilse stackoverflow.com/a/2717477/654245 iyi bir yol gibi görünüyor.
Ryanmt

46

Bunu bir takma ad olarak kullanabilirsiniz, böylece şunları yapabilirsiniz:

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

veya son 10 taahhüt için:

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

~ / .Gitconfig dosyasına ekleyin:

[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 "

Kaynak: https://github.com/brauliobo/gitconfig/blob/master/configs/.gitconfig

Umarım faydalıdır.


"git: 'change-commits' bir git komutu değil. Bkz. 'git --help'."
Native_Mobile_Arch_Dev

Bu komut ve master ile senkronizasyondan sonra geçmişteki tüm taahhütler kopyalanır! Diğer kullanıcıların bile :(
Vladimir

@ Beklenen Vladimir, lütfen git tarih değiştirme hakkında git
brauliobo

39

Bu @ Brian'ın versiyonunun daha ayrıntılı bir versiyonudur:

Yazarı ve değiştiriciyi değiştirmek için bunu yapabilirsiniz (dizede bash içinde mümkün olan satır izleri ile):

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

Aşağıdaki hatalardan birini alabilirsiniz:

  1. Geçici dizin zaten var
  2. Refs / original ile başlayan referanslar zaten var
    (bu, daha önce depoda başka bir filtre dalının çalıştırıldığı ve daha sonra orijinal dal başvurusunun refs / original'da yedeklendiği anlamına gelir )

Bu hatalara rağmen çalıştırmayı zorlamak istiyorsanız, --forcebayrağı ekleyin :

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

-- --allSeçeneğin küçük bir açıklaması gerekebilir: Filtre şubesinin tüm referanslardaki (tüm şubeleri içeren) tüm revizyonlar üzerinde çalışmasını sağlar . Bu, örneğin, etiketlerin de yeniden yazıldığı ve yeniden yazılan dallarda görülebileceği anlamına gelir.

Bunun yerine yaygın bir "hata" kullanmak HEAD, yalnızca geçerli daldaki tüm düzeltmeleri filtrelemek anlamına gelir . Ve sonra yeniden yazılan dalda hiçbir etiket (veya başka referanslar) mevcut olmaz.


Tüm ref / şubelerde değişiklik yapan bir prosedürün sağlanması için şeref .
Johnny Utahh

25

Bir tek komut geçen N kaydedilmesini yazarını değiştirmek için:

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

NOTLAR

  • --no-editbayrak markaları emin git commit --amendekstra onay sormuyor
  • kullandığınızda git rebase -i, yazarın değiştirileceği taahhütleri manuel olarak seçebilirsiniz,

düzenlediğiniz dosya şöyle görünür:

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

Daha sonra, yazarı nerede değiştirmek istediğinizi görmek için bazı satırları değiştirebilirsiniz. Bu, otomasyon ve kontrol arasında güzel bir orta yol sağlar: çalışacak adımları görürsünüz ve kaydettiğinizde her şey bir kerede uygulanır.


Müthiş! Teşekkür ederim!
Pablo Lalloni

HEAD ~ 8 kullandım ve son 8 işlemden daha fazla yol gösteriyor.
Bryan Bryce

1
@BryanBryce birleştirme taahhütleri varsa işler karmaşıklaşır :)
Chris Maes

@ChrisMaes Ah, neler olduğunu anladım. Bunlarla uğraşmak istemiyorum, sadece dalda olduğum dalda.
Bryan Bryce

Bu durumda, ustadan dallanmış olduğunuzu varsayalım, şunları yapabilirsiniz:git rebase -i master -x ...
Chris Maes

23
  1. Çalıştırmak git rebase -i <sha1 or ref of starting point>
  2. değiştirmek istediğiniz tüm taahhütleri işaretleyin edit(veya e)
  3. tüm işlemleri tamamlayana kadar aşağıdaki iki komutu tekrarlayın:

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

Bu, diğer tüm taahhüt bilgilerini (tarihler dahil) tutacaktır. Bu --reuse-message=HEADseçenek, mesaj düzenleyicinin başlatılmasını önler.


23

Etiketleri ve tüm dalları da dahil olmak üzere tüm bir depo için yazar yeniden yazmak için aşağıdakini kullanın:

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

Ardından, filtre dalının MAN sayfasında açıklandığı gibi, tarafından yedeklenen tüm orijinal referansları kaldırın filter-branch(bu yıkıcı, önce yedekleme):

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

2
Kullanmak çok önemli --tag-name-filter cat. Aksi takdirde etiketleriniz orijinal taahhüt zincirinde kalır. Diğer cevaplar bundan bahsetmiyor.
Ocak

21

Basit bir çözüm elde ederek çalışan bu çözümü uyarladım author-conv-file(format git-cvsimport için olanla aynıdır ). author-conv-fileTüm şubelerde tanımlanan tüm kullanıcıları değiştirerek çalışır .

Bunu cvs2gitdepomuzu cvs'den git'e taşımak için birlikte kullandık .

yani Örnek author-conv-file

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

Senaryo:

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

Teşekkürler, neden çekirdek git (veya git-svn) işlevselliği olmadığını merak ediyorum. Bu git svn klonu için bir bayrakla yapılabilir, ancak git filtre dalında değil ...
Daniel Hershcovich

20

Tek sorun yazarın / e-postanın her zamankinden farklı olması durumunda, bunun bir sorun olmadığını belirtmeliyim. Doğru düzeltme, .mailmapdizinin altında çağrılan bir dosya oluşturmaktır.

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

Ve o zamandan itibaren, gibi komutlar git shortlogbu iki ismi aynı olarak değerlendirecektir (özellikle onlara söylemediğiniz sürece). Daha fazla bilgi için http://schacon.github.com/git/git-shortlog.html adresine bakın .

Bu, diğer tüm çözümlerin avantajına sahiptir, çünkü geçmişi yeniden yazmak zorunda kalmazsınız, bu da bir yukarı akışınız varsa sorunlara neden olabilir ve yanlışlıkla veri kaybetmenin her zaman iyi bir yoludur.

Tabii ki, kendiniz gibi bir şey taahhüt ettiyseniz ve gerçekten başka biri olmalı ve bu noktada geçmişi yeniden yazmayı önemsemiyorsanız, taahhüt yazarını değiştirmek muhtemelen atıf amaçları için iyi bir fikirdir (bu durumda sizi burada başka cevap).


18

Sunulan sürümleri agresif bir şekilde buldum, özellikle diğer geliştiricilerin yamalarını yaparsanız, bu aslında kodlarını çalacaktır.

Aşağıdaki sürüm tüm dallarda çalışır ve bunu önlemek için yazar ve göndericiyi ayrı ayrı değiştirir.

Tüm seçenekler için leif81 için Kudos.

#!/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. Değişim taahhüt author name & emailtarafından Amenddaha sonra yerine 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. Başka bir yol 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
Çok güzel bir cevap. Değişikliklerin, güncelleme taahhütlerini temizlemeye kadar güncellemeden tamamlandığını beğendim
Aleks

12

Bunu yapmanın en hızlı, en kolay yolu git rebase'in --exec argümanını kullanmaktır:

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

Bu, şuna benzer bir yapılacaklar listesi oluşturur:

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
...

ve bu otomatik olarak çalışacak, yüzlerce işiniz olduğunda işe yarayacak.


9

Bu deponun sadece kullanıcı iseniz, olabilir tarihi yeniden kullanarak git filter-branch(olarak svick yazdım ) veya git fast-export/ git fast-importartı filtre (başvurulan makalesinde anlatıldığı gibi komut docgnome cevap ) veya etkileşimli Rebase . Ancak bunlardan herhangi biri, revizyonları ilk değişikliğin ardından değiştirecek; bu, değişikliklerini kendi dalınıza yeniden yazmaya dayanan herkes için sorun demektir.

KURTARMA

Diğer geliştiriciler çalışmalarını yeniden yazma öncesi sürüme dayandırmamışlarsa, en basit çözüm yeniden klonlamak olacaktır (tekrar klonlamak).

Alternatif olarak, git rebase --pulldepolarında herhangi bir değişiklik olmasaydı hızlı ileri gidebilir veya dallarını yeniden yazılmış taahhütlerin üzerine yeniden bastırabilirler (yeniden yazma önizlemelerini sonsuza dek tutacağı için birleştirmeden kaçınmak istiyoruz). Bütün bunlar, işlerini taahhüt etmediklerini varsayarak; kullanımgit stashaksi takdirde değişiklikleri saklamak için .

Diğer geliştiricilerin özelliği dalları kullanın ve / veya varsa git pull --rebasememba kurulmamış çünkü örneğin çalışmıyor, onlar zorunda rebase sonrası yeniden yazma kaydedilmesini üstünde işlerini. Örneğin, yeni değişiklikler getirildikten hemen sonra ( git fetch), masterkaynağa dayalı / çatallı bir dal için origin/master,

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

Burada origin/master@{1}yeniden yazma öncesi durum (getirmeden önce), bkz. Gitrevisions .


Alternatif çözüm, 1.6.5 sürümünden beri Git'te bulunan refs / replace / mekanizmasını kullanmak olacaktır . Bu çözümde, yanlış e-postaya sahip olan taahhütlerin yerine geçecek yedekleri sağlarsınız; Sonra getirir herkes ref (gibi bir şey 'yerine' fetch = +refs/replace/*:refs/replace/*uygun yerde refspec onların .git/config şeffaf alacağı değiştirmeler) ve eski kaydedilmesini görecekti bu ref getirme olmayanlar.

Prosedür şu şekilde gider:

  1. Yanlış e-posta ile tüm taahhütleri bulun, örneğin

    $ git log --author=user@wrong.email --all
    
  2. Her yanlış taahhüt için bir yedek taahhüt oluşturun ve bunu nesne veritabanına ekleyin

    $ 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. Nesne veritabanındaki kesinliği düzelttiğinize göre, git git replacekomutunu komut kullanarak otomatik olarak ve şeffaf bir şekilde yanlış kesinliği değiştirmesini söylemelisiniz :

    $ git replace <ID of wrong commit> <ID of corrected commit>
    
  4. Son olarak, bu prosedürün başarılı olup olmadığını kontrol etmek için tüm değiştirmeleri listeleyin

    $ git replace -l
    

    ve değişikliklerin olup olmadığını kontrol edin

    $ git log --author=user@wrong.email --all
    

Elbette bu prosedürü otomatikleştirebilirsiniz ... iyi, git replacehenüz toplu modu olmayan ( hariç) kullanımı hariç , bunun için kabuk döngüsünü kullanmanız veya "elle" değiştirmeniz gerekir.

TEST EDİLMEDİ! YMMV.

refs/replace/Mekanizmayı kullanırken bazı kaba köşelerle karşılaşabileceğinizi unutmayın : yeni ve henüz çok iyi test edilmemiştir .


6

Düzeltmek istediğiniz taahhütler en sonuncuysa ve bunlardan sadece birkaçı ise , doğru adı ve e-postayı yapılandırdıktan sonra bir kombinasyonunu kullanabilir git resetve git stashbir taahhütte bulunabilirsiniz.

Dizi şu şekilde olacaktır (2 yanlış taahhüt için, bekleyen değişiklik yok):

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

Ecitse'yi EGit ile kullanıyorsanız, oldukça kolay bir çözüm var.
Varsayım: Yerel kullanıcı 'local_master_user_x' dalında, geçersiz kullanıcı nedeniyle uzak bir ana yöneticiye gönderilemeyen taahhütleriniz var.

  1. Uzak daldaki 'master'a göz atın
  2. 'Local_master_user_x' öğesinin değişiklik içerdiği projeleri / klasörleri / dosyaları seçin
  3. Sağ tıklayın - Şununla değiştir - Şube - 'local_master_user_x'
  4. Bu değişikliği tekrar doğru kullanıcı olarak ve yerel şubeye 'master' yapın
  5. Uzaktan kumanda 'master'a aktar

5

Etkileşimli rebase'i kullanarak değiştirmek istediğiniz her bir taahhüdün ardından bir değişiklik komutu yerleştirebilirsiniz. Örneğin:

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

3
Buradaki sorun, diğer taahhüt meta verilerinin (örneğin tarih ve saat) de değiştirilmesidir. Bunu zor yoldan öğrendim ;-).
halfer

5

Not o git depolar iki farklı e-posta adresleri için bir committer (değişiklik işleyen kişinin) ve başka bir yazar (değişim yazdı kişi).

Committer bilgileri çoğu yerde görüntülenmez, ancak bunu ile görebilirsiniz git log -1 --format=%cn,%ce(veya belirli bir taahhüdü belirtmek showyerine kullanın log).

Son taahhüdünüzün yazarını değiştirmek kadar basit git commit --amend --author "Author Name <email@example.com>" , komisyon bilgisine aynı şeyi yapan tek bir astar veya argüman yoktur.

Çözüm, kullanıcı bilgilerinizi değiştirmek (geçici olarak veya değil), ardından taahhütçeyi değiştirmek;

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

Eski değerin hala birkaç yerde olduğunu unutmayın path\to\repo\.git. Tamamen ortadan kaldırmak için ne yapmanız gerektiğinden henüz emin değilim. Ne yazık ki değişiklikler (?) Silinmiş gibi görünmüyor.
ruffin

5

Bugün bir yazar adındaki UTF8 karakterinin yapı sunucusunda soruna neden olduğu bir sorun yaşadık, bu yüzden bunu düzeltmek için geçmişi yeniden yazmak zorunda kaldık. Atılan adımlar:

Adım 1: Git'teki kullanıcı adınızı gelecekteki tüm taahhütler için aşağıdaki talimatlara göre değiştirin: https://help.github.com/articles/setting-your-username-in-git/

Adım 2: Aşağıdaki bash betiğini çalıştırın:

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

Hızlı genel bakış: Deponuza geçici bir dosyaya bakın, tüm uzak dalları kontrol edin, geçmişi yeniden yazan komut dosyasını çalıştırın, yeni durumu zorla uygulayın ve tüm meslektaşlarınıza değişiklikleri almak için bir rebase çekme işlemi yapmasını söyleyin.

OS X'te bunu çalıştırmakta sorun yaşadık, çünkü işlem mesajlarında bir şekilde satır sonlarını berbat etti, bu yüzden daha sonra bir Linux makinesinde yeniden çalıştırmak zorunda kaldık.


5

Sorununuz gerçekten yaygın. Bkz. " Git'teki Yazarlar Listesini Düzeltmek için Posta Haritasını Kullanma "

Basitlik adına, süreci kolaylaştırmak için bir komut dosyası oluşturdum: git-changemail

Bu komut dosyasını yolunuza koyduktan sonra, aşağıdaki gibi komutlar verebilirsiniz:

  • Geçerli daldaki yazar eşleşmelerini değiştirme

    $ git changemail -a old@email.com -n newname -m new@email.com
    
  • <branch> ve <branch2> üzerindeki yazar ve değiştirici eşleşmelerini değiştirin. Geçiş -ffiltresi-dalına yedekleri yeniden izin vermek

    $ git changemail -b old@email.com -n newname -m new@email.com -- -f &lt;branch> &lt;branch2>
    
  • Mevcut kullanıcıları depoda göster

    $ git changemail --show-both
    

Bu arada, değişikliklerinizi yaptıktan sonra filtre dalından yedeklemeyi şu yolla temizleyin: git-backup-clean


1
komutunu çalıştırdığımda, "ölümcül: 'git-changemail' çalıştırılamıyor: İzin reddedildi" diyor
Govind


3

Örneğimi de eklemek istiyorum. Verilen parametre ile bir bash_function oluşturmak istiyorum .

Bu nane-linux-17.3 çalışır

# $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

Bu repo'nun tek kullanıcısıysanız veya muhtemelen diğer kullanıcılar için repoyu kırmakla ilgilenmiyorsanız, evet. Bu taahhütleri ittiyseniz ve başkalarının erişebileceği başka bir yerde mevcutlarsa, başkalarının depolarını kırmakla ilgilenmiyorsanız hayır. Sorun, bu taahhütleri değiştirerek farklı taahhütler olarak muamele görmelerine neden olacak yeni SHA'lar oluşturacaksınız. Bu değişen taahhütleri başka biri çekmeye çalıştığında, tarih farklı ve kaboom.

Bu sayfa http://inputvalidation.blogspot.com/2008/08/how-to-change-git-commit-author.html bunun nasıl yapılacağını açıklar. (Bunu denemedim bu yüzden YMMV)


Bu nedenle, user.email'i yeniden yazmanın güvenli bir yolu yoktur. Herkesi havaya uçurmadan. Tarihin yeniden yazılmasının kötü bir fikir olduğunu biliyordum, sadece bunu güvenli bir şekilde yapmanın temiz bir yolu olabileceğini düşündüm. Teşekkürler.
manumoomoo

@mediaslave: refs/replace/Mekanizmayı deneyin .
Jakub Narębski

meta.stackexchange.com/a/8259/184684 - aka, bunları yanıtlara dönüştürmek için bağlantıları toplayın .
ruffin
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.