어제자 HackerNews에 GitFS에 대한 글이 올라왔었다. GitFS는 이름에서 엿볼수 있듯, Git을 파일 시스템처럼 사용할 수 있게끔 해주는 파일 시스템 구현이다. Python으로 Fuse 구현을 한 것이기 때문에 왠만한 OS에서 문제 없이 동작한다.

일반 Git도 clone을 하면 읽고 쓰기가 가능하다. 그럼에도 GitFS를 쓰는 이유는 자동 커밋, 푸시, 패치를 해 주기 때문이다. git fetch의 경우 설정한 주기마다 서버에서 읽기를 시도한다. FUSE 구현으로 통해 파일이 새로 생겼거나 수정됨을 파악하여 알아서 commit과 push까지 해 준다. (이런식으로: https://bitbucket.org/ESukmean/gitfs-test/src/master/)

사용하려면 많은곳에서 쓸 수 있을듯 하다. 여러 서버에 동일한 파일들을 배포해야 할 때나, 수정이 빈번하여 매번 git commit을 하기 귀찮은 작업장에서 사용하기 딱 좋다. 버전관리 또한 깔끔하기 때문에 작업물을 저장하는 컴퓨터에서 사용하기도 좋다. 특히 git을 잘 못쓰는 사람도 써야하는 경우에 유용하다. 알아서 git commit과 push를 해 주며, 이전 버전의 파일을 보는것도 상당히 직관적이기 때문이다.

설치 방법

GitFS는 Python을 이용해서 Fuse로 파일 시스템을 구현한 것이다. 그러므로 Fuse를 지원하는 시스템과 파이썬이 필요하다. 필자의 경우 리눅스(우분투 21.04)에 GitFS를 설치했다. 다른 OS여도 큰 틀은 비슷하니까 따라오면 될 듯하다. 글을 쓰는 시점에서 GitFS의 release는 19년도에서 멈춰있다. 코드 수정 자체는 21년 이후에도 있으니까 왠만하면 OS의 패키지 관리자 대신 소스파일을 직접 컴파일 해서 쓰자. (어짜피 우분투용 패키지는 18.04 버전용 까지만 있다. 20.04 이후 우분투에서는 어쩔수 없이 컴파일해야한다)

[email protected]:~# sudo apt-get update
Hit:1 http://us.archive.ubuntu.com/ubuntu hirsute InRelease
Ign:2 http://ppa.launchpad.net/presslabs/gitfs/ubuntu hirsute InRelease
Hit:3 http://us.archive.ubuntu.com/ubuntu hirsute-updates InRelease
Hit:4 http://us.archive.ubuntu.com/ubuntu hirsute-backports InRelease
Hit:5 http://us.archive.ubuntu.com/ubuntu hirsute-security InRelease
Err:6 http://ppa.launchpad.net/presslabs/gitfs/ubuntu hirsute Release
  404  Not Found [IP: 2001:67c:1560:8008::19 80]
Reading package lists... Done
E: The repository 'http://ppa.launchpad.net/presslabs/gitfs/ubuntu hirsute Release' does not have a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.

우선 Python 3.7을 준비한다. make시에 사용되는 virtualenv에서 python 3.7을 요구한다. 우분투 21.04 에서는 Python 3.9만 지원한다. 어쩔수 없이 직접 Python 3.7 코드를 다운받아서 빌드를 먼저 했다. 컴파일은 https://gist.github.com/jerblack/798718c1910ccdd4ede92481229043be 를 참고했다.

sudo apt-get install virtualenv
sudo apt install build-essential libssl-dev zlib1g-dev libncurses5-dev libncursesw5-dev libreadline-dev libsqlite3-dev libgdbm-dev libdb5.3-dev libbz2-dev libexpat1-dev liblzma-dev tk-dev libffi-dev

# download and extract python
wget https://www.python.org/ftp/python/3.7.0/Python-3.7.11.tar.xz
tar xf Python-3.7.11.tar.xz
cd Python-3.7.11

./configure
sudo make
# altinstall does not alter original system python install
sudo make altinstall

python 3.7이 설치되면 힘든 과정이 지나간 것이다. GitFS 코드를 빌드하면 된다. virtualenv를 써야함을 유의해야 한다. 곧바로 make를 돌리면 virtualenv: error: the following arguments are required: dest 같은 오류가 발생한다.

cd gitfs/
python3.7 -m venv venv
source venv/bin/activate
make

이러면 설치는 모두 완료되었다. 사용만하면 된다.

사용하기

우선 git repo가 clone될 디렉토리와 GitFS가 마운트될 디렉토리 두곳을 만들어야 한다. git repo가 clone될 디렉토리가 뭔지 이해 안될수도 있다. GitFS는 외부 어딘가에 실제 Git 리포를 두고, 그것을 편하게 사용할 수 있는 방법을 제공하는것 뿐이다. 별도의 설정이 없으면 /var/lib/gitfs/ 에 리포들을 clone한다.

mkdir fs
mkdir /var/lib/gitfs
gitfs -o commiter_name=esukmean,[email protected],username=ESukmean,password=pw1234 https://[email protected]/ESukmean/gitfs-test.git fs

그리고 사용하면 된다. 최신 상태의 파일은 마운트한 디렉터리 아래에 있는 current에, 과거 버전 정보는 history에서 볼 수 있다. 아래는 마운트한 디렉토리에서 tree를 찍어본 결과이다.

[email protected]:~/fs# tree
.
├── current
│   ├── dist
│   ├── test.pyc
│   └── test_upload
└── history
    └── 2021-08-23
        ├── 12-51-35-3c269b89bd
        ├── 12-55-08-2ec0a6835a
        │   └── test_upload
        └── 12-56-01-a8c3dd80f1
            ├── dist
            └── test_upload

8 directories, 4 files

파일을 수정하거나 만든 후 Git commit을 보면 아래와 같이 반영됨을 볼 수 있다

몇가지 유의점

.gitignore로 설정된 파일과 폴더에는 쓰기를 할 수 없다. .gitignore에 해당되는 대상들은 git에서 관리할 수 없어서 GitFS에서도 쓰기를 거부하는것 같았다. 이 경우 git repo를 실제 클론한 디렉토리에서 파일을 만들거나 수정하면 된다. 어떻게 보면 write-protection을 걸어주는것이기에 의도치 않은 파일 수정을 막아줄 수도 있다. GitFS를 마운트 할 때 git repo 위치를 설정하지 않았으면 /var/lib/gitfs 아래에 있을것이다.

그 외 여러 git 작업들은 git repo 디렉토리에서 할 수 있다. 이 디렉토리는 git 디렉토리여서 아무 작업이나 가능하다. 또한 overlay 기능이 있기 때문에 여기에서 새로 파일을 만들거나 수정을 해도 되긴된다.

[email protected]:/var/lib/gitfs/tmp2tdrnypq# ls
dist  test.pyc  test_upload
[email protected]:/var/lib/gitfs/tmp2tdrnypq# git status
On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean

혹시라도 Merge 충돌이 발생하면 여기 디렉토리로 들어와서 mergetool을 실행해야 한다.

GitFS의 사용 예

GitFS로 여러 서버에 파일을 배포한다고 생각해 보자. 가장 먼저 해야할 것은 브랜치를 분리하는것이다. GitFS는 설정된 주기마다 원격 리포에서 파일을 가져온다. 때문에 개발/메인 브랜치를 거는것은 검증안된 코드마저 서버에 들어올 수 있게 한다. 미완성인 코드가 흘러 들어올 수도 있다. 때문에 배포용 리포를 만들어서 검증된 코드만이 배포되도록 해야한다.

다음은 fetch interval동안 여러개의 버전이 공존할 수 있음을 생각해야 한다. 설정에 따라서 fetch 주기를 줄일수는 있지만 완전 동시에 fetch가 되는것은 아니다. 그렇기 때문에 버전에 민감한 프로그램의 경우 대책을 마련해야 한다.

그리고 각 서버별로 있는 설정파일을 분리할 수 있게 해야한다. GitFS에 설정파일을 저장하면 그것 마저 commit되어 push된다. 그렇기 때문에 서버별로 설정해야 할 것들이 있으면 미리미리 분리하는 작업이 필요하다. 서버별 동작이 충분히 독립적이라면 서버별로 브랜치를 만들수도 있다. 메인 브랜치에서 각 서버 브랜치로 Merge 하는것으로 배포하는 것이다. 이 경우, 설정파일과 각 서버내에서 커스텀 한 코드를 손 쉽게 버전관리 할 수 있다.