git에서 특정 파일만 남기기 (git 기반 위키에서 특정 파일만 공개하기)

코드저장소에서 실수로 절대 넣어서는 안되는 파일을 넣어 버렸을 때, git의 filter-branch 명령을 사용하면 간단하게 특정 파일만 제외시키고 전체 히스토리를 재구축하는 것이 가능하다.

그러나 반대로 특정 파일만 남기는 것은 조금 까다롭다. filter-branch를 응용해서 남기고자 하는 파일 외에는 모두 삭제하면서 히스토리 전체를 재구축하는 방법이 있긴 한데, 속도도 느리고 잘 동작하게 만들기도 쉽지가 않다.

사실 일반적인 소프트웨어 개발 프로젝트라면, 프로젝트에서 특정 파일만 남기겠다는 요구사항은 그렇게 흔하지 않을 것이다. 하지만 git은 소프트웨어 개발 프로젝트에서만 쓰이는 것이 아니다. 개발자노트골룸과 같은 위키시스템은 git 저장소에 위키페이지를 저장한다. 그리고 위키 사용자들은 개인위키로 관리하던 페이지에서 몇몇 페이지만 선별하여 공개적으로 publish하고 싶어한다.

git은 rcs나 cvs와는 달리 파일별로 버전관리를 하지 않기 때문에 이런 요구에 부응해주기가 참 어렵다. 하지만 불가능하지는 않다.

이런 경우 보통은 fiter-branch를 써서 불필요한 파일들을 제거하는 해법을 선택하겠지만, 여기서는 그보다 더 빠르고 보다 잘 동작하는 방법을 알아볼 것이다.

branch 만들기 및 checkout

filter-branch와 다른 방법인 것 처럼 이야기했지만, 사실 기본적인 접근은 같다. 히스토리를 바닥부터 쌓아가는 것이다. 우선 완전히 아무 커밋도 없는 브랜치 “public”를 만든다. –orphan 옵션을 사용하면 가능하다.

git checkout --orphan "public"

준비

그리고 이제부터 커밋을 하나하나 쌓아갈 것이니, 불필요하게 staging area에 파일이 남아있다면 모두 제거해버리자.

git rm --cached -r .

commit

그럼 이제부터가 진짜다. 이제 공개하고자 하는 파일에 대한 히스토리를 죽 뽑아서, 그에 대한 커밋만 커밋할 것이다.

다음과 같은 방법으로 특정 파일들에 대한 커밋의 목록을 얻는다.

filenames=file1 file2 file3
commits=`git log --reverse --format='%H' master -- $filenames`

--foramt='%H'를 주면 커밋로그 출력 옵션이 커밋 아이디만 출력하는 형태가 될 것이다. --reverse 옵션을 주는 이유는, 커밋 로그를 가장 오래된 것이 먼저 오게 출력하기 위함이다. 그 순서대로 커밋을 할 것이기 때문이다.

위에서 얻은 커밋들을 하나하나 커밋한다. 그 커밋들에서도 오직 공개하기를 원하는 파일만 뽑아내어 커밋한다.

for commit in $commits
do
git checkout -qf $commit -- $filenames
git add --ignore-errors $filenames
git commit -C $commit
done

push

마지막으로 이렇게 구축한 브랜치 “public” 를 원격저장소에 push하면, 내가 선정한 파일들만 push될 것이다. 아마도 이 push는 히스토리 전체를 뒤바꿀 것이므로, -f 옵션을 줘야만 할 것이다.

아래는 개발자노트에 공개하고자 하는 페이지들만 담긴 브랜치 “public”을 push하는 예이다.

git push -f http://npcode.com:3000/devnote/notes/note.git public:master

마무리

“publish” 브랜치는 더 이상 필요치 않으니 제거한다. 다음번에 또 publish를 하기 위함이다.

git branch -D "publish"

전체 소스코드

전체 소스코드는 아래와 같다. argument로 공개할 파일들을 지정해주면 알아서 브랜칭하고, 히스토리를 재구축하고, “public”이란 이름의 저장소로 push한 뒤, 그 branch를 삭제하기까지 해주는 쉘 스크립트이다.

filenames=$*
from=master
commits=`git log --reverse --format='%H' $from -- $filenames`
branch="pub-`date +'%y%m%d-%H%M%S'`"
git checkout --orphan "$branch"
git rm --cached -r .
for commit in $commits
do
git checkout -qf $commit -- $filenames
git add --ignore-errors $filenames
git commit -C $commit > /dev/null
done
git push -f public "$branch":master
git branch -D $branch

사용은 다음과 같이 하면 된다. 아래와 같이 실행하면 “git”, “linux”, “mac” 페이지만 공개하게 된다.

./pub.sh git linux mac
Advertisements

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

%s에 연결하는 중