2017-02-22 10 views
3

이전 svn repo를 git로 가져 오려고합니다. 한 지점에서 폴더는 모든 지점에서 이름이 변경되었습니다. 이것은 svn에서 히스토리가있는 복제본을 작성한 다음 두 번째 확약시 원본을 삭제하여 수행되었습니다. 따라서 다음과 같은 저장소가 있습니다.분기에서 커밋을 스쿼시하는 방법

A -> B -> C -> D* -> E* -> F -> G -> H 
     \-> 1 -> 2* -> 3* - > 4 -/ 

여기서 D/E 및 2/3은 스쿼시하려는 커밋입니다. 스쿼시가 발생하는 이유는 svn이 "history with duplicate"를 알고있는 동안 자식은 다음 커밋까지 원본 파일이 제거되지 않았기 때문에 이름 바꾸기로 간주하지 않기 때문에이 시점에서 기록을 잃어 버리게됩니다.

일부 리베이스 스크립트를 사용하여 실험했지만 모든 브랜치를 병합했습니다. 위의 내용은 내가해야 할 일을 심각하게 단순화 한 버전입니다. 그래서 수동으로 할 수 없으므로 스크립트가 정말로 필요한 이유입니다. SVN 저장소의 역사를 통틀어 1,000 개가 넘는 지점이 있고이 변경이 완료된 지점 (거의 동시에)이 12 개의 병렬 지점이 있습니다.

git repo가 ​​아직 게시되지 않았으므로 유지 보수 해시가 적절하지 않습니다. 필자는 필터 - 브랜치 스크립트를 사용할 필요가 있다고 가정하지만, 필자가 여기서 도움을 얻을 수 있기를 기대하고있는 것을 관리하는 방법을 알아 내려고 노력 중이다. I 은 부숴 버릴 필요가있는 커밋과 그 부모의 sha1을 제공 할 수 있습니다.

+0

체크 아웃 4, 자식은 스쿼시 -i 1, 변경 2, 3 커밋을 리베이스, 그들은이 다음 내 나무의 나머지 부분을 리베이스해야 고아 4 ', 나에게 잎 1 – g19fanatic

+0

에 최대 스쿼시 것 에. 필자는 7 년의 역사와 거의 100,000 개의 커밋 및 모든 지점과 병합이이 시점 이후에 있으므로 수동으로 리베이스하고이 기록을 매우 복잡하게 만듭니다. – Paco103

답변

2

--parent-filter을 사용하여 D의 SHA를 C의 SHA로 바꾸려면 git filter-branch을 사용하고 싶습니다. .git/info/grafts 또는 git replace을 볼 수도 있는데, 이는 --parent-filter을 작성하는 것보다 간단 할 수도 있고 filter-branch으로 영구적으로 만들 수도 있습니다.

업데이트 : @ 토렉이 말했듯이, 당신은 확실히 git replace을 사용해야합니다. 실제 예제를 사용하려면 readme.md에서 README.md까지의 이름을 중간 이름 바꾸기 README1.md : https://github.com/dahlbyk/posh-git/compare/dahlbyk:2b9342c...dahlbyk:57394c5으로 실행했습니다. 이제 2b9342c 당신의 C57394c5을 부르 자 당신의 E :

$ git tag E 57394c5 
$ git tag C 2b9342c 
$ git tag G 450d8f1 
$ git log --oneline --graph --decorate C~..G 
* 450d8f1 (tag: G) Merge pull request #320 ... 
|\ 
| * 941935c Fix a few kbd/missing markdown issues/ 
| * f13dcf9 Upcase readme and have more prompt examples. 
| * 57394c5 (tag: E) Now rename to README.md. 
| * eb79ef2 Prepare to upcase README.md filename. 
* | 536c57f Merge pull request #319 ... 
|\ \ 
| |/ 
|/| 
| * 7fafb7b Speed up Get-GitStatus 
|/ 
* 2b9342c (tag: C) Merge pull request #313 ... 

가 중간 움직임은 결코 일어나지 않았다 척, 내가 할 수있는 자사의 조부모 (E~2 = C)와 replaceE의 부모 (E~) :

$ git log --stat --oneline C..E 
57394c5 Now rename to README.md. 
README1.md => README.md | 0 
1 file changed, 0 insertions(+), 0 deletions(-) 
eb79ef2 Prepare to upcase README.md filename. 
readme.md => README1.md | 0 
1 file changed, 0 insertions(+), 0 deletions(-) 
$ git replace E~ C 
$ git log --stat --oneline C..E 
57394c5 Now rename to README.md. 
readme.md => README.md | 0 
1 file changed, 0 insertions(+), 0 deletions(-) 
eb79ef2 Merge pull request ... 

마지막으로 filter-branch은 변경 사항을 영구 변경합니다.

$ git replace E~ E~2 
$ git replace 3~ 3~2 
$ git filter-branch -- ^A --all 

업데이트 2 : 당신은 같은 것을 할 것이다 당신의 목적을 위해

$ git filter-branch -- ^C G E # For demo, only rewrite G & E afer C 
$ git log --graph --oneline --decorate C~..G 
* fcfd345 (tag: G) Merge pull request #320 ... 
|\ 
| * fa76267 Fix a few kbd/missing markdown issues/ 
| * 4900687 Upcase readme and have more prompt examples. 
| * b25aa5a (tag: E) Now rename to README.md. 
* | 536c57f Merge pull request #319 ... 
|\ \ 
| |/ 
|/| 
| * 7fafb7b Speed up Get-GitStatus 
|/ 
* 2b9342c (tag: C) Merge pull request #313 ... 

,

의 I 얻을 커밋 메시지는 '나는 돈있는 E 떨어져있다 신경 쓰지 마. 차라리 D의 커밋 메시지 (또는 스크립트 제공 메시지)를 갖고 싶습니다.

tree (git cat-file -p E) D (그 E는 건너 뛰어야)을 위해, 예를 들어, '나는 이상 시작하고 E를 지정하는 --commit-filter을 사용하는 것이 좋습니다 것의 메타 데이터를 커밋'D을 유지하려면

git filter-branch --commit-filter ' 
    if [ "$GIT_COMMIT" = "SHA of D" ]; 
    then 
    git commit-tree "TREE of E" -p "SHA of C"; 
    elif [ "$GIT_COMMIT" = "SHA of E" ]; 
    then 
    skip_commit "[email protected]"; 
    else 
    git commit-tree "[email protected]"; 
    fi; 
    ' -- ^A E G 
+0

막히면 진행 상황에 대한 업데이트 나 의견을 남겨주세요. 도와 드리겠습니다. – dahlbyk

+0

이 경우,'git replace'를 두 번 실행하는 것이 좋습니다 : 첫째,'C'를 가리키는'E'를 만들기 위해서,'G'는'E' 대신'E'를 사용합니다; '3' 대신'3'을 사용하여'1'을 가리키는'3'을 다시 만듭니다. 그런 다음, 선택적으로'git filter-branch'를 실행하여 대체물을 시멘트로 만들고 원래의'D-E'와'2-3'을 완전히 버립니다. – torek

+0

예, '2-3'과 동일한 작업이 필요하다는 것을 알지 못했습니다. 업데이트 됨. – dahlbyk