[git] Git 저장소의 기록 축소

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

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

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

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

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

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

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



답변

바이너리 팽창을 제거하고 나머지 기록을 유지할 수 있습니다. 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

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


답변

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

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


답변

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

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

git filter-branch –tree-filter ‘rm filename’HEAD

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


답변

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).


답변