Git : 기록 커밋에서 파일을 제거하는 방법?


113

예를 들어 ID 56f06019로 커밋했습니다. 그 커밋에서 실수로 큰 파일 (50Mb)을 커밋했습니다. 다른 커밋에서 동일한 파일을 추가하지만 올바른 크기 (작음)로 추가합니다. 이제 복제가 너무 무거울 때 내 저장소 :( 저장소의 크기를 줄이기 위해 저장소 기록에서 큰 파일을 제거하는 방법은 무엇입니까?


제 경우에는 큰 파일이 아니라 데이터베이스 크레딧이 포함 된 구성 파일입니다. 나는 git을 공부하고 있었는데 그 당시에는 .gitignore를 몰랐습니다.
Rashi 2011


답변:


165

Pro Git 책의 9 장 에는 Remove Objects 에 대한 섹션이 있습니다 .

여기에서 단계를 간략하게 설명하겠습니다.

git filter-branch --index-filter \
    'git rm --cached --ignore-unmatch path/to/mylarge_50mb_file' \
    --tag-name-filter cat -- --all

이전에 설명한 리베이스 옵션과 마찬가지로 filter-branch다시 쓰기 작업입니다. 기록을 게시 한 경우 --force새 참조 를 푸시 해야합니다 .

filter-branch접근 방식은보다 훨씬 더 강력 rebase그것 때문에, 접근

  • 한 번에 모든 분기 / 참조에서 작업 할 수 있습니다.
  • 즉시 모든 태그의 이름을 바꿉니다.
  • 파일 추가 이후 병합 커밋이 여러 번 있어도 깨끗하게 작동합니다.
  • (a) 브랜치의 히스토리에서 파일이 여러 번 (재) 추가 / 제거 된 경우에도 깨끗하게 작동합니다.
  • 관련되지 않은 새로운 커밋을 생성하지 않고 관련 트리를 수정하는 동안 복사합니다. 이것은 서명 된 커밋, 커밋 메모 등과 같은 항목이 보존됨을 의미합니다.

filter-branch 백업도 유지하므로 reflog 및 가비지 수집을 만료하지 않는 한 repo의 크기가 즉시 감소하지 않습니다.

rm -Rf .git/refs/original       # careful
git gc --aggressive --prune=now # danger

1
이것은 Windows cmd.exe에서 작동하지 않는 것 같습니다. 그래도 cygwin에서 잘 작동하는 것 같습니다.
가짜 이름

2
나는 (윈도우 서버 2012 cmd.exe를에) 큰 따옴표 대신 작은 따옴표를 사용하여 작업 할 수있는 위의 자식 필터 지점을 가지고
JCii

1
나를 위해 일한 것은이 필터 분기 명령 줄이었습니다. git filter-branch --force --index-filter 'git rm --ignore-unmatch --cached PathTo/MyFile/ToRemove.dll' -- fbf28b005^.. 다음 rm --recursive --force .git/refs/originalrm --recursive --force .git/logs 다음 나는를 사용 git prune --expire now 하고 git gc --aggressive 이 위에 나열된 정확한 단계보다 나를 위해 더 나은했다. 귀중한 Git Pro 책 링크를 포함 해 주셔서 감사합니다.
dacke.geo

filter-branch 명령 후 .git 폴더의 크기를 줄일 수있는 유일한 방법은 다음 명령을 따르는 것입니다. stackoverflow.com/questions/1904860/… git -c gc.reflogExpire = 0 -c gc. reflogExpireUnreachable = 0 -c gc.rerereresolved = 0 \ -c gc.rerereunresolved = 0 -c gc.pruneExpire = 지금 GC "$ @"
스티브 아디스

다음 REPO 축소, 나는 자식 필터 지점 문서에 나와있는 명령을 사용 git-scm.com/docs/...
루도빅 Ronsin


0

대화 형 모드에서 git rebase 를 수행 해야합니다 . 여기 예제를 참조하십시오. GitHub에서 커밋을 제거하려면 어떻게해야합니까? 그리고 오래된 커밋을 제거하는 방법 .

커밋이 HEAD에서 10 커밋을 뺀 경우 :

$ git rebase -i HEAD~10

히스토리 편집 후에는 "새로운"히스토리를 푸시해야하며, +to force 를 추가해야합니다 ( 푸시 옵션 의 refspec 참조 ).

$ git push origin +master

다른 사람이 이미 저장소를 복제 한 경우 기록을 변경했기 때문에 알려야합니다.


3
이것은 기록에서 큰 파일을 제거 하지 않습니다 . 또한 강제로 푸시하는 표준 방법은 git push --force또는 git push -f(사람들이 분기 푸시 대상을 알 필요가 없음)
sehe

질문에 따르면 새 파일은 이전 파일, 즉 동일한 경로와 정확히 동일합니다. 이것이 git rm경로에서 직접 사용할 수없는 이유 입니다.
Loïc d' Anterroches

2
@sehe, 거대한 파일로 커밋을 제거하는 rebase를 수행하면 영원히 사라집니다.
vonbrand 2013

리베이스 한 브랜치에서만 @vonbrand. 나는 'from'브랜치가 삭제되었다고 가정하지 않습니다. 하지만 예, 수정 트리 분기를 삭제하면 도움이 될 것입니다. : _
sehe

@sehe, 당연히 문제가되는 커밋을 포함하는 모든 분기를 추적해야합니다. 리포지토리에서 약간의 덤불이 발생하기 전에 있다면 많은 재구성이 필요합니다. 그러나 rebase 는이를 위한 도구입니다.
vonbrand 2013

0

Windows https://stackoverflow.com/a/8741530/8461756 에서 다음 답변을 사용해 보았습니다.

작은 따옴표는 창에서 작동하지 않으며 큰 따옴표가 필요합니다.

다음은 나를 위해 일했습니다.

git filter-branch --force --index-filter "git rm --cached --ignore-unmatch PathRelativeRepositoryRoot / bigfile.csv"---all

큰 파일을 제거한 후 변경 사항을 github master에 푸시 할 수있었습니다.


0

간단한 명령을 사용하여 삭제할 수 있습니다.

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