2014-12-29 3 views
3

잘못된 메일 주소를 가진 소스 트리를 사용하여 여러 번의 커밋 (푸시되지 않았습니다.)을 수행했습니다.각 커밋에서 메일 주소를 변경하십시오.

이 오류를 수정하려면 조사를 수행하고이 스크립트를 사용하여 올바른 메일로 커밋을 편집하십시오. 제가 처음에 git에서 프로젝트를 가져 왔을 때 이미 여러 사용자로부터 200 건이 넘는 커밋이있었습니다. 내가 스크립트를 사용하는 경우

는 제대로 내 메일 주소를 복귀하지만, 다른 사람은 파괴되었다 :

ex : [email protected] became [email protected] 

당신은 내가이 문제를 관리 할 수있는 방법 어떤 생각을 가지고 있습니까?

#!/bin/sh 

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

OLD_EMAIL="[email protected]" 
CORRECT_NAME="a.bbbb" 
CORRECT_EMAIL="[email protected]" 

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

EDIT1 :

내가 다른 메일에 스크립트를 사용하고는 예전과 같이

이 모든 것을 해결 adresses하지만 sourcetree 나에게 그 주인을 알 수 248up/248down입니다 :

enter image description here

어떻게이 상태를 탈 수 있습니까?

는 EDIT2 :

으로 내가 여전히 sourcetree 2 배의 역사를 가지고 내가가의 repo (248up/248down 사라)

만의 상태를 수정

git branch -f master origin/master 

을 사용 제안 , 보라색으로 우리는 원격 저장소에서 마지막 커밋을 볼 수있다. (내가 수정 한 메일이 잘못되어있다.) 파란색 부분부터 올바른 내역이 내 로컬 커밋과 함께있다. 괴롭히는) : 당신은 단지 할 수있는 몇 가지 커밋을 가지고 있기 때문에

enter image description here

+0

위의 스크립트는 모든 커밋의 작성자 정보를 변경 했습니까? 'filter-branch'가 개정 선택자로 작동하는 참조를 제한 할 수 있습니다. 아마도 그렇게해야할까요? –

+0

@Schwern 네,이 게시물에서이 스크립트를 발견했지만 알 수 있듯이 문제가 발생했습니다. 내 질문은 내가 지금부터 할 수있는 것에 관한 것입니다 (이제는 내 이메일 주소 만 좋을 것입니다). –

+0

@EtanReisner 네, 그랬습니다. 이유는 모르겠습니다. 나는 sbash에별로 좋지 않다. ^^ –

답변

1

, 오히려 전체 역사보다, 나는 git rebase -i -pgit commit --amend --author "a.jard <[email protected]>"를 사용하여 손으로 그것을 할 것입니다.

It's covered in this answer 허용되는 대답은 아니지만 투표가 두 번 있습니다.

왜 당신은 당신이 스크립트에있는 결과를 얻었 는가에 관해서는, git의 본질과 rebase가 어떻게 작동하는지 때문입니다. 리베이스는 히스토리를 다시 쓰지 않습니다. 자식에 대한 커밋은 변경 불가능합니다. 커밋의 ID는 날짜, 로그 메시지, 작성자 및 커미터와 같은 메타 데이터를 포함하여 커밋 자체의 콘텐츠에 연결됩니다. rebase 는 새로운 기록을 남깁니다.

퍼즐의 또 다른 핵심은 부모의 ID를 사용하여 커밋 ID를 계산하는 것입니다. 자녀를 변경하지 않고는 부모를 변경할 수 없습니다. 이것은 git을 매우 효율적으로 만듭니다. ABC123을 저질렀다고 말하면, ABC123을 저 지르면 우리는 같은 역사를 가지고 있다는 것을 알 수 있습니다.

예를 들어, 이렇게 5 개의 커밋으로 구성된 간단한 저장소가 있다고 가정 해 봅시다. 마스터와 원점/마스터 모두 E.를 가리킨다.

A - B - C - D - E [master] [origin/master] 

B의 이메일 주소가 잘못되었습니다. A, C, D, E 모두 괜찮습니다. filter-branch 명령을 실행합니다. 그것은 A를 볼 것이고, 변화가없는 것을 보게 될 것이고, 그것을 내버려 둘 것입니다. B를보고, 커미터를 변경하고, A를 부모로하여 새로운 커밋을 작성합니다. B1이라고 부르 자.

A - B - C - D - E [master] [origin/master] 
\ 
    B1 

이제 C를 살펴 보겠습니다. 변경할 것은 없지만 B1에 부모가 필요합니다. ID는 상위 ID를 포함하기 때문에 새 확약을 작성해야합니다. E1에

A - B - C - D - E [master] [origin/master] 
\ 
    B1 - C1 

그리고 D와 똑같은 및 E.

A - B - C - D - E [master] [origin/master] 
\ 
    B1 - C1 - D1 - E1 

완료 필터 분기 이동 [마스터].

A - B - C - D - E [origin/master] 
\ 
    B1 - C1 - D1 - E1 [master] 

그래서 과거에 한 커밋을 변경하면 그 이후의 모든 항목이 분기됩니다.

이 스크립트의 작성자는 git-filter-branch가 필터링해야하는 버전을 제한하지 않도록 지시했기 때문에 현재 분기의 전체 기록을 작성했습니다.

다행히 마스터를 원본/마스터로 다시 이동하여 실행을 취소 할 수 있습니다. 이를 수행 할 수있는 몇 가지 방법이 있습니다. git branch -f master origin/master은 가장 간단합니다.

업데이트 여기에는 개발 분기가 필터링 된 분기에 걸려있는 새 문제가 포함됩니다. 처음부터 시작합시다. 당신은 이런 상황이었습니다 ...

당신은 git author-rewrite으로 달렸고 이것으로 감았습니다.

A - B - C - D - E [origin/master] 
\ 
    B1 - C1 - D1 - E1 [master] 

마스터를 분기하여 새로운 커밋을 시작했습니다.

A - B - C - D - E [origin/master] 
\ 
    B1 - C1 - D1 - E1 [master] - F - G - H [devel] 

git branch -f master origin/master을 실행하여 필터를 실행 취소했습니다. git의 브랜치는 커밋을 가리키는 레이블 일 뿐이므로 마스터 레이블 만 이동되었습니다. devel 브랜치는 여전히 필터링 된 커밋에 매달려 있습니다.

A - B - C - D - E [origin/master] [master] 
\ 
    B1 - C1 - D1 - E1 - F - G - H [devel] 

이제 devel과 F, ​​G 및 H를 마스터에서 중단시켜야합니다. 비즈니스의 첫 번째 순서는 devel을 마스터로 전환하는 것입니다. 우리가 그렇게하면 F, G, H를 다시 ​​찾기가 어려울 것입니다. ID를 적어 두거나 태그가있는 보험에 가입 할 수 있습니다. git tag tmp devel.

A - B - C - D - E [origin/master] [master] 
\ 
    B1 - C1 - D1 - E1 - F - G - H [devel] <tmp> 

이제 devel을 git branch -f devel master으로 마스터로 이동하십시오. tmp 태그는 필터링 된 분기를 액세스 가능하게 유지합니다.

A - B - C - D - E [origin/master] [master] [devel] 
\ 
    B1 - C1 - D1 - E1 - F - G - H <tmp> 

이제 git cherry-pick을 사용하여 개별적인 변경 사항을 복사 할 수 있습니다. 커밋의 내용은 변경되지 않지만 부모는 복사되므로 복사해야합니다.우리가 F를 포함 할 때문에

git checkout devel 
git cherry-pick F^..tmp 

는 단지 H 및 G.의, F..H는 H의 부모를 포함 말한다 F.에 우리는 H에서 모든 것을 할의 F^..tmp 부분을 설명하지만, F의 부모를 제외하려면 목록, 우리는 F^을 사용하여 F.의 부모를 제외합니다.

당신은 이것으로 바람을 피 웁니다.

A - B - C - D - E [origin/master] [master] - F1 - G1 - H1 [devel] 
\ 
    B1 - C1 - D1 - E1 - F - G - H <tmp> 

확인했으면 git tag -d tmp으로 tmp 태그를 삭제하십시오.

A - B - C - D - E [origin/master] [master] - F1 - G1 - H1 [devel] 

당신이 혼란 스러울 경우 커밋이 몇 주가 지나서 가비지 수집되기 때문에 걱정할 필요가 없습니다.

이제 devel을 확인하고 위에서 언급 한 리베이스 기술을 사용하여 커밋을 수정할 수 있습니다. 너는 이것으로 끝낼거야.

A - B - C - D - E [origin/master] [master] 
\ 
    B2 - C2 - D2 - E2 - F2 - G2 - H2 [devel] 

git branch -f master E2으로 수동으로 마스터를 E2로 이동하십시오.

A - B - C - D - E [origin/master] 
\ 
    B2 - C2 - D2 - E2 [master] - F2 - G2 - H2 [devel] 

당신은 여전히 ​​갈라 졌을 것입니다. 변경 사항을 강제로 적용해야하지만 강제로 변경해야합니다. 그 부분은 피할 수 없습니다. 푸시 된 후 변경 기록은 항상 지저분합니다.

이 모든 것을 수행하는 다른 많은 방법이 있습니다. git filter-branch을 사용하면 얻을 수있는 장점 중 하나는 길을 따라 모든 태그와 지점을 변경한다는 점입니다. 너와 같은 작은 변화와 새로운 사용자를 위해, 나는 작은 단계에서 그것을하는 것이 더 낫다. 진행 상황을 이해하는 것이 더 쉽습니다.

+0

이됩니다. 내 지역 저장소에 휴지통 기록의 일부가 없습니까? (설명은 분명합니다. 감사합니다) –

+0

@JulienM 예. 문제가되지 않습니다 .Git의 저장 용량은 매우 효율적입니다. 기저귀는 참조되지 않은 커밋을 느낄 때 가비지 수집합니다.이 것은 좋은 일입니다.'git reflog'를 사용하여 이전에 HEAD가 가리킨 커밋을보고 실수로 오래된 커밋을 복원 할 수 있습니다. – Schwern

+0

굉장한 답변 주셔서 감사합니다, 자식은 처음에는 너무 강력하지만 실제로 복잡합니다. 문제의 일부가 좋은 것임을 확인하기 위해 : 1- 나의 근원/마스터 아래의 역사는 훌륭한 메일을 가지고 있지 않다. devel은 2를 가지고있다. 나는 단지 서버로부터 프로젝트를 가져왔다. 아직 내 기능을 밀어 3 - 나는 또한 적어도 5 메일을 변경하려면, 그래서 스크립트를 실행 5 번;/ –

관련 문제