업스트림 프로젝트 세력이 마스터에 푸시 된 후 git 하위 트리를 어떻게 수정합니까?


13

git 하위 트리를 사용하여 실험하고 있으며 다음과 같은 상황이 발생했습니다.

git 하위 트리를 사용하여 리포지토리에 외부 프로젝트를 추가했습니다. 프로젝트 히스토리를 참조하고 나중에 업스트림 프로젝트에 다시 기여하기 위해 의도적으로 업스트림 프로젝트의 모든 히스토리를 유지했습니다.

결과적으로, 업스트림 프로젝트의 다른 제공자가 실수로 큰 파일을 마스터 브랜치로 푸시했습니다. 이 문제를 해결하기 위해 업스트림 프로젝트는 기록을 다시 작성하고 강제로 마스터에게 푸시했습니다. "모노 레포"를 만들 때이 커밋을 포함 시켰으며이를 제거하고 싶습니다.

하위 트리의 새 기록을 반영하도록 저장소를 업데이트하려면 어떻게해야합니까?

첫 번째 시도는 filter-branch를 사용하여 하위 트리와 모든 기록을 완전히 제거하는 것이 었습니다.

git filter-branch --index-filter 'git rm -rf --cached --ignore-unmatch upstream-project-dir' --prune-empty HEAD

이전 버전의 하위 트리가 제거되면 새로운 업스트림 마스터를 사용하여 하위 트리를 다시 추가 할 수 있습니다. 그러나 어떤 이유로 커밋 기록이 여전히 git log 출력에 표시되기 때문에 이것은 작동하지 않았습니다.

최신 정보

최소한의 재현 가능한 예제를 만드는 단계를 작성했습니다.

  1. 먼저 빈 자식 저장소를 만듭니다.

    git init test-monorepo
    cd ./test-monorepo
    
  2. 초기 커밋을 만듭니다.

    echo hello world > README
    git add README
    git commit -m 'initial commit'
    
  3. 이제 외부 프로젝트의 하위 트리를 추가하십시오.

    git remote add thirdparty git@github.com:teivah/algodeck.git
    git fetch thirdparty
    git subtree add --prefix algodeck thirdparty master
    
  4. monorepo에 대한 커밋 만들기

    echo dont panic >> algodeck/README.md
    git commit -a -m 'test commit'
    
  5. 이제 git filter-branch를 사용하여 하위 트리를 제거하십시오.

    git filter-branch --index-filter 'git rm -rf --cached --ignore-unmatch algodeck' --prune-empty HEAD
    
  6. 자식 로그 출력을 검사하면 초기 커밋 만 볼 것으로 예상됩니다.

    git log
    

git gc --prune = 이제 오래된 커밋을 버릴려고 했습니까? 이전 버전 커밋에 대한 언급이 있습니까?
Damiano

1
나는 이것을 시도 git gc --prune=now하지 않았지만에 나타나지 않는 커밋 만 삭제하지는 git log않습니까?
csnate

git branch -all을 사용하면 (이전 커밋을 보는 데 사용한다고 가정) 현재 브랜치와 관련이없는 커밋도 표시해야합니다.
Damiano

1
사실, 나는 git log논쟁을하지 않고 있었고 , 여전히 오래된 커밋을 보았습니다.
csnate

git log --pretty --all --graph를 게시 할 수 있습니까? 상황을 이해하기 위해
Damiano

답변:


0

당신은 이미 당신의 역사에서 나쁜 커밋을 가지고 있으며 계속하기 전에 그것을 제거해야합니다.

master마지막 커밋이 전환되어 다른 작업을 수행 할 수 없다고 가정 해 봅시다 (실제로 지점이 보이지 않으므로 시작할 무언가를 가정해야합니다)

이전 커밋을 체크 아웃하고 분기 마커를 1 단계 뒤로 (또는 X 단계 뒤로) 밀어 넣을 수 있습니다.

예 :

git checkout master~1
git branch master -f
git checkout master
git pull
  1. git checkout master~1 마스터의 부모 커밋을 체크 아웃하기 위해 자식은 우리가 가지를 벗어났다고 경고
  2. git branch master -f 현재 체크 아웃을 다시 마스터로 강제하기 위해, 즉 실제로 마스터 분기를 이전 커밋 (또는 X 이전 커밋)으로 되감습니다. 여기서 상류에 힘이 있었는지 여부는 중요하지 않습니다. 필요한 경우 위 단계로 돌아 가면 업스트림에서 아무것도 잃지 않고 마스터 만 다시 가져올 수 있습니다 (읽기 전용 일 수는 있지만 이것으로 아무것도 밀지 않을 것입니다)
  3. git checkout master "rewound"마스터 브랜치에 있어야합니다. 동일한 커밋과 같은 단계이지만 이제는 브랜치에 있습니다.
  4. git pull마스터를 다시 가져 오기 위해 (의 유무에 관계없이 --prune) 업스트림이 전환되면 여기에서 다시 돌아올 것입니다. 위의 첫 번째 단계로 돌아가서 더 많은 커밋을 되 감아 야합니다 git checkout master~5( 예 : 필요에 따라)

나는 이것이 작동하지 않을 것이라고 생각한다git subtree
csnate

@csnate 그것은 subrepo에서 이전 커밋을 체크 아웃과 매우 유사한 절차를 따르십시오, 당신이 MCVE을 구축하는 경우가 따라 당신에게 정확한 명령을 말할 쉬울 수 있습니다 stackoverflow.com/help/minimal-reproducible-example
arhak

GitHub에서 샘플 리포지토리를 만들려고합니다.
csnate

원래 질문에서 문제를 보여주는 일련의 단계를 만들었습니다.
csnate

0
  1. 리포지토리 에서이 원격에 대한 커밋 기록을 정리하십시오.

    git fetch upstream
    
  2. 자체 커밋 중 하나에 큰 파일이 포함 된 커밋이있는 경우이 큰 파일이 더 이상 참조되지 않도록 기록을 다시 작성하십시오.

    # using one or more of the following commands :
    git rebase --interactive
    git filter-branch
    ...
    

이 두 단계를 사용하면 큰 파일은 더 이상 repo의 커밋에 의해 참조되지 않습니다.
git이 가비지 수집기를 실행하고 매달려있는 얼룩의 만료 지연에 도달하면 특정 시점에 하드 드라이브에서 추가로 삭제됩니다.


이 큰 파일을 하드 드라이브에서 최대한 빨리 삭제해야하는 경우 :

수동으로 실행

git gc --prune=now
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.