จะเปลี่ยนชื่อผู้แต่งและผู้ส่งและอีเมลของคอมมิทหลายรายการใน Git ได้อย่างไร?


2391

ฉันกำลังเขียนสคริปต์ง่ายๆในคอมพิวเตอร์ของโรงเรียนและคอมมิชชันการเปลี่ยนแปลง Git (ใน repo ที่อยู่ใน pendrive ของฉันโคลนจากคอมพิวเตอร์ของฉันที่บ้าน) หลังจากการคอมมิทหลายครั้งฉันรู้ว่าฉันกำลังคอมมิทในฐานะผู้ใช้รูท

มีวิธีใดที่จะเปลี่ยนผู้สร้างสิ่งเหล่านี้ให้เป็นชื่อของฉัน?


13
คำถาม: การใช้ git filter-branch เก็บรักษา SHA1 ไว้สำหรับแท็กรุ่นและวัตถุก่อนหน้าหรือไม่ หรือจะเปลี่ยนชื่อผู้แต่งบังคับให้เปลี่ยน SHA1 ที่เกี่ยวข้องเช่นกัน?
AndyL

36
แฮชจะเปลี่ยนใช่
ไม่มีให้บริการ

3
ฉันจะสร้างสคริปเล็ก ๆ ซึ่งท้ายที่สุดก็แก้ไขต้นเหตุให้ฉัน gist.github.com/tripleee/16767aa4137706fd896c
tripleee

2
@impinball อายุของคำถามนั้นแทบจะไม่เกี่ยวข้องกันเลย การสร้างคำถามที่ซ้ำกันใหม่นั้นเกิดจากคำถาม ฉันคิดว่าฉันสามารถสร้างคำถามที่มีคำตอบเฉพาะนี้ แต่ฉันไม่เชื่อโดยสิ้นเชิงว่ามันจะได้รับการมองเห็นทั้งหมดที่มาก ไม่ใช่ว่ามีคำถาม Git ที่นี่ขาดแคลน ... ดีใจที่ฉันสามารถช่วยได้
tripleee

8
GitHub มีสคริปต์พิเศษสำหรับสิ่งนี้: help.github.com/articles/changing-author-info
Timur Bernikovich

คำตอบ:


1210

คำตอบนี้ใช้git-filter-branchซึ่งตอนนี้เอกสารให้คำเตือนนี้:

สาขาตัวกรอง git มีข้อผิดพลาดมากมายที่สามารถสร้าง manglings ที่ไม่ชัดเจนของการเขียนประวัติศาสตร์ที่ตั้งใจไว้ (และสามารถปล่อยให้คุณมีเวลาน้อยในการตรวจสอบปัญหาดังกล่าวเนื่องจากมีประสิทธิภาพสุดซึ้ง) ปัญหาด้านความปลอดภัยและประสิทธิภาพการทำงานเหล่านี้ไม่สามารถแก้ไขได้ย้อนหลังเข้ากันได้และไม่แนะนำให้ใช้งาน โปรดใช้เครื่องมือการกรองทางประวัติศาสตร์เช่นคอมไพล์กรอง repo หากคุณยังต้องการใช้สาขาตัวกรอง git โปรดอ่านSAFETY (และประสิทธิภาพ ) อย่างรอบคอบเพื่อเรียนรู้เกี่ยวกับการทำเหมืองในดินแดนของตัวกรองสาขาแล้วหลีกเลี่ยงอันตรายที่มีอยู่ในรายการให้มากที่สุด

การเปลี่ยนผู้แต่ง (หรือผู้เดินทาง) จะต้องเขียนประวัติศาสตร์ทั้งหมดใหม่ หากคุณโอเคกับที่และคิดว่ามันคุ้มค่าแล้วคุณควรตรวจสอบคอมไพล์กรองสาขา หน้าคนมีหลายตัวอย่างเพื่อให้คุณเริ่มต้น นอกจากนี้ทราบว่าคุณสามารถใช้ตัวแปรสภาพแวดล้อมที่มีการเปลี่ยนแปลงชื่อของผู้เขียน committer, วันที่, ฯลฯ - ดูส่วน "ตัวแปรสภาพแวดล้อม" ของหน้าคนคอมไพล์

โดยเฉพาะคุณสามารถแก้ไขชื่อผู้เขียนและอีเมลที่ไม่ถูกต้องทั้งหมดสำหรับสาขาและแท็กทั้งหมดด้วยคำสั่งนี้ (ที่มา: วิธีใช้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 มีสคริปต์สาธารณะสำหรับhelp.github.com/articles/changing-author-infoและใช้งานได้ดี!
defvol

34
หลังจากรันสคริปต์คุณสามารถลบสาขาสำรองโดยดำเนินการ "git update-ref -d refs / original / refs / heads / master"
DR

7
@rodowi มันซ้ำกับความมุ่งมั่นทั้งหมดของฉัน
Rafael Barros

6
@RafaelBarros ข้อมูลผู้แต่ง (เหมือนกับสิ่งอื่น ๆ ในประวัติศาสตร์) เป็นส่วนหนึ่งของคีย์ sha ของคอมมิชชัน การเปลี่ยนแปลงใด ๆ ในประวัติศาสตร์คือการเขียนซ้ำซึ่งนำไปสู่ ​​id ใหม่สำหรับการกระทำทั้งหมด ดังนั้นอย่าเขียนลงบน repo ที่แชร์หรือทำให้แน่ใจว่าผู้ใช้ทุกคนรับรู้ถึงมัน ...
johannes

20
แก้ไขการใช้git push --force --tags origin HEAD:master
mcont

1577

หมายเหตุ: คำตอบนี้จะเปลี่ยน SHA1s ดังนั้นโปรดระมัดระวังในการใช้กับสาขาที่ถูกผลักไปแล้ว หากคุณต้องการแก้ไขการสะกดชื่อหรืออัปเดตอีเมลเก่าเท่านั้น git ช่วยให้คุณทำสิ่งนี้ได้โดยไม่ต้องเขียนประวัติการใช้งาน.mailmapใหม่ ดูคำตอบอื่น ๆ ของฉัน

ใช้ Interactive Rebase

คุณสามารถทำได้

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

จากนั้นทำเครื่องหมายการกระทำที่ไม่ดีทั้งหมดของคุณเป็น "แก้ไข" ในไฟล์ rebase หากคุณต้องการเปลี่ยนการส่งคำสั่งแรกคุณต้องเพิ่มมันเป็นบรรทัดแรกในไฟล์ rebase ด้วยตนเอง (ตามรูปแบบของบรรทัดอื่น ๆ ) จากนั้นเมื่อคอมไพล์ขอให้คุณแก้ไขการกระทำแต่ละทำ

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

นี้จะเปลี่ยนผู้เขียนชื่อที่ระบุไว้ แต่ committer จะถูกตั้งค่าให้กับผู้ใช้กำหนดค่าของคุณและ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 จะมีการรวมการกระทำตันในประวัติศาสตร์ของคุณ) สิ่งนี้มักจะนำไปสู่ประวัติศาสตร์ที่แตกต่างกันมาก (เนื่องจากการเปลี่ยนแปลงที่ซ้ำกันอาจเป็น "rebased out") และในกรณีที่เลวร้ายที่สุดมันอาจนำไปสู่การgit rebaseขอให้คุณแก้ไขข้อขัดแย้งการผสานที่ยากลำบาก การแก้ปัญหาคือการใช้การ-pตั้งค่าสถานะgit rebaseซึ่งจะรักษาโครงสร้างการผสานของประวัติของคุณ manpage สำหรับgit rebaseเตือนว่าการใช้-pและ-iสามารถนำไปสู่ปัญหา แต่ในBUGS ส่วนจะกล่าวว่า "การแก้ไขการกระทำและการเขียนข้อความยืนยันการกระทำของพวกเขาควรจะทำงานได้ดี"

ฉันได้เพิ่ม-pคำสั่งข้างต้น สำหรับกรณีที่คุณเพิ่งเปลี่ยนการกระทำล่าสุดนี่ไม่ใช่ปัญหา


27
ยอดเยี่ยมสำหรับการกระทำที่แปลก - มีประโยชน์หากคุณกำลังจับคู่และลืมเปลี่ยนผู้เขียน
mloughran

32
+1 สำหรับการกล่าวถึง usecase สำหรับการแก้ไขข้อผิดพลาดทั่วไป: git commit - แก้ไข
Nathan Kidd

12
นี่คือที่สมบูรณ์แบบ usecase ที่พบบ่อยที่สุดของฉันคือฉันนั่งที่คอมพิวเตอร์เครื่องอื่นและลืมที่จะตั้งค่าผู้เขียนและมักจะมี <5 คอมมิทหรือมากกว่านั้นเพื่อแก้ไข
Zitrax

57
git commit --amend --reset-authorยังทำงานเพียงครั้งเดียวuser.nameและuser.emailกำหนดค่าอย่างถูกต้อง
pts

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 จะเปลี่ยนการกระทำทั้งหมด วิธีนี้ช่วยให้เงื่อนไข
user208769

5
"A previous backup already exists in refs/original/ Force overwriting the backup with -f"ขออภัยที่-f-flag จะเป็นตอนที่รันสคริปต์นี้สองครั้ง จริงๆแล้วนั่นคือคำตอบของไบรอันขออภัยเกี่ยวกับความวุ่นวายหลังจากที่ตัวกรองสาขาเป็นทางออก
hhh

2
@ user208769 env-filter ยังอนุญาตให้มีเงื่อนไข ดูคำตอบของฉัน :-)
stigkj

559

สายการบินหนึ่ง แต่ต้องระวังถ้าคุณมีที่เก็บหลายผู้ใช้ - สิ่งนี้จะเปลี่ยนความมุ่งมั่นทั้งหมดที่จะมีผู้เขียน (ใหม่) และผู้เดินทางเดียวกัน

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

ด้วย linebreaks ในสตริง (ซึ่งเป็นไปได้ในการทุบตี):

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 = 'หัวอีเมลใหม่'
อเล็กซ์ Geek

4
เหตุใดมันจึงเขียนใหม่ทั้งหมดคอมมิทถ้าคุณระบุHEADในตอนท้ายของคำสั่ง?
Nick Volynkin

1
มันใช้ไม่ได้กับพื้นที่เก็บข้อมูล bitbucket ของฉัน ฉันทำgit push --force --tags origin 'refs/heads/*'ตามคำสั่งที่แนะนำ
Olorin

1
คำสั่ง push สำหรับสิ่งนี้คือ:$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บันทึก a $$ ของฉันทันทีที่ต้องอัปเดตอีเมล
ecbrodie

187

สำหรับการกระทำเดียว:

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

(สกัดจากคำตอบของผู้ทดสอบ)


14
แต่นั่นก็ต่อเมื่อมันเป็นความมุ่งมั่นครั้งล่าสุด
Richard

4
ตามที่git help commit, git commit --amendการเปลี่ยนแปลงที่กระทำที่“เคล็ดลับของสาขาปัจจุบัน” (ซึ่งเป็น HEAD) นี้เป็นปกติล่าสุดกระทำ แต่คุณสามารถทำให้มันกระทำคุณต้องการเป็นครั้งแรกโดยการตรวจสอบออกมาว่ากระทำด้วยหรือgit checkout <branch-name> git checkout <commit-SHA>
Rory O'Kane

12
แต่ถ้าคุณทำเช่นนั้นความมุ่งมั่นทั้งหมดที่มีความมุ่งมั่นนั้นในฐานะผู้ปกครองจะชี้ไปที่การกระทำผิด ควรใช้สาขาตัวกรอง ณ จุดนั้นดีกว่า
John Gietzen

3
@JohnGietzen: คุณสามารถรีบูตคอมมิชชันกลับไปสู่สิ่งที่เปลี่ยนแปลงเพื่อแก้ไข อย่างไรก็ตามถ้าคุณทำ> 1 กระทำตามที่กล่าวไว้ตัวกรองสาขาอาจจะง่ายกว่ามาก
Thanatos

5
โปรดทราบว่าการเปลี่ยนแปลงนี้กระทำเฉพาะauthorและไม่ใช่committer
Nick Volynkin

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
ยอดเยี่ยมแน่นอน คุณสามารถย่อให้สั้นลงได้โดยการตั้งค่าชื่อผู้ใช้และชื่อผู้ใช้ในการกำหนดค่าท้องถิ่นของ repo จากนั้นแต่ละบรรทัดจะมีเพียงเท่านั้น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
แพทริคSchlüter

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>(ต้องรักการเริ่มต้นของคอมไพล์)
Alan Plum

1
ฉันไม่สามารถผลักดันหลังจากนี้ ฉันต้องใช้ "-f" หรือไม่?
Fish Monitor

9
git push -fฉันไม่ นอกจากนี้ repos ท้องถิ่นจะต้อง recloned หลังจากนี้
Fish Monitor

หากคุณต้องการเรียกใช้เชลล์สคริปต์ในสาขาเฉพาะคุณสามารถเปลี่ยนบรรทัดสุดท้ายเป็น: "'master .. your-branch-name" (สมมติว่าคุณแยกสาขาของมาสเตอร์)
Robert Kajic

คลิกที่ลิงค์ <ทางออกที่ดี> ตามที่สคริปต์ได้รับการอัปเดต
gxpr

82

ดังที่ docgnome กล่าวไว้ว่าการเขียนประวัติใหม่นั้นเป็นอันตรายและจะทำลายที่เก็บของคนอื่น

แต่ถ้าคุณต้องการทำอย่างนั้นจริงๆและคุณอยู่ในสภาพแวดล้อมทุบตี (ไม่มีปัญหาใน 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คือตัวเลือก "ทำให้ใช้งานได้"
Roman Starkov

@romkyns มีความคิดเกี่ยวกับวิธีการเปลี่ยนแท็กด้วยหรือไม่
Nick Volynkin

@NickVolynkin --tag-name-filter catใช่คุณระบุ สิ่งนี้ควรเป็นพฤติกรรมเริ่มต้น
Roman Starkov

48

เมื่อรับช่วงความมุ่งมั่นที่ไม่ได้จมจากผู้เขียนคนอื่นมีวิธีง่ายๆในการจัดการสิ่งนี้

git commit --amend --reset-author


1
สำหรับการกระทำครั้งเดียวและหากคุณต้องการใส่ชื่อผู้ใช้นี่เป็นวิธีที่ง่ายที่สุด
Pedro Benevides

7
คุณสามารถเพิ่ม--no-editเพื่อทำให้สิ่งนี้ง่ายยิ่งขึ้นโดยทั่วไปคนส่วนใหญ่จะต้องการอัปเดตที่อยู่อีเมลเท่านั้นไม่ใช่ข้อความยืนยัน
PlagueHammer

พวกคุณช่วยแบ่งปันคำสั่ง git เพื่ออัพเดทอีเมล / ชื่อผู้ใช้ล่าสุดของคอมมิชชันใหม่ได้หรือไม่
adi

คุณลองนี่ไหม นั่นควรเป็นผลข้างเคียงของสิ่งนี้หากไม่ใช่stackoverflow.com/a/2717477/654245ดูเหมือนว่าเส้นทางที่ดี
Ryanmt

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

หลังจากคำสั่งนี้ & ซิงค์กับมาสเตอร์การคอมมิททั้งหมดในประวัติถูกทำซ้ำ! แม้แต่ผู้ใช้อื่น ๆ :(
วลาดิมีร์

@ วลาดิเมียร์ที่คาดว่าจะโปรดศึกษาเกี่ยวกับการเปลี่ยนแปลงประวัติศาสตร์ใน git
brauliobo

39

นี่เป็นเวอร์ชั่นของ @ Brian ที่ให้รายละเอียดเพิ่มเติม:

ในการเปลี่ยนผู้แต่งและผู้ติดต่อคุณสามารถทำได้ (ด้วยการแบ่งบรรทัดในสตริงที่เป็นไปได้ในการทุบตี):

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 ที่เริ่มต้นด้วยrefs / ต้นฉบับอยู่แล้ว
    (ซึ่งหมายความว่ามีการรันสาขาตัวกรองอื่นก่อนหน้านี้ในที่เก็บและการอ้างอิงสาขาเดิมนั้นได้รับการสำรองไว้ที่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แทนซึ่งหมายถึงการกรองการแก้ไขทั้งหมดในเพียงสาขาในปัจจุบัน แล้วไม่มีแท็ก (หรือการอ้างอิงอื่น ๆ ) ในสาขาที่เขียนใหม่


รุ่งโรจน์สำหรับการจัดหาขั้นตอนที่มีการเปลี่ยนแปลงกระทำในทุก refs / สาขา
Johnny Utahh

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

จากนั้นคุณยังสามารถแก้ไขบางบรรทัดเพื่อดูตำแหน่งที่คุณต้องการเปลี่ยนผู้แต่ง สิ่งนี้จะให้พื้นกลางที่ดีระหว่างระบบอัตโนมัติและการควบคุม: คุณเห็นขั้นตอนที่จะทำงานและเมื่อคุณบันทึกทุกอย่างจะถูกนำไปใช้ในครั้งเดียว


! น่ากลัว ขอบคุณ!
Pablo Lalloni

ฉันใช้ HEAD ~ 8 และมันแสดงให้เห็นมากกว่า 8 คอมมิทล่าสุด
ไบรอันไบรซ์

1
@BryanBryce หากมีกระทำการผสานที่เกี่ยวข้องกับสิ่งที่ได้รับความซับซ้อน :)
คริส Maes

@ChrisMaes อ่าฉันเห็นว่าเกิดอะไรขึ้น ฉันไม่ต้องการยุ่งกับสิ่งเหล่านี้เพียงแค่อยู่ในสาขาที่ฉันอยู่
ไบรอันไบรซ์

ในกรณีนี้หากคุณแยกจากอาจารย์คุณสามารถ:git rebase -i master -x ...
Chris Maes

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 ไปยังคอมไพล์

ตัวอย่างเช่น 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

ขอบคุณฉันสงสัยว่าทำไมนี่ไม่ใช่ฟังก์ชั่น core git (หรือ git-svn) สามารถทำได้ด้วยธงสำหรับ git svn clone แต่ไม่อยู่ใน git filter-branch ...
Daniel Hershcovich

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
คำตอบที่ดีมาก ฉันชอบที่การเปลี่ยนแปลงจะถูกห่อหุ้มจากการอัปเดตเป็นอย่างมากแม้กระทั่งการทำความสะอาดคอมไพล์
Aleks

12

วิธีที่เร็วและง่ายที่สุดในการทำเช่นนี้คือการใช้อาร์กิวเมนต์ --exec ของการรีบูท git:

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บวกสคริปต์กรอง (ตามที่อธิบายไว้ในบทความที่อ้างอิงในคำตอบ docgnome ) หรือโต้ตอบrebase แต่อย่างใดอย่างหนึ่งเหล่านั้นจะเปลี่ยนการแก้ไขจากการเปลี่ยนแปลงครั้งแรกกระทำเป็นต้นไป; นี่หมายถึงปัญหาสำหรับใครก็ตามที่ใช้การเปลี่ยนแปลงของเขา / เธอในสาขาของคุณเขียนใหม่ล่วงหน้า

RECOVERY

หากผู้พัฒนารายอื่นไม่ได้อ้างอิงงานของพวกเขากับเวอร์ชันที่เขียนซ้ำล่วงหน้าโซลูชันที่ง่ายที่สุดคือการโคลนซ้ำ (โคลนอีกครั้ง)

หรือพวกเขาสามารถลอง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}รัฐจะ pre-เขียน (ก่อนที่จะดึงข้อมูล) ดูgitrevisions


โซลูชันทางเลือกคือใช้refs / replace /กลไกที่มีอยู่ใน Git ตั้งแต่รุ่น 1.6.5 ในโซลูชันนี้คุณให้การแทนที่สำหรับการยืนยันที่มีอีเมลผิด แล้วใครที่เรียก 'แทนที่' refs (บางอย่างเช่นfetch = +refs/replace/*:refs/replace/*refspec ในสถานที่ที่เหมาะสมในของพวกเขา .git/config ) จะได้รับการเปลี่ยนโปร่งใสและผู้ที่ไม่สามารถดึงข้อมูล refs เหล่านั้นจะดูเก่ากระทำ

ขั้นตอนจะเป็นดังนี้:

  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 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' ซึ่งไม่สามารถผลักไปยัง 'ต้นแบบ' ของสาขาระยะไกลเนื่องจากผู้ใช้ไม่ถูกต้อง

  1. ชำระเงิน 'ต้นแบบ' ของรีโมตสาขา
  2. เลือกโครงการ / โฟลเดอร์ / ไฟล์ที่ 'local_master_user_x' มีการเปลี่ยนแปลง
  3. คลิกขวา - แทนที่ด้วย - สาขา - 'local_master_user_x'
  4. ยอมรับการเปลี่ยนแปลงเหล่านี้อีกครั้งคราวนี้ในฐานะผู้ใช้ที่ถูกต้องและเข้าสู่ 'ต้นแบบ' ของสาขาในประเทศ
  5. กดไปที่ 'ต้นแบบ' ระยะไกล

5

การใช้การรีบูตแบบโต้ตอบคุณสามารถวางคำสั่งแก้ไขหลังจากการคอมมิทแต่ละครั้งที่คุณต้องการแก้ไข ตัวอย่างเช่น

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

3
ปัญหาของเรื่องนี้ก็คือการแก้ไขข้อมูลเมตาอื่น ๆ (เช่นวันที่และเวลา) ก็จะได้รับการแก้ไข ;-)ฉันเพิ่งพบว่าวิธีที่ยาก
halfer

5

โปรดทราบว่าร้านค้าคอมไพล์สองที่อยู่อีเมลที่แตกต่างกันหนึ่งสำหรับcommitter (คนที่มุ่งมั่นในการเปลี่ยนแปลง) และอีกคนหนึ่งสำหรับผู้เขียน (คนที่เขียนการเปลี่ยนแปลง)

ข้อมูลผู้ส่งไม่แสดงในสถานที่ส่วนใหญ่ แต่คุณสามารถดูได้ด้วย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: เปลี่ยนชื่อผู้ใช้ของคุณเป็นคอมไพล์สำหรับการกระทำในอนาคตตามคำแนะนำที่นี่: https://help.github.com/articles/setting-your-username-in-git/

ขั้นตอนที่ 2: เรียกใช้สคริปต์ทุบตีต่อไปนี้:

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

ภาพรวมอย่างรวดเร็ว: ชำระเงินที่เก็บของคุณไปที่ไฟล์ temp ชำระเงินที่สาขารีโมตทั้งหมดรันสคริปต์ที่จะเขียนประวัติใหม่บังคับให้ออกจากสถานะใหม่

เรามีปัญหาในการใช้งานบน OS X เพราะมันทำให้เกิดความสับสนในการส่งข้อความดังนั้นเราจึงต้องเรียกใช้มันซ้ำอีกครั้งบนเครื่อง Linux หลังจากนั้น


5

ปัญหาของคุณเป็นเรื่องธรรมดาจริงๆ ดู " การใช้ Mailmap เพื่อแก้ไขรายการผู้แต่งใน 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>
    
  • แสดงผู้ใช้ที่มีอยู่ใน repo

    $ git changemail --show-both
    

อย่างไรก็ตามหลังจากทำการเปลี่ยนแปลงแล้วให้ล้างข้อมูลสำรองจากตัวกรองสาขาด้วย: git-backup-clean


1
เมื่อฉันเรียกใช้คำสั่งของคุณมันบอกว่า "ร้ายแรง: ไม่สามารถ exec 'git-changemail': การอนุญาตถูกปฏิเสธ"
Govind


3

ฉันต้องการเพิ่มตัวอย่างของฉันด้วย ฉันต้องการสร้าง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:-"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

หากคุณเป็นผู้ใช้รายเดียวของ repo นี้หรือคุณไม่สนใจว่าจะทำลาย repo สำหรับผู้ใช้รายอื่นใช่แล้ว หากคุณผลักภาระเหล่านี้และพวกเขาอยู่ที่ไหนที่อื่นสามารถเข้าถึงพวกเขาแล้วไม่ยกเว้นว่าคุณไม่สนใจที่จะทำลาย repos ของคนอื่น ปัญหาคือการเปลี่ยนการกระทำเหล่านี้คุณจะสร้าง SHA ใหม่ซึ่งจะทำให้พวกเขาได้รับการปฏิบัติเหมือนการกระทำที่แตกต่างกัน เมื่อใครบางคนพยายามที่จะดึงในการกระทำเหล่านี้มีการเปลี่ยนแปลงประวัติแตกต่างและ kaboom

หน้านี้http://inputvalidation.blogspot.com/2008/08/how-to-change-git-commit-author.htmlอธิบายถึงวิธีการทำ (ฉันไม่ได้ลอง YMMV เลย)


ดังนั้นจึงไม่มีวิธีที่ปลอดภัยในการเขียน user.email โดยไม่ต้องระเบิดใคร ๆ ฉันรู้ว่าประวัติการเขียนใหม่เป็นความคิดที่ไม่ดีฉันแค่คิดว่าอาจมีวิธีที่สะอาดในการทำอย่างปลอดภัย ขอบคุณ
manumoomoo

@mediaslave: ลองใช้refs/replace/กลไก
Jakub Narębski

meta.stackexchange.com/a/8259/184684 - aka ลิงก์ผลรวมเพื่อทำให้เป็นคำตอบ
ruffin
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.