본문 바로가기

책/프로 Git

Git 브랜치-1

브랜치란 무엇인가?

파일을 Stage하면

  • Git 저장소에 파일을 저장하고( Blob )
  • Staging Area에 해당 파일의 체크썸을 저장한다. 
$ git add README test.rb LICENSE
$ git commit -m 'The initial commit of my project'

 

git commit으로 커밋하면

  • 먼저 루트 디렉터리와 각 하위 디렉터리의 트리 개체를 체크섬과 함께 저장소에 저장한다.
  • 커밋 개체를 만들고 메타데이터와 루트 디렉터리 트리개체를 가리키는 포인터 정보를 커밋 개체에 넣어 저장한다. 그래서 필요하면 언제든지 스냅샷을 다시 만들 수 있다.
  • 이 작업을 마치고 나면 Git 저장소에는 다섯개의 개체가 생긴다.
    • 각 파일에 대한 Blob 3개 파일
    • 디렉터리 구조가 들어있는 트리개체 하나
    • 메타데이터와 루트 트리를 가리키는 포인터가 담긴 커밋 개체 하나

 

 

다시 파일을 수정하고 커밋하면

  • 이전 커밋이 무엇인지도 저장한다.
  • 커밋을 두번 더 하면 다음과 같다.

 

testing 브랜치를 만든다.

$ git branch testing

 

 

Git 은 'HEAD'라는 특수한 포인터가 있다. 이 포인터는 지금 작업 하는 로컬 브랜치를 나타낸다.

testing으로 체크아웃 하면 HEAD는 testing 브랜치를 가리킨다.

$ git checkout testing

 

 

커밋을 새로 하면 다음과 같다.

$ vim test.rb
$ git commit -a -m 'made a change'

 

 

다시 master 브랜치로 되돌아 가면 다음과 같다.

$ git checkout master

 

 

master 브랜치 상태에서 커밋을 하면 프로젝트 히스토리가 분리돼 진행된다. 

$ vim test.rb
$ git commit -a -m 'made other changes'

 

브랜치와 Merge의 기초

브랜치와 Merge는 보통 이런식으로 진행된다.

  1. 작업 중인 웹사이트가 있다.
  2. 새로운 이슈 처리할 새 Branch를 하나 생성
  3. 새로 만든 Branch에서 작업중

이때 중요한 문제가 생겨서 그것을 해결하는 Hotfix를 먼저 만들어야 한다. 그러면 다음과 같이 할 수 있다.

  1. 새로운 이슈를 처리하기위해 이전의 운영(Production) 브랜치로 복원.
  2. Hotfix 브랜치를 새로 하나 생성
  3. 수정한 Hotfix 테스트를 마치고 운영 브랜치로 Merge
  4. 다시 작업 하던 브랜치로 옮겨가서 하던일 진행.

브랜치의 기초

다음과 같은 상태의 커밋 히스토리이다.

 

iss53 브랜치를 생성하고 체크아웃 한다.

#$ git branch iss53||git checkout iss53 와 같다.

$ git checkout -b iss53
Switched to a new branch "iss53"

 

 

 

iss53 브랜치에서 커밋한다.

$ vim index.html
$ git commit -a -m 'added a new footer [issue 53]'

 

 

master 브랜치로 체크아웃 하기전에 알아야 할 사항이 있다.

  • 만약 iss53에서 아직 커밋 하지 않은 파일이 checkout할 브랜치와 충돌 나면 브랜치를 변경할 수 없다.
  • 브랜치를 변경할 때에는 Working 디렉터리를 정리하는 것이 좋다.
  • 정리 방법은 Stash 나 커밋 Amend이다. 

master 브랜치로 체크아웃 한다.

  • 이때 Working 디렉터리는 iss53 을 시작하기 이전 모습으로 되돌려지기 때문에 새로운 문제에 집중할 수 있는 환경이 만들어진다.
  • Git은 자동으로 Working 디렉터리에 파일들을 추가하고, 지우고, 수정해서 Checkout한 브랜치의 스냅샷으로 되돌려 놓는다.
$ git checkout master
Switched to branch 'master'

 

 

hofix 브랜치를 생성 checkout 하고, 오류 수정 커밋을 한다. 

$ git checkout -b hotfix
Switched to a new branch 'hotfix'
$ vim index.html
$ git commit -a -m 'fixed the broken email address'
[hotfix 1fb7853] fixed the broken email address
 1 file changed, 2 insertions(+)

 

 

이후 master 브랜치로 체크아웃 하고 Merge 한다.

  • Fast Forward : Merge 할 브랜치(hotfix)가 가리키고 있던 커밋이 현 브랜치(master)가 가리키는 것보다 '앞으로 진행한 커밋'이기 때문에 master 브랜치는 최신커밋으로 이동한다.
$ git checkout master
$ git merge hotfix
Updating f42c576..3a0874c
Fast-forward
 index.html | 2 ++
 1 file changed, 2 insertions(+)

 

 

merge 브랜치 위치에서 hotfix 브랜치를 삭제한다.

$ git branch -d hotfix
Deleted branch hotfix (3a0874c).

 

iss53 브랜치로 checkout 해서 처리하던 환경으로 되돌아가 하던일을 계속한다.

$ git checkout iss53
Switched to branch "iss53"
$ vim index.html
$ git commit -a -m 'finished the new footer [issue 53]'
[iss53 ad82d7a] finished the new footer [issue 53]
1 file changed, 1 insertion(+)

Merge의 기초

iss53에서 작업을 마쳤으면 master로 체크아웃하고 iss53을 Merge 한다.

  • 3-way Merge : 브랜치가 가리키는 커밋 두 개(iss53, master) , 공통조상 하나(C2) 를 사용하여 머지하는 방식
    • 3개의 머지 결과를 별도의 커밋으로 만들고 나서 해당 브랜치가 그 커밋을 가리키도록 이동시킨다.
    • 이런 커밋은 부모가 여러개고 Merge 커밋이라고 부른다.
    • 개발자가 직접 공통조상을 찾아야 하는 다른 CVS와는 달리, Git은 자동으로 최적의 공통조상을 찾아 Merge한다.
$ git checkout master
Switched to branch 'master'
$ git merge iss53
Merge made by the recursive
README |    1 +
1 file changed, 1 insertion(+), 0 deletions(-)

 

작업을 마치면 iss53 브랜치를 삭제한다.

$ git branch -d iss53

충돌의 기초

가끔씩 3-way Merge가 실패할 때도 있다. Merge하는 두 브랜치에서 같은 파일의 한 부분을 동시에 수정하고 Merge하지 못한다. 예를 들어, 53번 이슈와 hotfix가 같은 부분을 수정했다면 Git은 Merge하지 못하고 다음과 같은 충돌(Conflict) 메시지를 출력한다.

$ git merge iss53
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.

Merge 충돌이 일어났을 때 git status 명령을 이용한다.

  • 충돌이 난 파일은 unmerged 상태로 표시된다.
$ git status
index.html: needs merge
# On branch master
# Changed but not updated:
#   (use 'git add <file>...' to update what will be committed)
#   (use 'git checkout -- <file>...' to discard changes in working directory)
#
#   unmerged:    index.html
#

 

충돌이 난 부분은 다음과 같이 표시된다.

  • ======= 위쪽 내용은 HEAD버젼( merge 명령을 실행할 때 master 브랜치)
  • 아래쪽은 iss53 브랜치의 내용이다.
<<<<<<< HEAD:index.html
<div id="footer">contact : email.support@github.com</div>
=======
<div id="footer">
 please contact us at support@github.com
</div>
>>>>>>> iss53:index.html

 

다음은 아예 새로 작성하여 충돌을 해결하는 예제다.

  • 충돌난 부분을 해결하고 git add 명령으로 다시 저장한다. 
<div id="footer">
please contact us at email.support@github.com
</div>

 

git status 명령으로 다시 한번 확인해볼 수 있다.

$ git status
# On branch master
# All conflicts fixed but you are still merging.
#   (use "git commit" to conclude merge)
# 
# Changes to be committed:
# 
#     modified:   index.html

 

충돌을 쉽게 해결하기 위해 git mergetool 명령도 있다.

$ git mergetool

 

git commit 명령으로 Merge 한 것을 커밋한다.

  • 충돌을 해결하고 Merge할 때에는 커밋 메시지가 다음과 같다.
  • 어떻게 충돌을 해결했고 좀 더 확인해야 하는 부분은 무엇을 어떻게 했는지 자세하게 기록한다.
Merge branch 'iss53'

Conflicts:
    index.html
#
# It looks like you may be committing a merge.
# If this is not correct, please remove the file
#	.git/MERGE_HEAD
# and try again.
#