2장. 클론 만들기

구식의 버전 관리 시스템에서는 체크아웃 명령어가 파일들을 가져오는 보편적인 방법이었습니다. 저장된 포인트로 부터 많은 파일들을 불러올 수 있죠.

Git을 포함한 다른 분산 제어 시스템에서는 클론만들기를 보편적인 방법으로 채택하고 있습니다. 파일을 얻기위해서는, 원하는 파일들이 저장되어있는 저장소에서 '클론'을 만들어야 합니다. 즉, 중앙 관리 서버를 미러링해오는 것과 같은 이치라고 설명할 수 있습니다. 주 저장소가 할 수 있는 모든 것들을 당신이 이제 할 수 있는 것이죠.

컴퓨터 동기화

기본적인 동기화 및 백업을 할 때 tarball을 만드는 것과 *rsync*명령어를 사용하는 것은 어느정도 견딜 수 있습니다. 그러나 저는 가끔씩 노트북에서 편집을 할 때도 있고, 데스크탑에서 할 때도 있는데, 이 두 개의 컴퓨터는 그리많은 대화를 나누지 않을지도 모릅니다.

한 컴퓨터에서 Git 저장소를 초기화하고 파일들을 commit함으로써 이 문제를 해결할 수 있습니다. 그 후 다른 컴퓨터에서:

$ git clone other.computer:/path/to/files

위 명령어를 이용해서 두 번째 파일/Git 저장소 사본을 만들 수 있습니다. 그 다음부터는,

$ git commit -a
$ git pull other.computer:/path/to/files HEAD

을 이용하여 현재 사용중인 컴퓨터로 다른 컴퓨터에 있는 파일들을 당겨올 (pull) 수 있습니다. 만약에 같은 파일에 대해서 전후가 맞지않는 편집을 했을 경우, Git은 당신에게 에러메세지로 먼저 이 모순을 해결 후 commit을 할 것을 알려줄 것입니다.

고전적인 소스 관리

우선 Git 저장소를 초기화 해줍니다:

$ git init
$ git add .
$ git commit -m "Initial commit"

그리고 중앙 서버에서, 아무 디렉토리에서나 간단한 저장소를 초기화 해줍니다:

$ mkdir proj.git
$ cd proj.git
$ git --bare init
$ touch proj.git/git-daemon-export-ok

필요하다면 Git daemon을 실행합니다:

$ git daemon --detach  # it may already be running

Git 호스팅 서비스를 한다면 우선 빈 Git 저장소를 만들어야 합니다. 대부분 웹페이지에서 어떠한 문서를 작성하곤 하죠.

다음 명령어를 사용해 당신의 프로젝트를 중앙서버로 '밀어넣기 (push)' 할 수 있습니다:
$ git push central.server/path/to/proj.git HEAD

소스를 확인하고 싶을 때에 개발자는 다음 명령어를 사용합니다:

$ git clone central.server/path/to/proj.git

편집이 끝난 후에 개발자는 다음명령어를 사용해 로컬드라이브에 각종 바뀐 사항들을 저장을 합니다:

$ git commit -a

가장 최신 버전으로 로컬파일들을 갱신하려면:

$ git pull

결합상의 곤란한 점들은 다음 commit 명령어를 사용하면 대부분 해결 될 것입니다:

$ git commit -a

로컬에서 바뀐 사항들을 중앙 저장소로 저장하기 위해서는:

$ git push

주 서버가 다른 개발자들로 인하여 새로운 변경사항이 생겼을 경우에는, '밀어넣기 (Push)'는 실패할 것입니다. 그렇다면 그 개발자는 최신 버전을 다시 당겨서 (pull) 결합후 다시 밀어넣기를 시도해야 하겠지요.

모든 개발자들은 push와 pull에 관한 SSH 접근권이 있어야합니다. 그러나 소스는 모든 이들에게 개방된 것으로써 다음 명령어를 이용하면 조회가 가능합니다:

$ git clone git://central.server/path/to/proj.git

Git 프로토콜은 HTTP와 비슷합니다: 증명서가 존재하지 않죠. 그래서 아무나 프로젝트를 조회할 수 있는겁니다. 그런 이유에서 '밀어넣기 (push)'는 Git 프로토콜로는 할 수없게 디폴트 설정이 되어있지요.

숨겨진 소스

개방되어 있지않은 소스의 프로젝트를 진행할 때에는 터치 (Touch) 명령어를 생략합니다. 그리고 'git-daemong-export-ok'라는 이름의 파일을 만들지 않도록 주의합니다. 이렇게하면 git 프로토콜을 사용해서 원치않는 사람들이 당신의 저장소를 조회할 수 있는 일은 없을 것입니다; 이제는 SSH 접근권이 있는 사람들만 조회할 수 있게 될겁니다. 당신의 모든 저장소가 개방되지 않은 경우에는 git daemon명령어는 필요없겠지요. 모든 저장소는 SSH 접근방식을 필요로 할 테니까요.

헐벗은 저장소

이 괴상한 이름의 저장소 (bare repository)는 현재 작업중인 디렉토리가 아니기에 이렇게 이름이 붙여졌습니다; 이 저장소는 하위 .git 디렉토리에서 숨겨진 파일들만을 저장하는 저장소입니다. 풀어 설명하면, 이 저장소는 현 프로젝트의 과거를 관리하기만 하고, 아무런 버전도 저장하지 않는 저장소입니다.

헐벗은 저장소는 버전 관리 중앙 서버와 비슷한 기능을 담당하고 있고 당신의 프로젝트가 저장되어 있는 집과같은 기능을 담당하고 있습니다. 개발자들은 이 곳에서 부터 클론을 만들 수 있고, 편집한 내용을 밀어넣기 (Push) 할 수 있습니다. 보편적으로 헐벗은 저장소는 서버에서 상주하고 있다가 데이터를 퍼트리는 역할을 맡고있습니다. 개발은 만들어진 클론에서 이루어짐으로써, 워킹 디렉토리없이 서버내에서 보호받는 저장소 역할을 할 수 있습니다.

많은 Git 명령어들은 GIT_DIR 환경 변수가 저장소로 path가 세팅되어 있지 않는 한 이 헐벗은 저장소에 인식되지 않을 것입니다. --bare 옵션을 이용한다면 모를까.

밀어넣기 (push) vs. 당기기 (pull)

당기기 (pull)에 의존하는 대신에 왜 제가 밀어넣기 (push)를 소개했을까요? 먼저, 당기기 (pull)는 아까 소개드린 헐벗은 저장소에서는 실행이 되지 않는 명령어입니다: 물론 나중에 소개할 물어오기 (fetch)라는 명령어로 같은 일을 할 수 있지만요. 그러나 헐벗은 것 말고 보통 일반적인 저장소를 중앙 서버에 저장해 놓는다고 해도, 당기기 (pull)는 번거로울 수 밖에 없습니다. 서버에 로그인을 해야 될 것이고 그런 후에야 당기기 (pull)을 사용해야 하다는 말이지요. 파이어월이 이런 작업을 방해할 수도 있습니다. 그리고 쉘 접근 권한이 없다면 중앙 서버에 접속이나 가능할런지요?

그러나 이러한 특수상황들이 아니라면 밀어넣기 (push)를 사용하실 것을 강추합니다. 목적지가 현재 작업중인 디렉토리가 있을 경우에는 굉장히 햇갈릴 수 있기 때문입니다.

줄여서, Git을 배울 때에는, 헐벗은 저장소일 경우에는 밀어넣기 (push) 아니면 당기기 (pull)을 사용합시다.

프로젝트 포크질 (forking) 하기

현재 프로젝트가 진행되고 있는 방식이 마음에 안 드신 다고요? 당신이 좀 더 잘할 수 있다고 생각하세요? 그렇다면 당신 서버에서:

$ git clone git://main.server/path/to/files

이 명령어를 쓴 후에, 다른 사람들에게 당신이 포크질 (fork)을 한 프로젝트에 대해 알리세요.

이후 아무때나 원래 프로젝트 파일에서 다음 명령어를 씀으로써 어떠한 변화가 있었다면 포크질 해놓은 프로젝트로 병합을 실행할 수 있습니다:

$ git pull

궁극의 백업

아무도 건들 수 없고 지리적으로 다양한 곳에 저장해놓고 싶은 기록 보관소를 소유하고 싶다고요? 만약 당신의 프로젝트에 많은 개발자들이 참여한다면 아무 것도 하지 마십시오. 클론을 만드신다면 그 클론 자체가 아주 효율적인 프로젝트 백업이 될 것 입니다. 현 상태의 프로젝트 뿐만이 아니라, 그 프로젝트의 모든 과거 버전까지 말이죠. 만약이라도 어떤 개발자 분의 클론이 훼손 된다면 암호화 된 hashing 덕에 다른 모든 개발자들이 프로젝트 훼손여부에 관해 알 수 있게 될 것입니다.

만약 당신의 프로젝트에 그리 많은 개발자들이 참여하지 않는다면, 최대한 많은 서버를 확보해서 클론을 만들어 놓으십시오.

편집증이 걸린 개발자들은 언제나 프로젝트 HEAD의 20-바이트 SHA1 hash를 어딘가에는 안전하게 모셔놓죠. 안전하다는 말이 사적인 공간에 저장해놓는다는 말은 아닙니다. 예를 들면, 어떤 신문에 기사를 개제하는 것도 안전한 기록보관의 한 방법이지요. 그 정보를 훼손하고자하는 작자들이 세상에 발간된 모든 신문 카피를 바꿀 수는 없기 때문입니다.

광속의 멀티테스킹

만약에 어떠한 프로젝트의 여러군데를 동시에 작업하고 싶으실 때에는 우선 프로젝트를 한 번 commit 한 후 다음 명령어를 사용합니다:

$ git clone . /some/new/directory

hardlinking 덕분에 클론들은 적은 시간과 공간을 이용해 백업으로 존재해줄 수 있습니다.

이렇게 하면 두개의 독립적인 구간에서 작업을 진행할 수 있습니다. 예로, 한 클론이 컴파일 중 다른 클론에서 작업을 진행하고 있을 수 있습니다. 그리고 다른 클론으로 부터 아무 때나 commit과 당기기 (pull)도 사용할 수 있습니다.

$ git pull /the/other/clone HEAD

게릴라 버전 관리

당신은 현재 다른 버전 관리 시스템을 사용하고 있지만, Git을 그리워하고 있진 않습니까? 그렇다면 현재 작업중인 디렉토리에서 Git을 초기화 시켜주십시오:

$ git init
$ git add .
$ git commit -m "Initial commit"

그리고 클론을 만들고:

$ git clone . /some/new/directory

이제 방금 클론 된 디렉토리에서 작업을 진행하시면 됩니다. 가끔은 다른 개발자 분들과 동기화하고 싶으시겠죠. 그 개발자분들은 아직 Git을 사용하고 있지 않아도 우리 Git에서는:

$ git add .
$ git commit -m "Sync with everyone else"

그리고는 새로운 디렉토리에서:

$ git commit -a -m "Description of my changes"
$ git pull

다른 분들에게 당신의 작업을 공유하는 일은 그 쪽 분들이 쓰시는 버전 관리 시스템에 따라 다릅니다. 새로운 디렉토리는 당신이 작업한 파일들이 포함되어 있죠. 위의 명령어를 쓰신 후에 다른 버전 관리 프로그램에서 쓰는 명령어를 통해서 그들의 중앙 서버에 업로드 하실 수 있습니다.

Subversion은 가장좋은 중앙 버전 관리식 시스템으로써 개발자들 사이에서 애용되고 있습니다. Git에서 *git svn*을 사용해서 위에서 언급한 일들은 Subversion 저장소를 대상으로 행할 수 있습니다.Git 프로젝트를 Subversion 저장소로 보내기.

Mercurial

Mercurial 역시 비슷한 버전 관리 시스템으로써 Git과 쉽게 연동될 수 있습니다. 'hg-git'플러그인을 통해서 Mercurial 유저들은 Git 저장소에 쉽게 밀어넣기 (push)와 당기기 (pull)을 사용할 수 있죠.

Git으로 'hg-git'을 구하는 방법:

$ git clone git://github.com/schacon/hg-git.git

Mercurial로 'hg-git'을 구하는 방법:

$ hg clone http://bitbucket.org/durin42/hg-git/

하지만 Git에 이 것과 비슷한 플러그인이 있는지는 모르겠다. 그렇기 때문에 Mercurial보다는 Git을 주 저장소를 쓰길 선호한다. Mercurial로 프로젝트를 진행할 경우에는 대부분의 케이스에 한 자원봉사 개발자가 Git 저장소를 관리하는 업무를 떠 맡곤 합니다. 그러나 Git으로 Mercurial 프로젝트를 진행할 경우에는 'hg-git'플러그인의 도움으로 그러한 번거로움이 필요없을 것입니다.

빈 저장소를 이용해서 Mercurial 저장소를 Git 저장소로 바꿀 수 있으나, 'hg-fast-export.sh'스크립트를 사용해 더 쉽게 이 작업을 끝낼 수 있습니다. 다음 저장소에서 이 스크립트를 구할 수 있습니다:

$ git clone git://repo.or.cz/fast-export.git

빈 저장소에서 한 번 바꿔봅시다:

$ git init
$ hg-fast-export.sh -r /hg/repo

위 명령어는 스크립트를 '$PATH'에 넣은 후에 실행합니다.

Bazaar

Bazaar는 Git과 Mercurial 다음으로 많이 알려진 버전 관리 시스템 입니다.

Bazaar는 작업 수정을 하기 용이하게 디자인 되어있지요; 개발자들은 과거의 실수에서 배우고 무시해도 될만한 에러에서 자유롭습니다. 그리고 Bazaar를 사용하는 개발자들은 다른 버전 관리 시스템들에 관해 굉장히 개방적인 분들 일겁니다.

bzr-git'플러그인은 Bazaar 이용자들이 Git 저장소를 통해 작업할 수 있도록 해줍니다. 'tailor 프로그램은 Bazaar 저장소를 Git 저장소로 바꿔줍니다. 'bzr-fast-export'도 한 번 검색해보세요.

내가 Git을 사용하는 이유

제가 Git을 처음에 사용했던 이유는 제가 듣기에 Git은 Linux kernel source 관리에 용이하다고 들었기 때문입니다. Git을 사용한 이후로는 다른 버전 관리 시스템으로 바꿔야겠다는 생각은 들지도 않았지요. Git은 저에게 유용한 도움이 되었으나, Git도 완벽한 플랫폼은 아닙니다. 저는 Linux를 주로 이용하기 때문에 다른 플랫폼과의 문제는 생략하겠습니다. 그리고 저는 C, bash scripts, Python을 이용하는 사람이고 빠른 프로그램 시간에 목숨을 거는 사람 중 하나입니다. Git이 어떻게 좀 더 발전할 수 있을지 Git과 비슷한 프로그램도 짜보기도 했지만 학교 프로젝트 정도로만 썻었을 뿐입니다. 그러나 제 프로젝트를 완료하더라도 저는 Git을 계속 이용했을 겁니다. 제 프로그램을 써도 별로 투자한 것에 비해 얻을 것이 적어보였기 때문이지요. 자연스레 여러분들이 필요로하고 원하는 프로그램은 계속해서 바뀝니다. 그러나 Git과는 그럴 가능성이 매우 적지요. == 나뭇가지 (branch) 마법 ==

Git의 죽이는 기능들 중에는 즉석으로 브랜칭 및 병합이 가능하다는 것입니다.

예시문제: 외부적인 요소들은 불가피하게 당신이 하던 일은 그만두게 합니다. 예를 들어, 치명적인 버그가 이미 배포된 버전에서 경고없이 퍼저나가게 생겼습니다. 프로그램에 새로 넣어야 할 기능이 있는데 데드라인은 가까워져 옵니다. 당신이 도움을 요청하고자 했던 개발자는 퇴사할려고 하니 도움을 요청할 수도 없고요. 시간이 촉박한 만큼 하던 일을 멈추고 버그를 고치는 데에 올인을 해야겠지요.

위와 같이 하던 일을 멈추는 것은 일의 생산성을 치명적으로 떨어트립니다. 특히나 지금까지 하던 일과 정 상관없는 부분의 프로그램을 건들어야 할 때 말이죠. 이럴 때, 중앙 버전 관리 시스템을 사용하는 경우엔 작동이 되는 버그없는 프로그램을 다시 받아야 합니다. 분산 관리 시스템일 경우에는 원하는 버전만 로컬 컴퓨터로 받아내면 되죠.

하지만 클로닝은 작업 중인 디렉토리 포함 그 디렉토리의 히스토리를 어느 선까지는 같이 다운로드 받게 합니다. Git은 최대한 효율성있게 시스템이 디자인되어 있지만, 클로닝 명령어를 쓴다면 프로젝트 파일들이 (비효율적으로) 현재 작업 중인 디렉토리에 전부 다시 생성될 것입니다.

해답: Git은 이런 상황에서 좀 더 빠르고 공간적으로 효율성있게 클로닝을 할 수 있는 명령어를 가지고 있습니다: git branch

이런 환상적인 명령어를 이용하여 디렉토리에 있는 파일들은 탈바꿈을 감행해 이 버전과 저 버전을 넘나들 수 있습니다. 이 변형기법은 버전 사이를 넘나드는 것 외에도 더 많은 것을 할 수 있습니다. 당신의 파일들은 전 버전에서 실험할 있는 임시버전, 개발버전, 친구들이 보유하고 있는 버전 등으로 변형할 수 있습니다.

일하는 척 하기 버튼

버튼 하나만 누르면 ("일하는 척 하기 버튼") 게임화면이 최소화되고 엑셀파일이 화면상에 나타나는 기능을 보신 적이 있을겁니다. 이 기능을 활용하면 직장상사의 눈을 속이고 일하던 척 할 수 있지요?

아무 디렉토리에서:

$ echo "I'm smarter than my boss" > myfile.txt # 난 내 상사보다 똑똑하다
$ git init
$ git add .
$ git commit -m "Initial commit"

우리는 "난 내 상사보다 똑똑하다"라는 내용을 가진 텍스트파일을 Git 저장소에 만들었습니다. 그리고:

$ git checkout -b boss  # 이 명령어를 사용한 후엔 아무것도 바뀌지 않은 것처럼 보일겁니다.
$ echo "My boss is smarter than me" > myfile.txt # 상사는 나보다 똑똑합니다
$ git commit -a -m "Another commit"

겉으로 보기에는 그 텍스트파일을 새로운 (맘에 들지않는) 문장으로 덮어씌우고 commit을 한 것처럼 보일겁니다. 그러나 그건 착각입니다. 다음 명령어를 입력해보세요:

$ git checkout master  # 처음 버전으로 돌아가기

자! 그럼 처음 생성했던 텍스트파일이 돌아왔을 겁니다. 만약에 그 상사가 이 사실을 알아채고 당신의 디렉토리를 살펴본다고 할 때는:

$ git checkout boss  # 아까 두 번째로 만들어놓은 "상사는 나보다 똑똑합니다"라는 메세지를 담은 myfile.txt 파일로 돌아갑니다.

이런 식으로 두 가지 다른버전의 파일 사이를 오갈 수 있습니다. 그리고 각각 따로 commit을 할 수 있지요.

힘든 작업

당신이 어떤 작업을하고 있다고 가정합니다. 작업 도중에 세 버전 전으로 돌아가서 새로운 print 라인을 넣고 테스팅 해보고 싶다는 생각이 들었습니다. 그럴 때엔:

$ git commit -a
$ git checkout HEAD~3

이제 테스팅하고 싶었던 파일에 더하고 싶은 것을 걱정없이 마구 넣어도 됩니다. 이 미친 짓(?)을 Commit 해놓을 수도 있습니다. 작업이 다 끝났다면,

$ git checkout master

를 사용해 아까 미친 짓을 하기 전의 작업상태로 돌아올 수 있습니다. Commit하지 않았던 작업들이 같이 딸려 왔다는 것을 확인 (조심!)할 수 있을 겁니다.

아까 그 임시작업 (미친 짓)을 세이브하고 싶다면 어떻게 해야할까요? 쉽습니다:

$ git checkout -b dirty

를 실행하여 그 나뭇가지 (branch) 에서 마스터 나뭇가지로 돌아오기 전에 commit을 하면 됩니다. 그런 후 다시 미친 짓을 할 때의 상태로 돌아가고 싶다면:

$ git checkout dirty

우리는 이 체크아웃이라는 명령어를 전에도 설명했었죠. 여기서는 이 명령어가 어떻게 예전 버전들을 불러오는 지 살펴볼 수 있었습니다: 파일을 원하는 버전으로 돌아가게 할 수 있으나, master 나뭇가지를 우선 벗어나야 하지요. 벗어난 후의 commit은 master 나뭇가지와는 다른 길을 걷게 될 것입니다. 그 길을 나중에 이름도 지어줄 수 있지요.

다시 말하면, 예전 상태 (state)에서 벗어나면 Git은 자동으로 이름이 (아직) 붙여지지 않은 새로운 나뭇가지로 이동시켜 줍니다. 이 나뭇가지는 *git checkout -b*로 이름을 바꿔 저장해줄 수 있죠.

빠른 해결책

작업 중에 갑자기 하던 일을 멈추고 '1b6d…'commit에 있는 버그를 고치라고 부탁을 받았다고 생각해 봅시다:

$ git commit -a
$ git checkout -b fixes 1b6d

버그를 다 고친 후에:

$ git commit -a -m "Bug fixed"
$ git checkout master

이제 아까 잠시 중단했던 작업으로 돌아갈 수 있습니다. 버그가 고쳐진 파일도 병합해올 수 있죠:

$ git merge fixes

병합 (Merging)

Git을 제외한 어떤 버전 컨트롤 시스템들을 이용할 땐 나뭇가지 (branch)들을 만드는 것은 쉽지만 나뭇가지들을 병합하기는 어려울지도 모릅니다. Git에서는 병합작업이 정말 쉽고 병합이 진행되고 있는 중인지도 모르는 사이에 끝날 것입니다.

우리는 병합을 아까 전에도 소개했었습니다. 당겨오기 (pull) 명령어는 commit들을 가져와 지금 사용중인 나뭇가지에 병합하여 줍니다. 로컬에서 아무런 편집작업을 진행하지 않았더라면 *pull*은 현 나뭇가지를 빨리 감기 하여 중앙 서버에서 가장 최근의 정보를 가져와 병합합니다. 로컬에서 편집작업을 한 기록이 있다면, Git은 자동으로 병합을 시도할 것이고, 병합에 버전간의 차질이 있다면 당신에게 보고할 것 입니다.

Commit은 보통 하나의 '부모 commit'이 있습니다. 병합을 다르게 생각해보면 한 commit이 적어도 두 개의 '부모 commit'이 있다고 생각할 수 있는 것이죠. 그럼 'HEAD~10'은 어떤 commit을 가르키는 걸까요? 부모가 하나가 아니라면 어떤 것을 거슬러 올라가야 전 버전에서 작업할 수 있을까요?

Git은 먼저 commit되었던 부모를 따르게 설정되어 있습니다. 현재 작업중인 나뭇가지가 병합이 실행될 경우 첫번째 부모가 되기때문에 당연한 겁니다.: 당신은 언제나 현 나뭇가지에 가장 최근에 한 작업에만 관심이 있을 수 밖에 없기 때문이지요. 다른 나뭇가지에서 한 작업은 다음 일입니다.

탈자 기호 (^)를 이용하서 부모를 수동으로 정해줄 수도 있습니다. 예를 들어 두번째 부모의 기록을 조회하고 싶다면:

$ git log HEAD^2

첫번째 부모의 기록을 조회할 때는 탈자기호 이후의 번호는 생략해도 됩니다. 굳이 보여드리자면:

$ git diff HEAD^

이 표기법은 다른 형식의 표기법과도 병행해서 사용할 수 있습니다:

$ git checkout 1b6d^^2~10 -b ancient

(집중하십시오) 새로운 나뭇가지인 "ancient"를 시작하고 두번째 부모의 첫번째 부모 나뭇가지에서 1b6d로 시작하는 commit과 그 commit 전 10개의 commit을 불러와 줄 것입니다.

방해받지 않는 작업진행

하드웨어 관련작업을 하다보면 현재 작업중인 단계가 완료되어야만 다음 단계 진행이 가능할 것입니다. 자동차를 예로들면 외부로부터 오기로했던 부품들이 도착해야 비로소 수리에 들어갈 수 있겠지요. 프로토타입들은 칩들이 가공되어야 건축이 가능해 지겠죠.

소프트웨어 관련작업도 비슷합니다. 다음 작업이 진행될려면 현재 작업이 이미 발표 및 테스트가 되어있어야 할 겁니다. 어떤 작업들은 당신의 코드가 받아 들여지기 전 검토부터 되어야 겠지요. 그래서 당신은 그 검토가 끌날 때까지는 다음 작업으로 진행하지 못 할것입니다.

하지만 나뭇가지와 병합기능 덕분에 이 규치을 깨고 파트 1이 완료되기도 전에 파트 2에서 미리 작업을 진행하고 있을 수 있습니다. 파트 1을 commit하고 검토를 위해 어디론가 보냈다고 생각하십시오. Master 나뭇가지에서 있었다면, 그 나뭇가지에서 다른 나뭇가지로 갈아타야합니다:

$ git checkout -b part2

그리곤 파트 2에서 commit을 하며 작업을 계속 진행하세요. 인간은 실수를 많이하는 동물이기에 파트 1으로 다시 돌아가서 무엇인가 고치고 싶을지도 모릅니다. 만약에 당신이 천재적인 프로그래머라면 다음 명령어를 사용할 일은 없겠지요.

$ git checkout master  # 파트 1로 돌아갑니다.
$ fix_problem # 수정 작업
$ git commit -a        # 수정 작업을 commit합니다.
$ git checkout part2   # 파트 2로 다시 갑니다.
$ git merge master     # 아까 파트 1의 수정을 파트 2로 병합합니다.

이 때 즈음이면 이미 파트 1은 허가 받았겠지요.

$ git checkout master  # 파트 1로 돌아갑니다.
$ submit files         # 파일 배포!
$ git merge part2      # 파트 2도 파트 1으로 병합.
$ git branch -d part2  # 파트 2 나뭇가지 삭제.

이제 파트 2의 모든 것과 함께 master 나뭇가지로 돌아왔습니다.

나뭇가지는 제한 없이 원하는 만큼 생성할 수 있습니다. 거꾸로도 나뭇가지를 만들 수도
있죠: 만약에 7번의 commit전에 나뭇가지를 하나 만들어 놓았어야 함을
늦게 깨닫았을 때, 다음 명령어를 이용해 보세요:
$ git branch -m master part2  # master 나뭇가지의 이름을 part2로 바꿉니다.
$ git branch master HEAD~7    # 7 commit 전의 상황에서 master 나뭇가지를 새로 만듭니다.

Master 나뭇가지는 이제 part 1만 들어있고, 나머지는 모두 part 2에 들어가게 되었습니다. 그리고 우리는 지금 part 2에서 작업을 하고 있는 중이겠지요; master를 만들면서 master로는 현재 작업공간을 옮겨가지 않았습니다. 처음 보시죠? 여태까지 설명한 예제들에서는 나뭇가지를 만들면서 곧바로 작업공간도 같이 옮겨갔었는데 말이죠. 이런 식으로요:

$ git checkout HEAD~7 -b master  # 나뭇가지를 만들고 바로 작업공간도 그 나뭇가지로 옮긴다.

메들리의 재정리

하나의 나뭇가지에서 모든 작업을 끝내고 싶을 수도 있습니다. 작업중인 일들은 혼자만 알고 중요한 commit들만 다른사람들에게 보여주고 싶을 수 있습니다. 그럴경우엔 두 개의 나뭇가지를 우선 만드세요:

$ git branch sanitized    # 정돈된 commit을 보여주기 위한 나뭇가지를 만듭니다.
$ git checkout -b medley  # 작업을 하게 될 "메들리" 나뭇가지를 만들어 이동합니다.

버그를 고치던, 어떤 기능을 더하던, 임시코드를 더하던 작업을 진행합니다. 물론 commit을 해가면서 말이죠. 그리고:

$ git checkout sanitized
$ git cherry-pick medley^^

위의 명령어들을 차례로 사용한다면 "메들리" 나뭇가지의 commit들을 "sanitzed" 나뭇가지에 붙입니다. "cherry-pick"명령어를 잘 사용한다면 영구적인 코드들만 들어있는 나뭇가지를 만들 수 있습니다. 그리고 그 commit들은 서로 연계가 잘 되어있을 것입니다.

나뭇가지 관리하기

여태까지 프로젝트에서 생성한 나뭇가지들을 보려면:

$ git branch

기본적으로 "master" 나뭇가지에서 작업을 시작하는 것이 디폴트로 지정되어 있습니다. 그러나 어떤 개발자들은 "master" 나뭇가지는 그대로 냅두고 새로운 나뭇가지를 만들어서 그 곳에서 작업하는 것을 선호합니다.

-d*와 *-m 옵션들은 각각 나뭇가지들을 지우거나 이름을 바꿔줄 수 있는 파라메터들 입니다. *git help branch*를 보시면 더욱 자세히 설명되어 있을겁니다 (번역 주: 어차피 영어입니다)

"master" 나뭇가지는 유용한 관례적인 이름의 나뭇가지일 뿐입니다. 다른 개발자들은 당신의 저장소에 당연히 "master"라는 이름을 가진 나뭇가지가 있을 것이라고 생각하겠지요. 그리고 그 나뭇가지는 모든 공식적인 자료들일 들어있다고 넘겨짚을 것입니다. 그러나 당신은 "master"를 없에거나 새로운 이름을 지정해줄 수 있으나, "master" 나뭇가지를 쓰는 관례를 따르는 것을 추천합니다.

임시 나뭇가지

Git을 사용하다보면 당신은 쓸모없는 하루살이의 나뭇가지들을 많이 만들고 있다는 사실을 깨달을 것입니다. 이유는 다음과 같겠지요: 그 많은 나뭇가지들은 작업의 경과를 저장하기 위해 만들어 놓고 무엇인가 고칠 것이 있을 때 빨리 돌가가기 위해서 쌓아두기만 하고있는 거겠죠.

다른 TV채널에서 무얼하나 확인할 때 잠시 채널을 바꾸는 것과 같은 아이디어입니다. 그러나 리모트 버튼 몇 개 누르면 되는 것과는 달리, 많은 나뭇가지를 만들고, 설정하고, 병합하고, 나중에 다쓰면 지워야합니다. 다행히도 Git에서는 TV 리모트와 비슷하게 지름길이 있습니다:

$ git stash

이 명령어는 현 버전을 임시저장소 (stash)에 저장해 주고 작업하기 전의 상태로 돌아갑니다. 작업중인 디렉토리는 작업 (편집, 버그고침 등) 하기 전의 상태로 돌아가겠지요. 그리고 임시 (stash)로 돌아가고 싶다면:

$ git stash apply  # 에러 (version conflict)가 날지도 몰라요.

물론 여러개의 임시저장소 (stash)를 만들수도 있습니다. *git help stash*에 설명이 되어있으니 읽어보세요. 눈치챘을지 모르겠지만, Git은 올바른 임시저장소 (stash) 기능을 쓰게 해주기 위해서 나뭇가지들을 몰래 이용한답니다.

원하는 방식대로 작업하기

나뭇가지를 이용하는 것이 꼭 필요한지 생각할지도 모르겠습니다. 파일들을 클로닝하는게 제일 빠르고 *cd*를 이용해 디렉토리를 바꿈으로써 나뭇가지를 대체하고 싶을지도 모릅니다.

웹브라우저의 예를 들어보겠습니다. 여러개의 창 아니면 여러개의 탭을 지원하는 이유는 무엇일까요? 여러 이용자들의 작업방식을 존중하여 주기 위해서랍니다. 어떤 이용자들은 웹브라우저 창 하나만 열고 여러 탭을 열어서 작업하는 방식을 추구합니다. 다른 이용자들은 반대의 형식으로 작업하는 것을 추구할지도 모르죠: 여러개의 창을 만들고 탭이 없이 작업하는 것을 말이죠. 또 어떤 이용자들은 이 두 방법들을 섞어서 작업하는 걸 선호할지도 모릅니다.

나뭇가지들은 마치 작업중인 디렉토리의 탭과 같습니다. 클로닝은 새로운 브라우저 창을 여는 것과 같은 것이죠. 이 두가지 방법은 모두 빠르고 로컬에서 진행됩니다. 그러니 당신에게 맞는 방법을 찾아보는 건 어떨까요? Git은 당신이 원하는 대로 일하게 도와줄 것입니다.