본문 바로가기

SCM/Git

14. Git 브랜치 만들고 이동하기 - git branch, git checkout

 
Git 에서 사용하는 브랜치는 Repository 내부의 디렉토리 정도로 이해해도 된다.
 
필요에 따라 디렉토리를 나누고 특정 파일을 각각의 디렉토리에 저장하며
 
필요에 따라 각 디렉토리의 싱크를 맞추는 작업이 필요하다.
 
이를 위해 Git 에서는 브랜치를 다루는 git branch 명령을 제공한다.
 

git branch 
 
브랜치를 생성, 수정, 삭제하는 기본적인 명령은 아래와 같다.
 
$ git branch [브랜치명] // 브랜치 생성
$ git branch -d [브랜치명] // 브랜치 삭제
$ git branch -m [기존 브랜치명] [바뀔 브랜치명] // 브랜치 이름 변경
 
조건으로 Commit 된게 하나도 없다면 브랜치는 생성할 수 없다.
 
왜냐하면 master 라는 브랜치는 포인터라서 먼가 가리키는게 필요하기 때문이다.
 
관련해서는 아래 브랜치 내부 동작 이해를 살펴보도록 하자.
 

 


git checkout
 
워킹 디렉토리의 소스를 특정 위치로 이동시키려는 경우 사용한다.
 
요는 HEAD 라는 포인트가 특정 커밋 위치나 브랜치 위치로 이동하면 거기에 커밋이 수행된다는 것이다.
 
관련해서는 아래 브랜치 내부 동작 이해를 살펴보도록 하자.
 
$ git checkout [브랜치명] // 특정 브랜치로 워킹 디렉토리 변경
$ git checkout [Commit ID] // 특정 커밋으로 워킹 디렉토리 변경
$ git checkout -- [파일경로] // 특정 파일을 해당 브랜치 또는 커밋 상태로 변경 
 

git branch 목록보기
 
git branch 를 옵션없이 실행하면 목록을 볼 수 있다.
 
* 가 붙어있는 branch 는 현재 checkout 해서 작업하는 branch 를 나타낸다.
 
$ git branch
  iss53
* master 
  testing
 
여기에 -v 를 붙여주면 commit 메세지도 함께 보여준다.
 
$ git branch -v
  iss53   93b412c fix javascript issue
* master  7a98805 Merge branch 'iss53'
  testing 782fd34 add scott to the author list in the readmes
 
--merged 옵션은 merge 된 브랜치만 확인한다.
 
$ git branch --merged
  iss53
* master
 
 --no--merged 옵션은 현재 작업중인 branch 에 merge 되지 않은 branch 만 나타낸다.
 
$ git branch --no-merged
  testing
 
merge 하지 않은 커밋을 담고 있기 때문에 삭제되지 않는다.
 
$ git branch -d testing
error: The branch 'testing' is not fully merged.
If you are sure you want to delete it, run 'git branch -D testing'.

 


Branch 이동에 대한 내부 동작 이해
 
Git 이 branch 를 다루는 과정을 이해하려면 Git 이 데이터를 어떻게 저장하는지 알아야 한다.
 
 
Step 1. 최초 commit 
 
아래와 같이 README, test.rb, LICENSE 파일을 add 후 commit 하면
 
$ git add README test.rb LICENSE
 
$ git commit -m 'initial commit of my project'
 
Git 저장소에는 다섯 개의 데이터 Object 가 생긴다.
 
각 파일에 대한 Blob Object 세 개,
 
파일과 디렉토리 구조가 들어 있는 Tree Object 한개 
 
메타 데이터와 루트 트리를 가리키는 포인터가 담긴 Commit Object 한 개 이다.
 
 
이 상태에서 파일을 수정하고 commit 하면 이전 commit 이 무엇인지도 저장한다. 
 
아래 그림을 보면 Snapshot A 의 포인터는 98ca9 인데 
 
Snapsho B 에서 parent 로 98ca9 를 저장하고 있다.
 
 
 
 그리고 최초로 commit 하면 Git 은 master 라는 이름의 branch 를 만든다.
 
그리고 commit 을 만들때마다 master branch 가 마지막 commit 을 포인팅 한다.
 
아래는 3번 commit 했을 때 master branch 가 마지막 commit 을 포인팅 하는 것을 보여준다.
 
 
 
 Step 2. 새로운 branch 만들기
 
여기서 아래의 명령으로 새 branch 를 생성하면 새 branch 도 마지막 commit 을 가리킨다.
 
하지만 여전히 현재 작업중인 branch 는 master branch 인데 이유는 HEAD 라는
 
특수한 포인터로 현재 작업하는 로컬 브랜치를 master branch 로 물고 있기 때문이다.
 
$ git branch testing
 
 
아래 명령을 통해서 HEAD 가 가리키는 branch 가 무엇인지 확인할 수 있다.
 
$ git log --oneline --decorate
 
 
이게 중요한 이유는 변경사항이 HEAD 가 가리키는 branch 로 Commit 되기 때문이다.
 
 
Step 3. 새로만든 branch 로 이동하기
 
아래 명령으로 testing 이라는 branch 로 HEAD 가 가리키는 branch 를 이동시킨다.
 
$ git checkout testing
 
 
 
 
Step 4. 새로운 브랜치에 커밋하기
 
이 상태에서 commit 을 수행하면 HEAD 가 가리키는 testing branch 가 새 commit 을 가리키게 된다.
 
$ git commit -a -m 'made a change'
 
 
 
 
Step 5. master 브랜치로 이동하기
 
이 상태에서 다시 master branch 로 이동시켜 보자.
 
$ git checkout master
 
 
이렇게 하면 실제 working directory 에 있는 파일이 해당 스냅샷의 내용으로 변경된다.
 
 
Step 6. master 브랜치에 변경사항 merge
 
파일을 수정하고 다시 commit 을 해보면 아래와 같이 변경된다.
 
$ git commit -a -m 'made other changes'
 
 

Git 과 다른 SCM
 
결국 Git의 브랜치는 어떤 한 커밋을 가리키는 40글자의
 
SHA-1 체크섬 파일에 불과하기 때문에 만들기도 쉽고 지우기도 쉽다.
 
새로 브랜치를 하나 만드는 것은 41바이트 크기의 파일을(40자와 줄 바꿈 문자) 하나 만드는 것에 불과하다.
 
브랜치를 만들어야 하면 프로젝트를 통째로 복사해야 하는 다른 버전 관리 도구와 Git의 차이는 극명하다.
 
통째로 복사하는 작업은 프로젝트 크기에 따라 다르겠지만 수십 초에서 수십 분까지 걸린다.
 
그에 비해 Git은 순식간이다.
 
게다가 커밋을 할 때마다 이전 커밋의 정보를 저장하기 때문에
 
Merge 할 때 어디서부터(Merge Base) 합쳐야 하는지 안다.
 
이런 특징은 개발자들이 수시로 브랜치를 만들어 사용하게 한다.