git에 의해 생성 된 큰 .pack 파일 제거


112

많은 파일을 브랜치에 체크인하고 병합 한 다음 제거해야했고 이제 제거하는 방법을 모르는 큰 .pack 파일이 남았습니다.

사용하여 모든 파일을 삭제 git rm -rf xxxxxx하고 --cached옵션 도 실행했습니다 .

누군가가 현재 다음 디렉토리에있는 큰 .pack 파일을 제거하는 방법을 알려줄 수 있습니까?

.git/objects/pack/pack-xxxxxxxxxxxxxxxxx.pack

아직 가지고 있지만 더 이상 사용하지 않는 분기 만 제거해야합니까? 아니면 내가 실행해야 할 다른 것이 있습니까?

얼마나 많은 차이가 있는지 모르겠지만 파일에 자물쇠가 표시됩니다.

감사


편집하다

여기에 내가 어떻게이 상태에 들어갈 수 있었는지 알 수있는 bash_history에서 발췌 한 내용이 있습니다. 파일) :

git add .
git commit -m "Adding my branch changes to master"
git checkout master
git merge my-branch
git rm -rf unwanted_folder/
rm -rf unwanted_folder/     (not sure why I ran this as well but I did)

나는 또한 다음을 실행했다고 생각했지만 다른 사람들과 함께 bash_history에 나타나지 않습니다.

git rm -rf --cached unwanted_folder/

또한 git gc팩 파일을 정리하기 위해 몇 가지 git 명령 (예 :)을 실행했다고 생각 했지만 .bash_history 파일에도 나타나지 않습니다.


어떻게 제거했는지 명확히 할 수 있습니까? 아직 커밋 히스토리에 있으면 팩 파일에 여전히 있습니다.
loganfsmyth

@loganfsmyth 안녕하세요. 도움이 될 bash 히스토리 스크립트를 추가했습니다.
user1116573

답변:


201

문제는 파일을 제거했지만 이전 개정판에 여전히 존재한다는 것입니다. 그것이 git의 요점입니다. 무언가를 삭제하더라도 기록에 액세스하여 다시 가져올 수 있다는 것입니다.

당신이하고자하는 것은 재 작성 히스토리라고 불리는데 그것은 git filter-branch명령 과 관련이 있습니다.

GitHub의 사이트에 문제에 대한 좋은 설명이 있습니다. https://help.github.com/articles/remove-sensitive-data

질문에 더 직접적으로 대답하기 위해 기본적으로 실행해야하는 것은이 명령을 unwanted_filename_or_folder적절 하게 대체하는 것입니다.

git filter-branch --index-filter 'git rm -r --cached --ignore-unmatch unwanted_filename_or_folder' --prune-empty

이렇게하면 저장소의 활성 기록에서 파일에 대한 모든 참조가 제거됩니다.

다음 단계는 GC주기를 수행하여 파일에 대한 모든 참조를 강제로 만료시키고 packfile에서 제거합니다. 이 명령에서 대체 할 필요가 없습니다.

git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
# or, for older git versions (e.g. 1.8.3.1) which don't support --stdin
# git update-ref $(git for-each-ref --format='delete %(refname)' refs/original)
git reflog expire --expire=now --all
git gc --aggressive --prune=now

3
나는 그것이 미래에이 질문에 오는 사람이 더 쉽게 올 수 있도록 허용한다면 그것을 받아 들인 것으로 표시했다. 비록 내가 실제로 새로운 git repo를 만들어서 당시 내 문제를 해결했지만
user1116573

3
이걸 어떻게 생각해 냈는지 모르겠지만 ... 당신은 남자입니다. 감사.
에스겔 빅터

5
이 대답은 저를 올바른 방향으로 안내했습니다. 그러나 실제로 파일을 삭제하려면 3 개의 명령이 더 필요합니다. 1) git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin2) git reflog expire --expire=now --all3)git gc --prune=now
arod

3
사용하기가 bfg훨씬 더 쉽습니다. 공식 github 문서에서도 권장됩니다 : help.github.com/articles/…
Timo

2
@Timo 시간이 지남에 따라 상황이 변경된 경우 새로운 답변을 추가하는 것이 좋습니다. 그것을 위해 가십시오!
loganfsmyth

12

시나리오 A : 큰 파일이 브랜치에만 추가 된 경우에는을 실행할 필요가 없습니다 git filter-branch. 분기를 삭제하고 가비지 수집을 실행하기 만하면됩니다.

git branch -D mybranch
git reflog expire --expire-unreachable=all --all
git gc --prune=all

시나리오 B : 그러나 bash 히스토리에 따르면 변경 사항을 마스터에 병합 한 것 같습니다. 변경 사항을 누구와도 공유하지 않은 경우 ( git push아직 공유하지 않음). 가장 쉬운 방법은 큰 파일이있는 브랜치와 병합하기 전에 마스터를 다시 재설정하는 것입니다. 이렇게하면 브랜치의 모든 커밋과 병합 후 마스터에 대한 모든 커밋이 제거됩니다. 따라서 실제로 원할 수있는 큰 파일 외에도 변경 사항이 손실 될 수 있습니다.

git checkout master
git log # Find the commit hash just before the merge
git reset --hard <commit hash>

그런 다음 시나리오 A의 단계를 실행하십시오.

시나리오 C : 유지하려는 병합 후 분기에서 다른 변경 사항이 있거나 마스터 에서 변경된 경우 마스터를 리베이스하고 원하는 커밋을 선택적으로 포함하는 것이 가장 좋습니다.

git checkout master
git log # Find the commit hash just before the merge
git rebase -i <commit hash>

편집기에서 큰 파일을 추가 한 커밋에 해당하는 줄을 제거하고 나머지는 그대로 둡니다. 저장하고 종료하십시오. 마스터 브랜치는 원하는 내용 만 포함해야하며 대용량 파일은 포함하지 않아야합니다. 참고 것을 git rebase하지 않고 -p병합 커밋을 제거 할 것이다, 그래서 당신은 후 마스터 선형 역사에 남아있을 것입니다 <commit hash>. 이것은 아마도 당신에게 괜찮을 수 있지만 그렇지 않다면을 사용해 볼 수 -p있지만 git help rebase라고 말합니다 combining -p with the -i option explicitly is generally not a good idea unless you know what you are doing.

그런 다음 시나리오 A의 명령을 실행하십시오.


대본의 변형이있다 여기에 추가 예상치 못한 문제는, 그러나,와.

시나리오 A는 대량의 임시 팩 파일을 삭제하기 위해 광산 문제를 해결했습니다. 저장소는 빌드 서버에 의해 관리되었으며 .git / objects / pack 폴더 내에 원치 않는 파일 생성이 발생합니다. 디스크에서 귀중한 GB를 확보 할 수 있습니다.
xrissz

7

loganfsmyth가 이미 그의 답변 에서 언급했듯이 파일이 저장소에서 삭제 된 후에도 계속 존재하기 때문에 git 기록을 제거해야합니다. 공식 GitHub 문서 에서는filter-branch 다음 보다 사용하기 쉬운 BFG권장합니다 .

기록에서 파일 삭제

웹 사이트에서 BFG를 다운로드하십시오 . Java가 설치되어 있는지 확인한 다음 미러 클론을 만들고 기록을 제거하십시오. YOUR_FILE_NAME삭제할 파일의 이름 으로 바꾸십시오 .

git clone --mirror git://example.com/some-big-repo.git
java -jar bfg.jar --delete-files YOUR_FILE_NAME some-big-repo.git
cd some-big-repo.git
git reflog expire --expire=now --all && git gc --prune=now --aggressive
git push

폴더 삭제

위와 같지만 사용 --delete-folders

java -jar bfg.jar --delete-folders YOUR_FOLDER_NAME some-big-repo.git

다른 옵션

BFG는 또한 다음과 같은 더 멋진 옵션 ( 문서 참조 )을 허용합니다 .

기록에서 100M보다 큰 모든 파일을 제거합니다.

java -jar bfg.jar --strip-blobs-bigger-than 100M some-big-repo.git

중대한!

BFG를 실행할 때 YOUR_FILE_NAME및 둘 다 YOUR_FOLDER_NAME실제로 파일 / 폴더 이름 임을주의 하십시오. 그들은 경로가 아니므로 같은 foo/bar.jpg것이 작동하지 않습니다! 대신 지정된 이름의 모든 파일 / 폴더가 존재하는 경로 또는 분기에 관계없이 저장소 기록에서 제거됩니다.


bfg도구를 로컬 git repo 에 적용하고 싶은지 궁금 합니다. 명령이 어떻게 생겼을까 요?
Angel Todorov 2011

5

하나의 옵션 :

git gc수동으로 실행 하여 여러 팩 파일을 하나 또는 몇 개의 팩 파일로 압축합니다. 이 작업은 지속적이므로 (즉, 큰 팩 파일은 압축 동작을 유지합니다) 따라서 정기적으로 저장소를 압축하는 것이 좋습니다.git gc --aggressive

또 다른 옵션은 코드와 .git을 어딘가에 저장 한 다음 .git을 삭제하고이 기존 코드를 사용하여 다시 시작하여 새 git 저장소 ( git init)를 만드는 것 입니다.


안녕하세요 Michael, 저는 실행을 시도 git gc하고 몇 개의 팩 파일로 내려 갔지만 큰 파일은 여전히 ​​그중 하나이며 폴더를 외부에서 쉽게 백업 할 수 있도록 제거하고 싶습니다 (이전에는 1 -2Mb, 이제 55Mb). 누군가가 다른 것을 제안 할 수 없다면 새로운 자식을 만들어야 할 수도 있습니다. 나는 이것이 내가 현재 가지고있는 브랜치 등에 대한 액세스 권한을 잃을 것이라는 것을 의미한다고 가정합니다.
user1116573

2
나는 시도를 포기하고 방금 .git 폴더를 삭제하고 당신이 말한 것처럼 새로운 git 저장소를 만들었습니다. 나는 그것을 배운 교훈이라고 생각할 것입니다. 감사합니다 마이클.
user1116573

4
이것은별로 말이되지 않습니다. 왜 git에게 현재 저장소를 통합하고 프로세스에서 팩 파일을 제거하도록 지시 할 수 없습니까?
jml 2013

4

다음 명령을 실행하여 PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA파일 이름뿐만 아니라 제거 할 파일의 경로로 바꿉니다 . 이러한 인수는 다음과 같습니다.

  1. Git이 모든 브랜치 및 태그의 전체 기록을 처리하되 체크 아웃하지 않도록합니다.
  2. 지정된 파일과 결과로 생성 된 빈 커밋을 제거합니다.
  3. 기존 태그 덮어 쓰기
git filter-branch --force --index-filter "git rm --cached --ignore-unmatch PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA" --prune-empty --tag-name-filter cat -- --all

이렇게하면 저장소의 활성 기록에서 파일에 대한 모든 참조가 강제로 제거됩니다.

다음 단계는 GC주기를 수행하여 파일에 대한 모든 참조를 강제로 만료시키고 팩 파일에서 제거합니다. 이 명령에서 대체 할 필요가 없습니다.

git update-ref -d refs/original/refs/remotes/origin/master
git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
git reflog expire --expire=now --all
git gc --aggressive --prune=now

마지막으로 두 번째 부분에서 28G 저장소를 158M으로 줄였습니다. Google에서 거의 작동하지 않았습니다. 감사합니다.
Sridhar Sarnobat

위의 단계를 따랐고 "git push origin --force --all"으로 푸시했지만 여전히 원격 브랜치 (마스터, 개발 및 기능 / ASD-1010)가 정리되지 않았습니다. 원격 저장소에서 새로 복제했을 때 .pack 파일이 여전히 존재했습니다. 이 정리를 모든 원격 git 브랜치에 어떻게 반영 할 수 있습니까 ??
Sambit Swain

1

쇼에 조금 늦었지만 위의 답변으로 쿼리가 해결되지 않은 경우 다른 방법을 찾았습니다. .pack에서 특정 대용량 파일을 제거하기 만하면됩니다. 실수로 큰 2GB 파일을 체크인 한이 문제가 발생했습니다. 이 링크에 설명 된 단계를 따랐습니다. http://www.ducea.com/2012/02/07/howto-completely-remove-a-file-from-git-history/


이 방법을 수행하면 프로젝트의 전체 기록이 완전히 제거되거나 지정된 파일 만 제거됩니다.
Samim Aftab Ahmed

-3

이것은 코딩보다 편리한 솔루션입니다. 파일을 압축하십시오. 파일보기 형식으로 zip을 엽니 다 (압축 해제와 다름). .pack 파일을 삭제하십시오. 폴더의 압축을 풀고 교체하십시오. 매력처럼 작동합니다!

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