Git에서 여러 커밋의 작성자와 커미터 이름 및 전자 메일을 변경하는 방법은 무엇입니까?


2391

나는 학교 컴퓨터에서 간단한 스크립트를 작성하고 Git (내 펜 드라이브에있는 저장소에서 집의 컴퓨터에서 복제 된 저장소)에 변경 사항을 적용했습니다. 몇 번의 커밋 후에 나는 루트 사용자로 물건을 커밋하고 있음을 깨달았습니다.

이 커밋의 저자를 내 이름으로 바꿀 수있는 방법이 있습니까?


13
질문 : git filter-branch를 사용하면 이전 태그, 버전 및 객체에 대한 SHA1이 유지됩니까? 아니면 작성자 이름을 변경하면 관련 SHA1도 변경됩니까?
AndyL

36
해시가 변경됩니다
사용할 수 없음

3
접선으로, 나는 근본적으로 근본 원인을 해결하는 작은 스크립트를 만들었습니다. gist.github.com/tripleee/16767aa4137706fd896c
3

2
@impinball 질문의 나이는 거의 관련이 없습니다. 새로운 중복 질문을 만드는 것은 문제가 아닙니다. 나는이 특정 대답을 구걸하는 질문을 만들 수 있다고 생각하지만 그 모든 가시성을 얻을 것이라고 확신하지는 않습니다. 여기에 Git 질문이 부족한 것 같지 않습니다 ... 어쨌든 도와 드리겠습니다.
tripleee

8
GitHub는이를위한 특별한 스크립트를 가지고 있습니다 : help.github.com/articles/changing-author-info
Timur Bernikovich

답변:


1210

이 답변에 사용 git-filter-branch하는, 워드 프로세서는 지금이 경고를 :

git filter-branch는 의도 한 히스토리 재 작성의 명백한 맹 글링을 생성 할 수있는 많은 함정을 가지고 있습니다. 이러한 안전 및 성능 문제는 이전 버전과 호환되지 않으므로 사용하지 않는 것이 좋습니다. git filter-repo 와 같은 대체 히스토리 필터링 도구를 사용하십시오 . 여전히 git filter-branch를 사용해야하는 경우 SAFETY (및 PERFORMANCE )를 주의 깊게 읽고 filter-branch의 지뢰에 대해 배우고 거기에 열거 된 많은 위험을 합리적으로 피하십시오.

저자 (또는 커미터)를 변경하면 모든 히스토리를 다시 작성해야합니다. 괜찮다면 가치가 있다고 생각되면 git filter-branch을 확인하십시오 . 매뉴얼 페이지에는 시작하기위한 몇 가지 예가 포함되어 있습니다. 또한 환경 변수를 사용하여 작성자, 커미터, 날짜 등의 이름을 변경할 수 있습니다 . git man page 의 "Environment Variables"섹션을 참조하십시오 .

특히이 명령을 사용하여 모든 브랜치 및 태그에 대해 잘못된 작성자 이름과 이메일 을 모두 수정할 수 있습니다 (출처 : 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

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 2016 년

6
@RafaelBarros 저자 정보 (역사에있는 다른 것들과 마찬가지로)는 커밋의 sha 키의 일부입니다. 히스토리가 변경되면 모든 커밋에 대한 새 ID로 이어지는 재 작성입니다. 공유 리포지토리에 다시 쓰거나 모든 사용자가이를 알고 있는지 확인하지 마십시오.
johannes

20
사용하여 해결git push --force --tags origin HEAD:master
mcont

1577

참고 :이 답변은 SHA1을 변경하므로 이미 푸시 된 지점에서 사용하십시오. 이름의 철자를 수정하거나 오래된 전자 메일을 업데이트하려는 경우 git을 사용하여 기록을 다시 쓰지 않고도이 작업을 수행 할 수 있습니다 .mailmap. 내 다른 답변을 참조하십시오 .

대화식 Rebase 사용

넌 할 수있어

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

그런 다음 rebase 파일에서 모든 잘못된 커밋을 "편집"으로 표시하십시오. 첫 번째 커밋도 변경하려면 rebase 파일에서 첫 번째 커밋을 수동으로 추가해야합니다 (다른 줄의 형식에 따름). 그런 다음 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위의 명령에 추가 했습니다. 가장 최근의 커밋을 변경하는 경우에는 문제가되지 않습니다.


27
홀수에 대한 중대한는하지만 커밋 - 유용한 당신이 경우에있는 거 페어링 및 저자 변경하는 것을 잊지
mloughran

32
git commit --amend --author = username
Nathan Kidd

12
이것은 완벽합니다. 가장 일반적인 유스 케이스는 다른 컴퓨터에 앉아서 작성자를 설정하는 것을 잊어 버려 일반적으로 <5 커밋 또는 수정해야한다는 것입니다.
Zitrax

57
git commit --amend --reset-author또한 한 번 작동 user.name하고 user.email올바르게 구성되었습니다.
pts

14
run , save, quit <commit>사용 user.nameuser.emailfrom 후 모든 커밋에 대한 작성자 정보를 다시 작성하십시오 . 편집 할 필요가 없습니다! ~/.gitconfiggit 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-filter를 사용하는 것이 더 쉬운 해결책이 아닙니까? 그렇다면 왜 이것이 더 많은 표를 얻고 있는지 확실하지 않습니다.
stigkj

3
그런 다음 링크가 끊어졌습니다. 이러한 변경 사항을 다른 저장소에 어떻게 적용합니까?
Russell

28
env-filter는 모든 커밋을 변경합니다. 이 솔루션은 조건부를 허용합니다.
user208769

5
"A previous backup already exists in refs/original/ Force overwriting the backup with -f"죄송하지만 -f이 스크립트를 두 번 실행할 때 -flag가있을 위치 입니다. 실제로 그것은 브라이언의 대답에 있습니다. 필터 브랜치가 해결책이 된 직후의 방해에 대해 죄송합니다.
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.
Alec the Geek

4
HEAD명령 끝에 지정하면 왜 모든 커밋을 다시 작성 합니까?
Nick Volynkin 2016 년

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

자식 버전 1.7.5.4로 테스트


9
마지막 커밋에서 실제로 잘 작동합니다. 좋고 간단합니다. 하지 않습니다 사용하는 글로벌 변화로 --local너무 작품

이것은 저에게 큰 승자였습니다! 이 git commit --amend --reset-author --no-edit명령은 잘못된 작성자 정보로 커밋을 만든 다음을 통해 정확한 작성자를 설정하는 경우 특히 유용합니다 git config. 이메일을 업데이트해야 할 때 바로 $$를 저장했습니다.
ecbrodie 2019

187

단일 커밋의 경우 :

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

(asmeurer의 답변에서 추출)


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 커밋을 수행하는 경우 언급했듯이 filter-branch가 훨씬 쉬울 것입니다.
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의 로컬 구성에서 user.name 및 user.email을 설정하여 단축 할 수 있습니까 exec git commit --amend --reset-author -C HEAD?
앤드류

1
필터 브랜치를 사용하는 정식 답변은 refs / heads / master를 삭제했습니다. 제어 가능하고 편집 가능한 솔루션에 +1하십시오. 감사!
jmtd 2016 년

Someone else's commit대신에 시작 my bad commit 1합니까? 방금 HEAD^^마지막 2 개의 커밋을 수정 하려고 시도했지만 완벽하게 작동했습니다.
fredoverflow 12

3
대신 git rebase -i HEAD^^^^^^당신도 쓸 수 있습니다git rebase -i HEAD~6
Patrick Schlüter

1
커밋 타임 스탬프가 변경됩니다. 올바른 타임 스탬프로
되돌리려

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수정 된 버전을 -ed, 여기에 내가 포함 된 선없이 오전 unknown <stupid-windows-user@.StupidWindowsDomain.local>(사랑 자식의 디폴트에에 도착).
Alan Plum

1
이 후에는 밀 수 없습니다. "-f"를 사용해야합니까?
물고기 모니터

9
나는했다 git push -f. 또한이 후 로컬 리포지토리를 다시 복제해야합니다.
물고기 모니터

특정 분기에서 셸 스크립트를 실행해야하는 경우 마지막 줄을 " 'master..your-branch-name"(마스터 분기로 가정)으로 변경할 수 있습니다.
Robert Kajic

스크립트가 업데이트되면 <nice solution> 링크를 클릭하십시오
gxpr

82

교리가 언급했듯이, 역사를 다시 쓰는 것은 위험하며 다른 사람들의 저장소를 깨뜨릴 것입니다.

그러나 정말로 그렇게하고 싶고 bash 환경에 있다면 (Linux의 경우 Windows에서는 문제가 없지만 git 설치와 함께 제공되는 git bash를 사용할 수 있음) 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 2016 년

@NickVolynkin 예, 지정 --tag-name-filter cat합니다. 이것은 실제로 기본 행동이었습니다.
로마 스타 코프

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

이 명령 및 마스터와 동기화 후 기록의 모든 커밋이 복제됩니다! 다른 사용자의 경우에도 :(
Vladimir

예상되는 @Vladimir, git
brauliobo의

39

이것은 @Brian 버전의보다 정교한 버전입니다.

작성자와 커미터를 변경하려면 bash에서 가능한 문자열에 줄 바꿈을 사용 하여이 작업을 수행 할 수 있습니다.

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

다음 오류 중 하나가 나타날 수 있습니다.

  1. 임시 디렉토리가 이미 존재합니다
  2. 참조 / 원본으로 시작하는 참조는 이미 존재합니다
    (이것은 다른 필터 브랜치가 저장소에서 이전에 실행되었고 원래 브랜치 참조가 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대신 사용하는 것입니다. 즉, 현재 분기 에서만 모든 개정을 필터링합니다 . 그리고 다시 작성된 브랜치에는 태그 (또는 다른 참조)가 없습니다.


모든 심판 / 지점 에 대한 커밋을 변경하는 절차를 제공하기위한 전문가.
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 병합 커밋이 관련된 경우 상황이 복잡해집니다 :)
Chris 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

그런 다음 filter-branchMAN 페이지에 설명 된대로 백업 된 모든 원본 참조를 제거하십시오 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 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

가장 빠르고 쉬운 방법은 git rebase의 --exec 인수를 사용하는 것입니다.

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 . 그러나 그 중 하나는 처음 변경된 커밋부터 개정을 변경합니다. 이는 브랜치 사전 다시 쓰기에 대한 변경 내용을 기반으로하는 모든 사람에게 문제가 있음을 의미합니다.

회복

다른 개발자가 사전 재 작성 버전을 기반으로하지 않은 경우 가장 간단한 해결책은 다시 복제하는 것입니다.

또는 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를 참조하십시오 .


대체 솔루션은 버전 1.6.5부터 Git에서 사용 가능한 참조 / 바꾸기 / 메커니즘 을 사용하는 것 입니다. 이 솔루션에서는 잘못된 이메일을 가진 커밋을 대체 할 수 있습니다. 다음 가져 오는 사람이 심판 (같은 '대신' 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 resetgit 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

EGit과 함께 Eclipse를 사용하는 경우 매우 쉬운 해결책이 있습니다.
가정 : 유효하지 않은 사용자로 인해 로컬 분기 'local_master_user_x'에 원격 분기 'master'로 푸시 할 수없는 커밋이 있습니다.

  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
이것의 문제점은 다른 커밋 메타 데이터 (예 : 날짜 및 시간)도 수정된다는 것입니다. 난 그냥 어려운 길을 발견했습니다 ;-).
1/27

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

당신의 문제는 정말 일반적입니다. "를 참조 수정 저자 힘내에서 목록에 Mailmap 사용 "

간단하게하기 위해 프로세스를 용이하게하는 스크립트를 만들었습니다 : 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_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

이 리포지토리의 유일한 사용자이거나 다른 사용자에 대한 리포지토리를 무너 뜨릴 염려가 없다면, 그렇습니다. 이 커밋을 푸시하고 다른 사람이 액세스 할 수있는 곳에 존재한다면 다른 사람들의 저장소를 깨는 것에 신경 쓰지 않는 한 그렇지 않습니다. 문제는 이러한 커밋을 변경하여 새 SHA를 생성하여 다른 커밋으로 취급하게하는 것입니다. 누군가가 변경된 커밋을 가져 오려고하면 역사가 다릅니다.

이 페이지는 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- 일명 링크하여 답변으로 만듭니다.
ruffin
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.