월별 글 목록: 2013년 11월월

LGU+ 아이패드 개통(OPMD를 기준으로)

가상망 사업자를 제외하고, 우리나라에서 무선통신을 제공하는 사업자는 세군데가 있다. 익히 알려진대로 SKT, KT, LGT.
정식명칭은 따로 있지만 편의상 저렇게 쓰기로 하자.

여튼 이 세 통신사중에 해외 단말기를 도입못하는 회사가 있었으니 LGT가 그 주인공.
CDMA, 그것도 국제표준과 동떨어져서 주파수블럭이 5MHz 옆으로 빗겨 있는 탓에 단말기 도입이 겁나게 불리한 상황.
게다가 딱히 도입의지도 없어 보였고.

여하튼 그렇게 군소리 찡찡거리다가, LGT용 LTE브릿지 유심을 넥서스7에 냅다꽂으면 망에 잘 붙는다는 소식을 알게 되었다.
당연하지만 LTE only이고, LTE 커버리지를 벗어나면 CDMA fallback은 되지 않는다. 넥7에서 LGT CDMA를 지원 안하니까.

댓글 보니까 아이패드 미니도 LTE 망에 붙는다고 한다. 즉슨 LGT 전산에서 막을 뿐이지 단말기 접속은 가능하다는 결론.
국내 정발된 아이패드4 LTE모델 (A1460)은 LTE 주파수 2100 MHz(LGT), 1800 MHz(SKT, KT), 850 MHz(SKT, LGT) 을 모두 지원한다.

시간은 흘러, 지난 10월말에 어쩌다보니 베가아이언을 LGT로 개통하게 되었다. 짤없이 석달열흘동안 통화무제한69요금제를 써야 하는 상황.
한달 평균 데이터사용량이 2GB를 밑돌다보니, 69요금제의 5GB 데이터는 도통 쓸모가 없다- 테더링이나 하자- 하는 와중에
LGT도 해외단말기의 LTE OPMD를 허용한다는 소식을 듣게 되었다.

타이밍 좋구나~ 아이패드4 있는거 붙여보자 하고 냅다 트위터에 문의. 트위터 답변이니까 아래에서 위로 읽도록 하자.

LGT 답변

그렇다고 합니다.

가능하댄다. 자세한 정보는 114로 문의~라길래 냅다 전화질.

안된대

아니이게 무슨소리요 상담사 양반 내가 내부전산 자료도 봤고 트위터로도 컨펌을 받았는데!
상담사 주장은 그런 공지 받은 적 없다, 홈페이지에 공지된 7개 단말기만 데이터쉐어링 가입이 가능하다고 한다.

말이 다르잖아. 트위터로 재문의. 역시나 이번에도 아래에서 위로 읽자.

LGT 답변

그렇다고 합니다.

아 그러세요, 하고 다시 114 전화. 다른 상담원이 받더니 알아보고 다시 전화준댄다.
20분쯤 후 아이패드4는 가능하다는 답변과 함께 단말기 전산등록이 필요하니 단말 OS 및 버전정보, IMEI, WiFi MAC 정보를 문자로 보내달랜다.

019114

베가아이언 720p 스크린

전산등록에는 최장 24시간까지 걸린다던데 실제로는 한시간 반만에 전산등록 완료 문자가 왔다.
모델명(OM-VTPAD)과 일련번호를 알려주는데, 이걸 들고 가까운 대리점에 가서 등록하면 OK.
대리점 달려가서 데이터쉐어링이 어쩌고저쩌고 주저리주저리 말을 하니

모른댄다

정책 풀린지 며칠 되지 않은 상황에서는 전산공지가 제대로 안 되어 있으니 이런 사태가 벌어진다.
하여 이번에 전산이 풀렸으니까 해봐라, 기존에 단말기 데이터쉐어링 가입하는 것처럼 하되 단말정보만 이거로 입력하면 된다 식으로
내가 직원을 교육하는 사태를 연출하면서 가입 진행.

그렇게 일단 쉐어링회선 개통은 성공하였으나, 대리점 직원이 또 태클을 걸어오니, “LTE 요금제만 데이터쉐어링 가능하세요 고갱님”
지들 자료에는 “LTE요금제만 가입가능”으로 되어 있는데 LTE요금제는 “LTE34에서 LTE120을 의미”한다는 것이 대리점 직원의 요지.
이쯤되면 슬슬 짜증나기 시작한다. 그럼 통화무제한69요금제는 LTE 요금제 아니냐 식으로 지랄지랄 하기를 10여분.

피곤하고 늦은 시간에 싸우기 귀찮으니 즉석에서 114 전화. 대리점직원 설명이 맞냐 맞으면 69요금제 3개월 제한인데 뭐로 바꿔야되냐 이야기하니까
114 상담원 왈 “무제한69요금제도 데이터쉐어링 가능하세요”

아 더이상 싸우기도 귀찮다, 대리점 직원에게 휴대폰 넘기고 니들끼리 알아서 싸우고 해결봐라 하고 대리점에 비치된 커피나 뽑아마시기 시작.
그렇게 세 잔쯤 마시니까 전산 정리가 끝났다며 유심 따서 넘겨주더라. 꽂아보니 KOR LGUplus 잘 뜬다.

OK 하고 귀가…귀교? 여튼 연구실로 돌아왔다. 패드 충전기 꽂고 데이터통신 시도해 보는데-

안되잖아?

주말을 허송세월하고 오늘 다시 대리점 방문하여 유심초기화를 다시 진행하고 해보니까 잘 붙는다.
아이패드는 전화기능이 없어서 나밍(유심에 번호를 심는 작업)이 불가능 -> 망접속 불가 상황이 벌어졌던 것.

LG U+ LTE

그렇다고 합니다.

LGT LTE가 대역폭이 좁아서 타 통신사 대비 속도는 썩 만족스럽지 않지만 뭐 그냥저냥 쓰기에는 괜춘한 편.
다만 LTE 권외이탈 = 통신절단이라 좀 아쉽긴 하다. CDMA fallback도 안 되니까.

SVN to git 이전하기, 윈도우 환경을 기준으로.

Reference: http://john.albin.net/git/convert-subversion-to-git

한동안 개발에 SVN을 사용하다가, 최근들어 git을 사용하면서 옮겨가게 되었다.

SVN 대비 git 장점.

1. 저장소(의 완전한 복사본)가 로컬에 있어서 네트워크 접속이 필요없고 속도가 빠르다.
로컬에서 작업 끝나면? 브랜치 정리하고 로컬->서버로 밀어넣던지(push), 아니면 서버에서 로컬 데이터를 당겨가도록 요구(pull request)할 수도 있다.

2. 저장소 사본을 내가 들고 있으므로 브랜치 작업이 자유롭다. 그냥 브랜치 따서 쓰면 된다. 로컬 저장소는 온전히 내 소유이기 때문.
반면 SVN은 서버에 커밋권한이 없으면 브랜치 따는게 불가능하다. 물론 로컬 저장소를 만들면 되지만… 서버와 동기화가 귀찮아진다.

3. 브랜치 사이에 merge 관리가 쉽다.
SVN에서는 내가 어디에서 어디까지 merge했는지가 명확하지 않지만(기록은 된다), git에서는 어느 커밋과 어느 커밋을 merge했는지 명확하게 기록이 남는다.
애당초 git 구조상 merge 이력이 남을 수밖에 없다. 굳이 안 남길 수도 있지만, 다른 사람 – 내지는 두 달 후의 자신에게서 욕을 좀 먹을 것이다.

그 외에도 개념이나 장단점은 다른데에도 자료가 많이 있으니까 넘어가기로 하고.
여하튼 이번 포스팅에서는 SVN으로 구성된 저장소를 git으로 마이그레이션 하는 방법을 소개한다. 윈도우 환경을 기준으로.

굳이 마이그레이션을 강조하는 이유는, 절차를 완료한 후에는 SVN 저장소를 더이상 사용하지 않고 git으로 버전관리를 할 것이기 때문.
git-svn은 SVN을 리모트 서버로, 로컬에서는 git을 사용하는 것을 전제로 만들어져 있지만, 이중 뻘짓은 사양하기로 하자.

이 글을 읽는 사람이 SVN, git의 사용법은 알고있다고 가정하겠다. 윈도우 콘솔 명령어도.

1. 마이그레이션 할 SVN 저장소를 준비한다.

작업도중 IDPW를 지정할 수는 있지만, 가능하다면 Everyone에게 읽기권한은 주는 것이 좋겠다.

2. SVN 저장소의 Log를 보면서, committers list를 준비한다.

링크된 글에서는 SVN 작업사본에서 쉘 스크립트 명령어를 이용해서 committer list를 뽑아낸 모양이지만, 윈도우에서는 못 써먹는다.
나는 그냥 손으로 만들었다. 서버 committer가 10명이 채 안돼기 때문에 굳이 쉘 스크립트 짤 필요도 없었고.

committer list는 일반 텍스트 파일로 저장되며, 다음과 같은 형태를 가진다. 파일이름은 편의상 svn_authors.txt 로 저장하자.

[SVN USERNAME] = [GIT USERNAME] <[email protected]>
committer001 = John Doe <[email protected]>
committer002 = Jane Doe <[email protected]>

3. SourceTree를 설치한다.

http://www.sourcetreeapp.com/

git이 리눅스 커널 개발을 위하여 설계된 물건인지라, 윈도우 환경에서 git쓰기는 꽤나 지저분하다.
애당초 이건 모든 (리눅스를 기반으로 개발된) 오픈소스 어플리케이션의 문제이기도 하지만.

여튼 윈도우에서 git을 편하게 사용하려면 프론트엔드를 써야 하는데, 그나마 현 시점에서 안정적이고 깔끔한게 SourceTree인 것 같다.
그래프 방식으로 branch history를 쭉 보여주는데 이만한 툴이 없는 듯. 굳이 윈도우에서 GUI환경을 포기할 이유가 있을까.
(GitHub 클라이언트는 History View가 안 나오는거같다.)

git 라이브러리는 SourceTree 내장으로 설치하면 된다. 18. Nov. 2013 현재 git 버전은 1.8.3 이고 이 글도 해당 버전을 기준으로 설명한다.
SourceTree 설치가 완료되면 툴박스에서 Terminal 버튼을 눌러 git 터미널을 열고, 작업할 수 있는 임시폴더로 이동한다. MinGW 환경으로 실행될거다 아마.

4. git-svn으로 SVN 저장소를 git 저장소로 변환

명령어는 다음과 같다.

git svn clone http://svn_server/project_name/ –no-metadata -A svn_authors.txt -T trunk -b branches -t tags ./temp

옵션을 풀어 설명하자면 다음과 같다.

git svn clone : SVN 서버에서 복제해서 git 저장소를 생성한다. 밑에서 설명하겠지만 clone = init + fetch 이다.
http://svn_server/project_name/ : 프로젝트 최상위 폴더. 통상적으로 이 밑에 trunk, branches, tags 폴더가 위치한다.
–no-metadata : git-SVN 연동을 위한 메타데이터를 생성하지 않는다. 마이그레이션을 목적으로 하므로 메타데이터를 생략하는 것.
-A svn_authors.txt : 3번에서 만든 committers list
-T trunk -b branches -t tags : 트렁크, 브랜치, 태그 폴더명. 참고로 위에 표시된 것과 같은 표준 사양인 경우 –stdlayout 으로 대체 가능.
./temp : git 저장소가 만들어질 폴더이름

5. 인내심을 가지고 기다린다.

변환 과정은 짤없이 하나의 리비전을 체크아웃 -> git으로 커밋 과정을 반복하는 것이므로 시간이 꽤 걸린다.
리비전이 1천 단위를 넘어간다면 2~3시간 이상 걸릴 수도 있다. r50 정도 되는 저장소를 변환하는데 2분 정도 걸린 것 같다.

폴더구조가 이상하게 꼬여있지 않고 브랜치/태그를 svn copy로 정확하게 만들었다면 그럭저럭 잘 인식해서 브랜치를 만들어 준다.
브랜치 병합 또한, svn-props에 merge 정보가 기록되어 있다면 이를 반영해서 merge commit을 생성해 준다.
정보가 없으면? git에서 merge commit으로 기록은 안 된다. 뭐 트렁크에 병합된건 사실이니까 git에서도 데이터는 남겠지만 추적이 안 될 뿐이다.

변환 도중 알 수 없는 committer가 발견되면 그 시점에서 변환이 중단된다. committer list를 업데이트해야 한다.
겪어보지는 않았지만(말했다시피 서버에 커미터가 10명이 채 안된다), 중단된 시점 이후로는 git svn fetch 명령어로 이어서 작업이 가능할거다.

6. 브랜치/태그 정리

시간이 흘러 작업이 완료되면, SVN 저장소는 git 저장소로 변환된 것이며 더 이상 SVN 저장소는 필요가 없다.
이제 SourceTree로 마이그레이션 된 git 저장소를 열어보자. SVN trunk에 해당하는 git master 브랜치가 체크아웃 되어 있을 것이다.

문제는 브랜치, 그리고 태그. 우선 브랜치부터 해결하자.
git 저장소로 변환되긴 했지만, SVN 브랜치는 기본적으로 로컬에 체크아웃 되어 있지 않다. 따라서 수동으로 한 번씩 체크아웃을 해 줘야 한다.

그 다음은 태그. SVN에서는 브랜치나 태그나 원리만 놓고보면 그냥 svn copy 명령을 수행한 것일 뿐이다. 단지 특수한 폴더에 넣어둔 것일 뿐.
따라서 각각의 SVN 태그도 git 입장에서 보자면 그냥 하나의 (delta가 없는) 브랜치 커밋으로 취급될 뿐이다. 물론 브랜치 이름 대신 태그가 달려있지만.
이를 깔끔하게 정리해준다. 필요한 커밋에 git 태그를 달아주고, 불필요하게 생성된 SVN 태그용 브랜치를 삭제한다.

7. 저장소 재복사

이렇게 정리한 저장소는 아직 SVN 관련 옵션이 남아있어서 지저분할 수 있다.
그냥 써도 좋지만 좀 더 깔끔하게 쓰고 싶은 경우, 아니면 다시 서버에 올리려는 경우는 저장소를 다시 복사해야 한다.

작업 자체는 간단하다. SourceTree 툴박스에서 Clone 을 선택하고, Source Path에 마이그레이션 된 git 저장소 폴더를 지정하면 된다.
Clone 작업이 완료되면 이제 SVN 이력이 깨끗하게 정리된 git 로컬 저장소를 얻게 된다.

뻘짓1. 특정 revision 무시하기

변환을 하다보면, SVN에서 특정 revision을 무시해야 하는 경우가 생긴다. 보통은 잘못된 커밋을 reverse-merge한 경우로, 여러 개의 커밋이 상쇄되어 없던게 되는 경우.

예를 들어

예를 들어 SVN에서 브랜치를 삭제하고 다시 생성한 경우. 아직 git에서 인식을 못한다.

브랜치 생성을 r21에서 해야 하는데 r20에서 잘못 한 경우를 생각해 보자. 그래서 브랜치를 지우고(r23), 올바르게 다시 생성했다(r24).
그냥 r21을 merge하면 되지 않아? 라고 생각할 수도 있겠지만, 커밋로그를 바꿀 수도 없는 노릇이니까 그냥 넘어가자.

이런 경우, 사용자가 의도하는 git history는 다음과 같을 것이다.

근데 정작 git svn으로 변환해 보면, 브랜치 삭제를 제대로 인식 못하고 다음 그림과 같은 결과물이 나오게 된다.

불필요한 r22가 생성된 것도 있고 r24가 merge로 취급되어 히스토리가 복잡하게 꼬이게 된다. 트래킹 되니까 merge에는 문제없잖아-라고 생각하면 뭐 할 말은 없겠다만.

접기

여하튼, 위와 같은 경우도 있고 그 외에 다양한 사유로 특정 revision을 git으로 보내고 싶지 않은 경우가 발생한다.

아쉽지만, 아직 git-svn 명령줄에서 “SVN의 특정 revision을 제외하고 fetch하는” 옵션은 없다. 반대로 말하자면, “SVN의 특정 revision만 fetch하는” 옵션은 있다.
위의 예시를 들자면, r22, r23을 삭제해야 하는 경우인데 그렇다면 BASE:r21, 그리고 r24:HEAD를 fetch하면 되는 것.

5번 과정에서 명령어에 옵션이 추가된다.

git svn clone (blahblah) -t tags -r BASE:21 ./temp
git svn fetch -r 24:HEAD

명령이 둘로 나뉘고, 옵션이 하나 추가되었다.

git svn fetch: 정확하게는 이 명령어가 svn으로부터 데이터를 가져오도록 하는 명령이다. clone = init + fetch 인 축약 명령.
-r START:END : START에서 END까지의 리비전만 가져오도록 제한하는 옵션. START와 END의 리비전을 포함한다.

즉, 두 번에 걸쳐서 데이터를 가져오게 하는 것.
첫 번째 명령에서 BASE~r21까지의 리비전을 가져오고, fetch로 r24~HEAD 리비전을 가져옴으로써 불필요한 r22, r23을 생략하게 된다.

필요한 경우 더 잘게 쪼개서 여러 개의 불필요한 리비전을 생략할 수도 있다. 응용은 직접. 물론 신중하게 잘 사용해야 한다.
잘못 사용하는 경우 커밋 순서나 브랜치가 꼬이게 되며, 최악의 경우 git 저장소를 삭제하고 처음부터 다시 작업해야 할 수도 있다.

뻘짓 2. SVN 저장소 구조가 이상한 경우

Reference : http://www.jeremyjohnstone.com/blog/2010-01-14-using-git-svn-with-non-standard-subversion-repository-layouts.html

보통 SVN 저장소는 안정화 배포버전인 trunk, 문제 해결이나 개발용 사본인 branches, 과거의 특정 버전을 손쉽게 찾아보기 위한 tags 로 구성된다.
형상관리가 10년이 넘도록 사용되면서 그 효율성을 인정받아서 자연스럽게 굳어진 형태이지만, 꼭 저장소가 이렇게 구성되라는 법은 없다.
(SVN 저장소는 저런거를 따로 관리해 주지 않고 그냥 통째로 형상을 기억한다.)

프로젝트 여러 개가 저장소를 공유하는 경우

프로젝트 여러 개가 저장소를 공유하는 경우가 대표적인데, 보통은 저장소 루트에 프로젝트 폴더를 생성하고 그 밑에 stdlayout을 생성하게 된다.
그러니까 아래같은 경우. 이 때는 그냥 full 주소를 쓰면 된다. –prefix=PROJECTxx/ 옵션을 써도 되지만, 이 경우 마지막 백슬래시를 꼭 붙여줘야 한다.
git으로 마이그레이션 후, commonlib를 서브프로젝트로 등록하는 것은 이 글의 범위를 벗어나므로 생략하도록 한다.

/PROJECTxx/trunk
/PROJECTxx/branches
/PROJECTxx/tags

/PROJECTyy/trunk
/PROJECTyy/branches
/PROJECTyy/tags

/commonlib/trunk
/commonlib/branches
/commonlib/tags

접기

문제는 저장소가 저런 stdlyaout을 벗어나는 경우.

잘못된 레이아웃의 예시

링크 건 참조사이트는 이런 구조 때문에 엿을 먹었다고 한다.

trunk/PROJECTxx
trunk/PROJECTyy
trunk/commonlib

branches/PROJECTxx
branches/PROJECTyy
branches/commonlib

tags/PROJECTxx
tags/PROJECTyy
tags/commonlib

그 외에 내가 겪은 케이스는, 막 SVN 도입당시에 생성된 repo라서 아예 stdlayout 구조 없이 썼던 프로젝트가 있다.
따로 trunk/branches/tags를 구분하지 않고 마일스톤 달성시점마다 새롭게 브랜치를 따고, 기존 브랜치는 개발 중단하는 식으로 사용한 것.

/PROJECT
/PROJECT_rev2
/PROJECT_rev3

접기

여하튼 이런 경우는 git에서 브랜치를 파악하지 못하므로, 사용자가 직접 브랜치를 명명해 줘야 한다. 우선 git-svn 저장소부터 만들자.

git svn init http://svn_server/project_name/ –no-metadata -T PROJECT ./temp

이렇게 하면 ./temp 폴더에 비어 있는 git 저장소가 만들어진다. 이제 ./temp/.git/config 파일을 텍스트 편집기로 연다.

(생략)
[svn-remote “svn”]
noMetadata = 1
url = http://svn_server/project_name
fetch = PROJECT:refs/remotes/trunk

fetch 뒤쪽에 다른 브랜치 경로들을 추가해준다.

(생략)
[svn-remote “svn”]
noMetadata = 1
url = http://svn_server/project_name
fetch = PROJECT:refs/remotes/trunk
fetch = PROJECT_REV2:refs/remotes/rev2
fetch = PROJECT_REV3:refs/remotes/rev3

이렇게 하면 각각의 SVN branches가 git branches로 온전히 인식된다. 이제 fetch하면 된다.

git svn fetch -A svn_authors.txt

뻘짓 3. 비어 있는 commit 제거하기

SVN에서 브랜치나 태그를 따는 커밋은 파일 구성에는 변화가 없는 커밋이다. (다시 말하지만, SVN에서 브랜치, 태그는 단순한 cheap copy일 뿐이다.)
git으로 변환된 커밋로그를 보면, (아마도 create branch for issue #nnnn 따위의) 커밋 메시지는 남아있지만 정작 파일 변경점은 전혀 없는 커밋이 존재하게 된다.

물론 이것도 지울 수 있다. git이 재미있는 점이 과거 커밋도 강제로 수정 가능하다는 점.
각각의 커밋이 독자적으로 완벽한 하나의 형상으로 존재하며, 커밋간의 관계를 포인터로만 구성하기 때문에 이런 뻘짓이 가능하다.

저장소에서 터미널을 열고 다음 명령을 수행하면 파일 변경점이 없는 커밋을 찾아서 몽땅 삭제해 준다.
단, 부모 커밋이 딱 하나인 경우에만 삭제 가능하다. 부모가 둘 이상인 merge 커밋이나 0개인 Initial 커밋은 삭제 안 된다.

git filter-branch –prune-empty — –all

git filter-branch: 브랜치에 필터를 적용한다.
–prune-empty : 빈 커밋을 잘라낸다. (prune 뜻이 가지치기 한다는 뜻임)
— –all : 모든 커밋에 적용하도록 한다. 이거 안 쓰면 다른 브랜치에는 변경사항이 적용 안 되므로 커밋 그래프가 아주 형이상학적으로 바뀌게 된다.

사실 이런 “과거 커밋을 건드는” 명령은 잘못 쓰면 저장소 망가뜨리기 일쑤다. 거의 모든 커밋의 SHA-1 해시가 바뀌므로 히스토리가 꼬이거나 할 가능성이 높다.
특히 태그같은 경우는 거의 전부 새로 작업해 줘야 할거다. 어짜피 SVN 태그를 옮겨오려면 git에서 새로 만들어야 하긴 하지만.

아, SHA-1 해시가 모두 바뀐다고 하였다. 따라서 다른사람하고 공유를 시작한 저장소에서는 절대 쓰지 마라.