EXQT EXQT

SVN에서 Git으로 이전하기

2026-06-20

팀에서 SVN에서 Git으로 전환하는 업무가 백로그로 계속 남아 있어, 시간이 날 때 진행해 보았습니다. 실제로 진행한 방법과 그 과정에서 겪은 트러블슈팅을 정리했습니다.

git svn

Git에는 SVN 저장소와 Git 저장소 사이를 연결해 주는 git svn 명령어가 있습니다. 원래는 SVN 저장소와 양방향으로 작업하기 위한 도구지만, SVN 히스토리를 Git 저장소로 옮기는 용도로도 사용할 수 있습니다.

git svn clone <SVN 저장소>

SVN 프로젝트 레이아웃

SVN에서는 trunk, branches, tags를 실제 path 형태로 저장합니다. 저장소 루트 아래에 이 세 path가 있는 형태를 보통 standard layout이라고 합니다.

repository/
  trunk/
  branches/
  tags/

이 구조라면 --stdlayout 옵션을 사용하면 됩니다.

git svn clone --stdlayout <SVN 저장소> <path>

하지만 저장소가 standard layout을 따르지 않는 경우에는 경로를 직접 지정해야 합니다. --trunk, --branches, --tags는 SVN 저장소 안에서의 상대 경로를 넣는다고 생각하면 편합니다.

git svn clone <SVN 저장소> 
  --trunk=Project/trunk/Main 
  --branches=Project/branches 
  --tags=Project/tags 
  <path>

팀원 이름 리스트 authors.txt 준비

SVN에서는 커밋 작성자 정보가 사번 ID나 계정명으로만 남아 있는 경우가 많습니다. Git에서는 작성자를 이름 <이메일> 형식으로 저장하므로 이를 매핑해 주는 authors.txt 파일이 필요합니다.

ab12345 = 홍길동 <ab12345@example.com>
ab12347 = 김철수 <ab12347@example.com>
ab13642 = ab13642 <>

이 파일에 없는 작성자가 나오면 변환이 중단됩니다. 에러 메시지에 누락된 ID가 나오므로, 해당 ID를 authors.txt에 추가한 뒤 다시 이어받으면 됩니다.

git svn clone <SVN 저장소> --authors-file=authors.txt

주의할 점은 git svn이 authors 파일의 왼쪽 값을 정확히 매칭한다는 것입니다. SVN 로그에 ab12345, AB12345처럼 대소문자만 다른 ID가 섞여 있다면 각각 추가해야 할 수 있습니다.

ab12345 = 홍길동 <ab12345@example.com>
AB12345 = 홍길동 <ab12345@example.com>

이메일을 모르는 경우에는 비워 둘 수는 있지만, 이후 Git 호스팅 서비스에서 작성자 연결이 안 될 수 있으므로 가능하면 회사 계정이나 실제 이메일로 맞춰 두는 편이 좋습니다.

revision 범위 지정

전체 변환 중 특정 revision에서 계속 실패하는 경우가 있습니다. 이럴 때 처음부터 전체를 받기보다 특정 범위만 내려받아 문제가 되는 구간을 좁히면 트러블슈팅이 편합니다.

git svn clone -r1234:1345 <SVN 저장소> <path>

-r 뒤에는 시작 revision과 끝 revision을 :로 연결합니다. 시작 revision만 고정하고 최신까지 받고 싶다면 다음처럼 쓸 수 있습니다.

git svn clone -r1234:HEAD <SVN 저장소> <path>

이어 받기

변환 프로세스가 도중에 중단된 경우에는 생성된 Git 저장소 path로 이동한 뒤 git svn fetch를 실행하면 이어받을 수 있습니다.

cd <path>
git svn fetch

작성자 누락처럼 설정을 보완한 뒤 다시 실행할 수 있는 오류라면, 대체로 처음부터 다시 받을 필요 없이 git svn fetch로 이어갈 수 있었습니다.

Trouble Shooting

받고 싶지 않은 revision 무시

변환이 실패하여 SVN 로그를 확인해 보니, 실수로 잘못된 경로에서 브랜치를 복사해 온 revision이 문제인 경우가 있었습니다. 이런 경우 특정 branch나 tag ref를 제외하고 가져오도록 설정할 수 있습니다.

--ignore-refs는 branch나 tag ref 이름에 대해 Perl 정규식을 적용합니다. 단순 경로 문자열이 아니라 refs/remotes/... 형태의 ref에 매칭된다는 점을 주의해야 합니다.

git svn clone <SVN 저장소> 
  --stdlayout 
  --ignore-refs='^refs/remotes/origin/broken-branch$'

소스 코드에 포함할 필요가 없는 빌드 결과물, apk, 압축 파일 같은 경로는 --ignore-paths로 제외할 수 있습니다. 이 옵션도 정규식을 사용합니다.

git svn clone <SVN 저장소> 
  --stdlayout 
  --ignore-paths='(^|/)(Build|Temp|Library|.*.apk)$'

이미 clone을 시작한 뒤라면 .git/config[svn-remote "..."] 섹션에 ignore-pathsignore-refs 설정을 추가하고 git svn fetch를 다시 실행할 수도 있습니다.

Connection Reset

Connection reset by peer: Error running context: Connection reset by peer at C:/Program Files/Git/mingw64/share/perl5/Git/SVN/Ra.pm line 312

변환 도중 위와 같은 에러와 함께 중단되는 경우가 있었습니다. 제 경우에는 대부분 다시 git svn fetch를 실행하면 이어서 진행되었습니다.

그러나 큰 파일이 있거나 파일이 많은 경우 한 번에 가져오는 경우 지속적으로 실패하는 경우도 있었습니다. 이때는 --log-window-size를 낮춰 한 번에 가져오는 revision 수를 줄이는 방법을 시도 해볼 수 있습니다.

또는 아래의 git 설정을 적용해보는 것도 도움이 되었던 것 같습니다.

git config --global http.postBuffer 2048M
git config --global http.maxRequestBuffer 1024M
git config --global core.compression 2

git config --global ssh.postBuffer 2048M
git config --global ssh.maxRequestBuffer 1024M

git config --global pack.windowMemory 1024M
git config --global pack.packSizeLimit 1024M

BFG Repo Cleaner

변환을 완료한 뒤 Git 저장소에 업로드하려는데, 과거 히스토리에 500MB 이상의 큰 파일이 남아 있어 push가 불가능한 경우가 있었습니다. 현재 최신 커밋에는 포함되어 있지 않더라도, Git은 히스토리의 객체를 함께 전송하므로 과거 커밋에 큰 파일이 남아 있으면 문제가 됩니다.

이번 경우에는 실수로 빌드 파일이나 .unitypackage가 SVN에 올라간 적이 있었습니다.

Git에서 히스토리를 재작성하려면 git filter-repo를 사용할 수 있습니다.

git filter-repo --strip-blobs-bigger-than 500M

다만 몇 만 개 이상의 커밋을 가진 저장소에서는 시간이 오래 걸릴 수 있습니다. 큰 파일이나 민감한 텍스트 제거처럼 단순한 정리 작업이라면 BFG Repo-Cleaner도 좋은 선택지입니다.

BFG는 mirror clone을 기준으로 사용하는 것이 일반적입니다.

java -jar bfg.jar --strip-blobs-bigger-than 500M repo
cd repo
git reflog expire --expire=now --all
git gc --prune=now --aggressive

BFG는 기본적으로 최신 커밋의 파일을 보호합니다. 즉, 최신 커밋에도 큰 파일이 남아 있으면 과거 히스토리에서 제거되지 않을 수 있습니다. 먼저 최신 상태에서 문제 파일을 제거하고 커밋한 뒤 BFG를 실행하는 것이 좋습니다.

히스토리를 재작성하면 커밋 해시가 바뀝니다. 이미 다른 사람이 clone한 저장소가 있다면 기존 clone을 그대로 쓰지 말고 새로 clone하도록 안내해야 합니다. 기존 히스토리를 다시 push하면 제거한 큰 파일이 되살아날 수 있습니다.