Git 저장소의 기록 축소


85

우리는 꽤 큰 역사를 가진 git 프로젝트를 가지고 있습니다.

특히 프로젝트 초기에는 프로젝트에 상당히 많은 바이너리 리소스 파일이 있었지만 이제는 사실상 외부 리소스이므로 제거되었습니다.

그러나이 파일이 이전에 커밋 되었기 때문에 리포지토리의 크기는> 200MB (현재 총 체크 아웃은 ~ 20MB)입니다.

우리가하고자하는 것은 히스토리를 "축소"하여 저장소가 이전보다 나중 개정에서 생성 된 것처럼 보이도록하는 것입니다. 예를 들면

1-----2-----3-----4-----+---+---+
                   \       /
                    +-----+---+---+
  1. 저장소가 생성되었습니다.
  2. 큰 바이너리 파일 세트 추가
  3. 큰 바이너리 파일 세트 제거
  4. 새로운 의도의 저장소 '시작'

따라서 효과적으로 특정 시점 이전에 프로젝트 기록을 잃고 싶습니다. 이 시점에서 브랜치가 하나뿐이므로 여러 시작점 등을 처리하려고하는 데 복잡함이 없습니다. 그러나 모든 기록을 잃고 현재 버전으로 새 저장소를 시작하고 싶지는 않습니다.

이것이 가능합니까, 아니면 저장소가 영원히 커질 운명입니까?

답변:


89

바이너리 팽창을 제거하고 나머지 기록을 유지할 수 있습니다. Git을 사용하면 이전 커밋을 재정렬하고 '스쿼시'할 수 있으므로 큰 바이너리 파일을 추가하고 제거하는 커밋 만 결합 할 수 있습니다. 추가가 모두 한 커밋에서 수행되고 다른 커밋에서 제거되면 각 파일을 처리하는 것보다 훨씬 쉽습니다.

$ git log --stat       # list all commits and commit messages 

바이너리 파일을 추가 및 삭제하는 커밋을 검색하고 해당 SHA1 (예 : 2bcdef및)을 기록 3cdef3합니다.

그런 다음 리포지토리의 기록을 편집하려면 rebase -i바이너리를 추가 한 커밋의 부모부터 시작하여 대화 형 옵션과 함께 command를 사용 합니다. $ EDITOR가 시작되고 2bcdef다음으로 시작하는 커밋 목록이 표시됩니다 .

$ git rebase -i 2bcdef^    # generate a pick list of all commits starting with 2bcdef
# Rebasing zzzzzz onto yyyyyyy 
# 
# Commands: 
#  pick = use commit 
#  edit = use commit, but stop for amending 
#  squash = use commit, but meld into previous commit 
# 
# If you remove a line here THAT COMMIT WILL BE LOST.
#
pick 2bcdef   Add binary files and other edits
pick xxxxxx   Another change
  .
  .
pick 3cdef3   Remove binary files; link to them as external resources
  .
  .

squash 3cdef3두 번째 줄로 삽입 pick 3cdef3하고 목록에서 말하는 줄을 제거하십시오 . 이제 rebase바이너리를 추가하고 삭제하는 커밋을 하나의 커밋으로 결합 하는 대화 형 작업 목록 이 있습니다. 그런 다음 완료하도록 지시하면 모든 후속 커밋을 순서대로 다시 적용합니다.

$ git rebase --continue

1 ~ 2 분 정도 걸립니다.
이제 바이너리가 더 이상 들어 오거나 나가지 않는 저장소가 있습니다. 그러나 기본적으로 Git은 변경 사항이 가비지 수집되기 전에 30 일 동안 유지되므로 마음을 바꿀 수 있기 때문에 여전히 공간을 차지합니다. 지금 제거하려면 다음을 수행하십시오.

$ git reflog expire --expire=1.minute refs/heads/master
      #all deletions up to 1 minute  ago available to be garbage-collected
$ git fsck --unreachable      # lists all the blobs(files) that will be garbage-collected
$ git prune
$ git gc                      

이제 부풀음을 제거했지만 나머지 기록은 유지했습니다.


7
다른 사람들이 이미 해당 저장소에서 가져 왔는지 기억해야합니다. 기록을 다시 작성하면 가져 오기가 혼동됩니다. git-rebase 매뉴얼은 다른 저장소를 복구하는 방법을 설명합니다. kernel.org/pub/software/scm/git/docs/git-rebase.html
Otto

이것은 사용자의 특정 문제에 대한 훌륭한 대답이지만 실제 질문에 대해서는 아닙니다! davitenio의 답변은 실제 질문에 대한 훌륭한 답변입니다.
Sam Watkins 2013

27

git filter-branch접목과 함께 사용 하여 커밋 번호 4를 브랜치의 새로운 루트 커밋으로 만들 수 있습니다 . .git/info/grafts커밋 번호 4의 SHA1을 포함하는 한 줄만 있는 파일 을 만듭니다 .

당신이 지금 할 경우 git log또는 gitk당신은 그 명령이 지점의 루트로 숫자 4를 저지 표시됩니다 것을 볼 수 있습니다. 그러나 실제로 저장소에서 변경된 사항은 없습니다. 삭제할 수 있으며 또는 .git/info/grafts출력은 이전과 동일합니다. 실제로 커밋 번호 4를 새 루트로 만들려면 인수없이 를 실행해야합니다 .git loggitkgit filter-branch


병합 커밋을 유지하는 데 문제가없고 타임 스탬프가 변경되지 않기 때문에 리베이스보다 훨씬 좋습니다. 모든 rebase 방법보다 쉽고 빠릅니다.
mmrobins

실제로 더 이상 해당 브랜치의 일부가 아닌 모든 커밋을 물리적으로 삭제할 수있는 방법이 있습니까? git gc --prune=0정리하지 않는 것 같습니다.
Verhogen

1
@verhogen git gc --prune=now은 더 이상 참조되지 않는 모든 커밋을 물리적으로 정리합니다. 이것이 작동하지 않으면 여전히 이전 루트를 참조하는 원격 추적 분기가있을 수 있습니다. 로 나열한 git branch -r다음 예를 들어로 원격 분기를 제거한 git branch -rd origin/master다음 git gc --prune=now다시 실행 하십시오.
kayahr

20

JesperE의 게시물 덕분에 내가 살펴본 git-filter-branch것은 실제로 당신이 원하는 것일 수 있습니다. Big Files가 제거 된 이후 수정되는 것을 제외하고는 이전 커밋도 유지할 수있는 것 같습니다. 로부터 자식 필터 - 지점 man 페이지 :

모든 커밋에서 파일 (기밀 정보 또는 저작권 위반 포함)을 제거한다고 가정합니다.

git filter-branch --tree-filter 'rm filename'HEAD

그 man 페이지를 반드시 읽으십시오 ... 분명히 예상대로 작동하는지 확인하기 위해 저장소의 예비 복제본에서이 작업을 수행하고 싶을 것입니다.


2
github에의 링크를 확인 ... 망할 놈의 필터 분기 명령과 함께 몇 가지 강력한 옵션이 있습니다 help.github.com/articles/remove-sensitive-data
ricosrealm

5

git-fast-export당신이 찾고있는 무엇?

NAME
   git-fast-export - Git data exporter

SYNOPSIS
   git-fast-export [options] | git-fast-import

DESCRIPTION
   This program dumps the given revisions in a form suitable to be piped into git-fast-
   import(1).

   You can use it as a human readable bundle replacement (see git-bundle(1)), or as a kind
   of an interactive git-filter-branch(1).
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.