형상 관리 도구(Configuration Management Tool)로서의 GIT
소프트웨어를 중심으로 하는 프로젝트에서 빈번하게 발생하는 이러한 문제를 해결하기 위해 등장한 도구가 바로 형상 관리 도구(Configuration Management Tool)입니다. 소프트웨어 공학의 프로젝트 진행 및 관리 방법에서 비중 있게 다뤄 지는 영역 중 하나이기도 합니다.
오늘날 많이 사용되는 형상 관리 도구의 두 축이 있는데, 바로 SVN과 GIT입니다. 한때 SVN이 널리 사용되었지만, 근래에 들어 GIT이 등장하고 나서부터 SVN을 사용하던 많은 기업들이 GIT으로 갈아타고 있는 추세라고 합니다.
SVN과 GIT은 모두 소스코드의 효율적인 관리를 위한 형상 관리 도구이지만, 비슷하면서도 많은 점이 다릅니다. 심지어 같은 용어도 서로 동작하는 개념이 다르기 때문에 SVN에서 GIT으로 옮겨 가는 프로그래머들이 많은 혼란을 느낀다고 합니다.
SVN과 GIT의 가장 큰 차이점을 나타내는 한 단어가 있는데, 바로 '분산'입니다. SVN은 중앙 집중식 소스코드 관리 방식인데 반해, GIT은 분산 소스코드 관리 방식입니다. 즉, GIT을 사용할 경우 중앙 저장소가 폭파되더라도 분산되어 있는 로컬 저장소를 이용해 중앙 저장소를 복원할 수 있습니다.
SVN과 GIT에 대해서는 상호 장단점에 대한 의견이 분분합니다.
GIT Guide
[ProGit 한국어판] http://git-scm.com/book/ko/v1
GIT을 사용하면 가능한 것들
- 소스코드 주고받기가 필요 없고, 같은 파일을 여려 명이 동시에 작업하는 등 병렬 개발이 가능해지며, 버전 관리가 용이해져 생산성이 증가합니다.
- 소스코드의 수정 내용이 커밋 단위로 관리되고, 패치 형식으로 배포할 수 있기 때문에 프로그램의 변동 과정을 체계적으로 관리할 수 있고, 언제든지 지난 시점의 소스코드로 점프(Checkout)할 수 있습니다.
- 새로운 기능을 추가하는 Experimental version을 개발하는 경우, 브랜치를 통해 충분히 실험을 한 뒤 본 프로그램에 합치는 방식(Merge)으로 개발을 진행할 수 있습니다.
- '분산' 버전관리이기 때문에, 인터넷이 연결되지 않은 곳에서도 개발을 진행할 수 있으며, 중앙 저장소가 폭파되어도 다시 원상복구할 수 있습니다.
- 비단 팀 프로젝트가 아닌, 개인 프로젝트일지라도 GIT을 통해 버전 관리를 하면 체계적인 개발이 가능해지고, 프로그램이나 패치를 배포하는 과정도 간단해집니다. (Pull을 통한 업데이트, Patch 파일 배포)
GIT 관련 주요 용어
GIT에 대해서 조금이라도 자료를 찾아보신 분들을 위와 같은 도표를 자주 접했을 것입니다. 이 도표는 GIT을 사용하면서 일어나는 트랜젝션들을 나타낸 것입니다.
뭔가 좀 복잡해 보이지만, 가장 중요한 트랜젝션을 한 문장으로 간단하게 요약하면 다음과 같습니다.
"작업한 내용을 스테이지에 올려서 로컬 저장소에 커밋하고, 이를 푸시해서 원격 저장소로 보낸다."
GIT과 관련된 용어는 많이 있지만, 여기에서는 GIT을 사용하기 위해 필수적으로 알아야 될 용어만을 설명해 드리도록 하겠습니다.
저장소 (Repository)
소스코드가 저장되어 있는 여러 개의 브랜치(Branch)들이 모여 있는 디스크상의 물리적 공간을 의미합니다.
원격 저장소만 있는 SVN과 달리, GIT에서는 저장소가 로컬 저장소(Local Repository)와 원격 저장소(Remote Repository)로 나뉩니다.
작업을 시작할 때 원격 저장소에서 로컬 저장소로 소스코드를 복사해서 가져오고(Clone), 이후 소스코드를 변경한 다음 커밋(Commit)을 합니다. 이 때, 커밋한 소스는 로컬 저장소에 저장되며, 푸시를 하기 전에는 원격 저장소에 반영되지 않습니다.
오픈소스코드 등을 구하려고 사이트에 방문하면 다음과 같이 git 이나 http 프로토콜로 시작하는 저장소 주소만 달랑 써져 있는 경우를 자주 접할 수 있습니다.
이전에는 오픈소스 코드를 배포할 때 버전별 압축파일 형태로 배포했으나, GIT이 등장한 이후 위와 같이 저장소를 통해 배포하는 경우가 많아졌습니다.
위와 같이 임의의 사용자가 마음대로 다운받을 수 있도록 공개된 저장소가 있는 반면, 인증된 사용자만 접근할 수 있는 비공개 저장소도 있습니다.
단, 공개된 저장소일지라도 저장소의 다운로드만 가능하며, 수정된 코드를 저장소에 반영하기 위해서는 저장소 관리자의 허가를 받고 SSH 키를 등록해야 합니다.
체크아웃 (Checkout)
특정 시점이나 브랜치의 소스코드로 이동하는 것을 의미합니다. 체크아웃 대상은 브랜치, 커밋, 그리고 태그입니다. 체크아웃을 통해 과거 여러 시점의 소스코드로 이동할 수 있습니다.
cf. SVN의 체크아웃
SVN에서는 체크아웃이 원격 저장소의 파일을 작업하기 위해 로컬로 가져오면서 동시에 다른 사람이 수정할 수 없도록 Lock을 거는 과정을 의미하며, GIT에서의 체크아웃과는 전혀 다른 의미입니다.
스테이지 (Stage)
작업한 내용이 올라가는 임시 저장 영역입니다. 이 영역을 이용하여 작업한 내용 중 커밋에 반영할 파일만 선별하여 커밋을 수행할 수 있습니다.
커밋 (Commit)
작업한 내용을 로컬 저장소에 저장하는 과정입니다. 각각의 커밋은 의미 있는 변경 단위이고, 변경에 대한 설명을 커밋 로그로 남깁니다. 대개 하나의 커밋은 '회원 가입 기능 추가', '검색 버그 수정'과 같이 하나의 주제로 묶을 수 있는 변경 단위가 됩니다.
프로젝트 팀에 따라 커밋을 하는 단위가 서로 다르고, 커밋 로그를 작성하는 형식(Format)도 정해져 있습니다. 특히, Continuous Build System과 같이 원격 저장소와 연동된 자동화 시스템을 사용하고 있는 경우, 이 자동화 시스템이 인식할 수 있도록 엄격한 형식에 맞춰서 커밋 로그를 작성해야 할 수도 있습니다.
태그 (Tag)
커밋의 임의 위치에 쉽게 찾아갈 수 있도록 붙여놓은 이정표를 태그라 합니다. 태그가 붙여진 커밋은 Commit ID 대신 태그명을 입력하여 쉽게 체크아웃 할 수 있습니다.
푸시 (Push)
로컬 저장소의 내용 중 원격 저장소에 반영되지 않은 커밋을 원격 저장소로 보내는 과정입니다.
cf. SVN의 커밋과 푸시
SVN에서의 커밋은 변경 사항을 원격 저장소로 저장하는 과정을 의미합니다. GIT에서의 커밋은 로컬 저장소로 변경 사항을 반영하는 것을 의미하며, 원격 저장소로 변경사항을 보내는 과정은 푸시입니다.
즉, 'SVN의 커밋 = GIT의 커밋 + GIT의 푸시' 라고 할 수 있습니다.
풀 (Pull)
푸시와 반대로 원격 저장소에 있는 내용 중 로컬 저장소에 반영되지 않은 내용을 가져와서 로컬 저장소에 저장하는 과정을 의미합니다. 이를 통해 다른 팀원이 변경하고 푸시한 내용을 로컬 저장소로 가져올 수 있습니다.
푸시 과정에서 충돌(Collision)이 일어나서 푸시가 거절된 경우, 풀을 통해 원격 저장소의 변경 내용을 반영한 뒤 다시 푸시를 시도해야 합니다.
브랜치 (Branch)
커밋을 단위로 구분된 소스코드 타임라인에서 분기해서 새로운 커밋을 쌓을 수 있는 가지를 만드는 것, 혹은 그 가지를 브랜치라 합니다.
브랜치 중에 개발의 주축이 되는 브랜치를 마스터 브랜치(Master Branch)라 하며, 모든 브랜치는 마스터 브랜치에서 분기되어 최종적으로 다시 마스터 브랜치에 병합(Merge)되며 개발이 진행됩니다.
위 그림에서 서로 다른 색상으로 구분된 선들이 각각 하나의 브랜치를 의미합니다. 가장 오른쪽에 있는 빨간색 브랜치가 마스터 브랜치이며, 작업의 흐름을 보면 이 마스터 브랜치에서 분기된 뒤 최종적으로 다시 마스터 브랜치에 병합됨을 알 수 있습니다.
브랜치를 항상 마스터 브랜치에서 해야 한다는 제약은 없으며, 브랜치에서 또 브랜치를 할 수도 있습니다. 대개 프로젝트에서 브랜치는 프로그램 전체를 몇 개의 단위로 나눈 토픽 단위로 생성하며, 각 토픽 브랜치에서 개발자별로 새로운 브랜치를 생성하여 작업을 합니다. 개발자별로 작업한 내용은 토픽 브랜치에 병합되며, 최종적으로 마스터 브랜치로 병합되어 하나의 토픽이 종료됩니다.
cf. Fork
Branch와 유사한 용어로 Fork가 있습니다. GitHub와 같은 Social GIT 사이트에 보면 Fork 버튼이 있는 것을 많이 보셨을 것입니다.
리눅스에서 새로운 프로세스를 실행하는 방법 중 하나인 Fork는 이미 동작중인 프로세스를 복제해서 새로운 프로세스를 만드는 것을 의미합니다.
GIT에서의 Fork도 이와 유사한 개념이라고 할 수 있습니다. GIT의 Fork는 저장소를 복제해서 새로운 독립된 저장소를 만드는 작업을 의미합니다.
오픈 소스 프로젝트일지라도 소스코드의 메인스트림에 커밋을 반영하는 커밋터(Commiter)의 권한을 아무에게나 주지 않고, 대개 일정 기준을 통과해야 하는 경우가 많습니다. 대규모 오픈소스 프로젝트일수록 이 기준은 더 까다롭습니다.
공개된 오픈 소스 프로젝트를 자신이 프로젝트 매니저가 되어 입맛대로 수정하고 싶을 때 사용하는 기능이 바로 Fork입니다. 원격 저장소를 로컬 저장소로 복제한 뒤 새로운 원격 저장소에 푸시하는 과정을 한큐에 해결할 수 있도록 도입한 기능이 바로 Fork입니다.
병합 (Merge)
브랜치와 반대되는 개념으로, 하나의 브랜치를 다른 브랜치와 합치는 과정을 의미합니다.
두 개의 브랜치를 합쳐서 하나의 브랜치로 만드는 3-Way Merge가 모든 병합 작업의 기본이 됩니다. 병합의 대상이 되는 두 브랜치는 주종관계가 성립하며, 따라서 'A 브랜치와 B 브랜치를 병합한다'라는 말은 모호한 표현이 됩니다. 즉, 'A 브랜치를 B 브랜치에 병합'하는 작업과 'B 브랜치를 A 브랜치에 병합'하는 작업은 서로 다른 작업입니다.
병합도 엄연히 말하면 커밋의 한 종류입니다. 일반적인 커밋은 조상 커밋이 하나인 커밋인 데 반해, 병합의 조상 커밋이 둘 이상인 경우입니다. 즉, 3-Way Merge는 '서로 다른 두 커밋으로부터 하나의 새로운 새로운 커밋을 생성하는 작업'입니다.
병합 과정에서 두 개의 브랜치에서 파일의 같은 부분을 서로 다른게 수정한 경우 충돌(Collision)이 발생하며, 병합이 일시정지 됩니다. 이 경우, 충돌이 발생한 부분을 직접 수정하거나, Merge Tool 등을 활용하여 충돌을 해결한 뒤 병합을 계속 진행하면 됩니다.
보통 Merge 작업은 각각의 팀원이 수행하기 보다는 Project Manager가 일괄적으로 수행하는 것이 일반적입니다. 대개 한 브랜치의 작업이 끝나면 PM에게 Merge Request를 보내고, PM은 병합하기 전 해당 브랜치를 작업한 개발자와 함께 코드 리뷰를 진행한 뒤 이상이 없으면 마스터 브랜치에 해당 브랜치를 병합하는 작업을 수행합니다.
GIT 관련 웹 기반 솔루션
GIT의 원격 저장소를 가장 효율적으로 관리하는 방법은 바로 웹 기반 GIT 솔루션을 사용하는 것입니다.
이들 솔루션에서는 원격 저장소 관리 기능 뿐만 아니라 위키, 이슈 관리, 머지 요청 관리, 팀원 관리 등 전반적인 프로젝트 관리 기능도 함께 제공합니다. 웹 기반으로 동작하므로 브라우저만 있으면 접근이 가능하기 때문에 코드리뷰 등의 작업도 한층 수월하게 할 수 있습니다.
이러한 솔루션의 대표적인 예로 GitHub와 GitLab을 들 수 있습니다.
이 둘의 가장 큰 차이점은 폐쇄성 여부입니다. GitHub은 오픈소스 프로젝트에서 많이 사용되고, GitLab은 기업체 등에서 인트라넷에 설치하여 많이 사용합니다.
GIT을 가장 빠르고 효율적으로 배우는 방법
지금 이 글을 열심히 읽고 있을 여러분은 아마 이제 막 GIT에 입문하여 뭐가 뭔지 잘 모르는 분들이 많을 것입니다.
GIT은 공부해야 할 대상이 아니라 당장 프로그램을 만들면서 활용해야 할 '도구'의 성격이 강하기 때문에, 처음 입문하는 경우 대개 급한 마음에 구글링을 하거나 책을 뒤지는 경우가 많습니다.
GIT에 빠르게 익숙해지려면 책을 들여다보며 명령어 하나 하나 꼼꼼히 살펴보는것 보다는, 직접 프로젝트에 뛰어들어 부딪혀 보는 편이 훨씬 좋습니다. 아마 GIT을 처음 접하고, 공부한다고 책에 쓰여진 명령어를 들여다보면서 드는 생각은 대부분 다음과 같을 것입니다.
'그래, 이게 뭐 하는건지는 알겠는데 대체 언제 써먹는거야?'
실제로 형상관리 도구로 GIT을 사용하는 프로젝트 팀에 개발자로 처음 들어와서 필요한 명령어의 수는 그리 많지 않습니다. 원격 저장소에서 로컬 저장소로 복제하는 clone 명령어, 작업 내용을 스테이지에 올리는 add 명령어, 커밋을 작성하는commit 명령어만 알고 있어도 당장 작업을 시작할 수 있습니다.
브랜치를 생성하거나 병합하고, 커밋들을 재정렬하는 Rebase등의 작업은 대개 PM이 하는 업무이기 때문입니다. GIT 관련 고급 명령어들은 그 상황에 부딪혔을 때 그때 그때 배우는 편이 더 효율적입니다.
'Dev Environment > Git' 카테고리의 다른 글
GitLab 소개 (SSH 생성) (0) | 2016.05.12 |
---|---|
Git 리모트 저장소 (0) | 2016.02.02 |
Git branch(브랜치) (0) | 2016.02.02 |
Git 기초- 깃(git) 명령어 배워보기 (5) | 2016.02.01 |
VCS & Git/Github (0) | 2015.03.04 |