Git LFS(Large file storage) 사용해보기

얼마전 Gitlab 8.2 버전이 릴리즈되며 git-lfs를 지원한다는 말에 진행중인 프로젝트에 적용해보기로 했습니다. 결과적으로는 꽤 오랜 시간이 걸려서야 lfs를 이용한 git 사용이 가능하도록 세팅하는데 성공했습니다. 이 삽질기는 gitlab에 깊이 관여되어 있어서 다음에 기회가 되면 공유하고 이번엔 삽질하며 공부한 git lfs 대해 아주 얇게 다뤄보려 합니다.

LFS?

lfs는 large file handling을 하기 위해 만들어진 오픈소스이고 github에서 채택한 상태입니다. github에서는 lfs 도입 이유를 다음고 같이 설명하고 있습니다.

git과 같은 분산된 버전 컨트롤 시스템은 새롭고 좋은 workflows를 가능하게 합니다. 하지만 대용량 파일을 다룰 때는 적절하지 않을 때도 있습니다. Distributed version control systems like Git have enabled new and powerful workflows, but they haven’t always been practical for versioning large files

git이 제공하는 분산환경에서 모든 개발자들은 프로젝트 파일 뿐만 아니라 그 파일들의 full change history를 모두 가지고 있어야 합니다. 이와중에 거대한 binary 파일이 변경되는 것만으로도 레파지토리의 크기가 커지게 됩니다. 그 파일 뿐만 아니라 변경사항까지 저장하고 있기 때문이죠. 때문에 레파지토리 크기를 컨트롤하기 어려웠습니다.

lfs는 이 문제를 해결하기 위해 나온 오픈소스입니다.

동작

lfs의 핵심은 대용량 파일을 그대로 저장하지 않고 파일이 저장되어 있는 곳을 text pointer로 대체하는 것입니다. 실제 파일은 git lfs api를 통해 분리된 공간으로 저장됩니다. 이 부분은 현재 github보다 gitlab에 lfs로 오브젝트를 저장해보면 쉽게 확인할 수 있습니다.

gitlab-lfs-text-pointer

그림이 실제로 뜨는 대신 text가 표시되고 있습니다. oid의 sha 체크섬이 gitlab server내의 lfs object를 가르키고 있는 형태입니다. github에서는 lfs로 저장해도 raw에 접근하면 그림이 뜨긴 합니다만 lfs로 저장된 파일과 그냥 push 된 파일의 링크형태가 다릅니다.

#lfs raw link
- https://media.githubusercontent.com/media/darkrasid/testing-lfs1/master/test-lfs.jpg
#non lfs raw link
- https://raw.githubusercontent.com/darkrasid/testing-lfs2/master/test-lfs.jpg

lfs에 저장된 파일과 그냥 저장된 파일의 관리 방식이 다른 것을 알 수 있습니다. 이 방법의 장점은 lfs로 저장한 프로젝트와 아닌 프로젝트의 .git 용량 차이를 보면 확실하게 찾아볼 수 있습니다.

diff-lfs-nonlfs

두 프로젝트 중 용량이 적은 쪽은 lfs를 이용해서 푸시하고 다른 것은 그냥 했을 때 입니다. 동일한 브랜치 수(3개씩)와 동일한 파일을 가지고 있죠. 용량 차이가 3배가량 나는 것을 확인할 수 있습니다. 프로젝트가 더 커지고 대용량 파일의 크기가 더 커질 수록 차이는 더 크게 나겠죠.

사용법

lfs 장점 중 또 하나는 한번 설정해놓으면 git workflow를 해치지 않는다는 것입니다. lfs를 사용하기 위해서는 우선 lfs client를 먼저 설치해야 합니다. 설치는 lfs 홈페이지의 다운로드 페이지에서 받으시면 됩니다. window는 installer가 제공되고 linux및 mac등은 다운 후 압축을 풀어보면 install shell script가 제공됩니다. 설치 후 사용법은 아주 간단합니다.

cd GIT_PROJECT_PATH
# lfs install은 한번만 해주면 됩니다.
git lfs install
# lfs로 관리할 파일을 지정해줍니다.
# *.jpg나 *.mp4 등 형식으로 지정하거나 /image 등의 폴더 test.png등의 지정도 가능합니다.
git lfs track "*.jpg"

이후로는 git을 그냥 사용하는 것과 같습니다. 위의 예시에서 track되고 있는 jpg는 앞으로 별도의 명령어 없이 lfs로 관리됩니다. track되고 있는 파일들은 git lfs track 명령어로 확인가능합니다. 또 track을 시작하면 자동으로 .gitattributes 파일이 생성이 되고 내부에 track중인 내용이 정의됩니다.

처음 lfs를 적용하고 나서 개인적으로 불편했던 것은 인증입니다. lfs로 파일을 관리하기 시작하면 그냥 git만 사용할 때보다 인증을 더 많이 해줘야 합니다. 예를 들어 git lfs track "*.md" 명령어로 markdown 파일을 트랙킹 할 경우

pilsner @ pil-mac : ~/projects/tvset $ git lfs install
Updated pre-push hook.
Git LFS initialized.
pilsner @ pil-mac : ~/projects/tvset $ git lfs track "*.md"
Tracking *.md
pilsner @ pil-mac : ~/projects/tvset $ touch README.md
pilsner @ pil-mac : ~/projects/tvset $ git add .
pilsner @ pil-mac : ~/projects/tvset $ git commit -m "README init"
[master 3ef7faa] README init
 2 files changed, 4 insertions(+)
 create mode 100644 .gitattributes
 create mode 100644 README.md
pilsner @ pil-mac : ~/projects/tvset $ git push origin master
### 한번 인증
Username for 'https://github.com': pilsner
Password for 'https://pilsner@github.com':
### 두번째 인증
Username for 'https://github.com': pilsner
Password for 'https://pilsner@github.com':
Git LFS: (1 of 1 files) 0 B / 0 B                                                                                                                                                                                                                                                                                                                                          Counting objects: 4, done.
Delta compression using up to 12 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 533 bytes | 0 bytes/s, done.
Total 4 (delta 0), reused 0 (delta 0)
To https://github.com/pilsner/tvset.git
   f630faa..3ef7faa  master -> master

인증을 두번 진행하게 됩니다. track되는 파일 형식당 한번의 인증을 추가로 진행하는 것입니다. 아마 lfs object를 저장하기 위한 인증이라고 추측하고 있습니다. 위의 예제에선 *.md파일의 인증을 이미 한번 진행했으므로 앞으로 관리되는 md 파일에 대해서는 추가 인증을 할 필요가 없습니다. 하지만 *.jpg파일을 추가로 track한다면 처음 jpg파일을 push 할 때는 추가 인증을 해야합니다.

이건 clone받을 때도 마찬가지 인데요. public project라면 인증없이 모두 받겠지만 그렇지 않다면 track되는 파일 형식당 한번의 인증이 필요합니다. 엄청 귀찮겠죠. 그래서 lfs를 쓸 때 계정을 cache하는 방법을 추천합니다. 방법은 여기 있습니다.

적용

적용도 어렵지 않은데요. 이미 많은 양의 대용량 파일을 관리중인 프로젝트라도 track rule(.gitattributes 파일)을 커밋한 후에 다시 clone 받게 되면 별도의 행위 없이 tracking되는 대용량 파일들이 modified 상태가 되어 있습니다. 이걸 push 하면 원래 가지고 있던 대용량 파일들도 모두 lfs로 관리됩니다.

여기까지 lfs에 대해 알아봤습니다. 대용량 파일이 많아 레파지토리의 크기를 걱정해야 하는 팀에서 유용할 것 같습니다. 특히 저희 팀은 gitlab을 이용한 git 레파지토리 서버를 관리해야 하는 입장인데요. 안그래도 서버 용량때문에 문제가 많았는데 현명하게 피해갈 수 있는 방법인 것 같습니다.