, 오히려 전체 역사보다, 나는 git rebase -i -p
및 git 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
을 사용하면 얻을 수있는 장점 중 하나는 길을 따라 모든 태그와 지점을 변경한다는 점입니다. 너와 같은 작은 변화와 새로운 사용자를 위해, 나는 작은 단계에서 그것을하는 것이 더 낫다. 진행 상황을 이해하는 것이 더 쉽습니다.
위의 스크립트는 모든 커밋의 작성자 정보를 변경 했습니까? 'filter-branch'가 개정 선택자로 작동하는 참조를 제한 할 수 있습니다. 아마도 그렇게해야할까요? –
@Schwern 네,이 게시물에서이 스크립트를 발견했지만 알 수 있듯이 문제가 발생했습니다. 내 질문은 내가 지금부터 할 수있는 것에 관한 것입니다 (이제는 내 이메일 주소 만 좋을 것입니다). –
@EtanReisner 네, 그랬습니다. 이유는 모르겠습니다. 나는 sbash에별로 좋지 않다. ^^ –