공부/ELSE

Git 브랜치

5월._. 2022. 6. 28.
728x90

Git 브랜치

main과 master 브랜치는 동일한 의미다. 이미지와 설명이 일치하지 않을 수 있다.

1. Git Branch

Commit

git은 데이터를 change set이나 diff로 기록하지 않고 스냅샷으로 기록한다. 커밋하면 git은 현재 staging area에 있는 데이터의 스냅샷에 대한 포인터, 저자나 커밋 메시지 같은 메타데이터, 이전 커밋에 대한 포인터 등을 포함하는 commit object를 저장한다. 이전 커밋 포인터가 있어서 현재 커밋이 무엇을 기준으로 바뀌었는지를 알 수 있다. 최초 커밋을 제외한 나머지 커밋은 이전 커밋 포인터가 적어도 하나씩 있고 브랜치를 합친 Merge 커밋 같은 경우는 이전 커밋 포인터가 여러개 있다.
git commit으로 커밋하면 먼저 1) 각 파일에 대한 blob을 만들고 2) 루트 디렉터리와 하위 디렉터리의 트리 개체를 체크섬과 함께 저장소에 저장한다. 3) 그 다음 커밋 개체를 만들고 메타데이터와 루트 디렉터리 트리 개체를 가리키는 포인터 정보를 커밋 개체에 넣어 저장한다.

$ git add README test.rb LICENSE
$ git commit -m 'The initial commit of my project'

위의 명령어는 파일 3개를 staging area에 저장한 뒤 커밋한다. 이 작업을 마치고 나면 git 저장소에는 다섯개의 데이터 개체가 생긴다. 각 파일에 대한 blob 세개, 파일과 디렉터리 구조가 들어있는 트리 개체 하나, 메타데이터와 루트 트리를 가리키는 포인터가 담긴 커밋 개체 하나다.

Git 브랜치 - 1. Git Branch - Commit

다시 파일을 수정하고 커밋하면 이전 커밋이 무엇인지도 저장한다.

Git 브랜치 - 1. Git Branch - Commit
커밋 개체들

 

Branch

git 브랜치는 커밋 사이를 가볍게 이동할 수 있는 포인터같은 것이다. 깃은 기본적으로 main 브랜치를 만든다. 처음 커밋하면 이 main 브랜치가 생성된 커밋을 가리킨다. 이후 커밋을 만들면 main브랜치는 자동으로 가장 마지막 커밋을 가리킨다.

Git 브랜치 - 1. Git Branch - Branch
master--> 현재는 main으로 변경되었다.

 

새 브랜치 생성하고 옮기기

git branch 명령어를 사용해 새 브랜치를 생성할 수 있다. 새로 만든 브랜치는 지금 작업하고 있던 마지막 커밋을 가리킨다.

git branch 브랜치이름

Git 브랜치 - 1. Git Branch - 새 브랜치 생성하고 옮기기

git은 HEAD라는 포인터를 활용한다. 이 포인터는 지금 작업하고 있는 로컬 브랜치를 가리킨다. 만약 브랜치가 어떤 커밋을 가리키고 있는지 알고싶다면 git log 명령에 --decorate 옵션을 사용하면 된다.

Git 브랜치 - 1. Git Branch - 새 브랜치 생성하고 옮기기

git branch 명령어는 브랜치를 만들기만 하고 브랜치를 옮기지 않기 때문에 git checkout 명령을 사용한다.

git checkout 브랜치이름

이렇게하면 HEAD는 "브랜치이름" 브랜치를 가리킨다.

Git 브랜치 - 1. Git Branch - 새 브랜치 생성하고 옮기기

이 상태에서 커밋을 새로 한다면 아래 그림처럼 된다. 새로 커밋해서 testing 브랜치는 앞으로 이동했지만 master(main)브랜치는 여전히 이전 커밋을 가리킨다.

Git 브랜치 - 1. Git Branch - 새 브랜치 생성하고 옮기기

master(main) 브랜치로 되돌아가면 master 브랜치가 가리키는 커밋을 HEAD가 가리키게 하고 워킹 디렉토리의 파일도 그 시점으로 되돌려놓는다. 앞으로 커밋을 하면 다른 브랜치의 작업들과 별개로 진행되기 때문에 testing 브랜치에서 임시로 작업하고 원래 master 브랜치로 돌아와서 하던 일을 계속할 수 있다.

Git 브랜치 - 1. Git Branch - 새 브랜치 생성하고 옮기기

브랜치를 새로 만들면서 checkout까지 한번에 하려면 git checkout -b 옵션을 추가한다.

git checkout -b "브랜치이름"

 

브랜치 삭제

git branch 명령에 -d 옵션을 주고 브랜치를 삭제할 수 있다.

git branch -d "브랜치이름"

 

2. Branch와 Merge

Fast forward

A브랜치에서 다른 B브랜치를 merge할 때 B브랜치가 A브랜치 이후의 커밋을 가리키고 있으면 그저 A브랜치가 B브랜치와 동일한 커밋을 가리키도록 이동시키는 방식이다.
예를 들어, 해결해야할 핫픽스가 생겼을 때 main에서 hotfix라는 브랜치를 만들고 새로운 이슈를 해결할 때까지 사용한다. 문제를 모두 고쳤다면 git merge 명령으로 hotfix 브랜치를 main 브랜치에 합쳐야 한다.

Git 브랜치 - 2. Branch와 Merge - Fast forward

$ git checkout master
$ git merge hotfix
Updating f42c576..3a0874c
Fast-forward
index.html | 2 ++
1 file changed, 2 insertions(+)

hotfix 브랜치가 가리키는 C4 커밋이 main의 C2커밋에 기반한 브랜치기 떄문에 브랜치 포인터는 merge 없이 그저 최신 커밋으로 이동한다. 이런 merge 방식을 "Fast forward"라고 부른다.

3-way Merge

iss53 브랜치를 main 브랜치로 merge하는 것은 fast forward방식과 다르다. 이 경우는 각 브랜치가 가리키는 커밋 두 개와 공통 조상 하나를 사용해 3-way merge를 한다.

Git 브랜치 - 2. Branch와 Merge - 3-way Merge

단순히 브랜치 포인터를 최신 커밋으로 옮기는 게 아니라 3-way merge의 결과를 별도의 커밋(C6)으로 만들고 나서 해당 브랜치가 그 커밋을 가리키도록 이동시킨다. 그래서 이런 커밋은 부모가 여러 개고 merge커밋이라고 불린다.

Git 브랜치 - 2. Branch와 Merge - 3-way Merge

 

Conflict

가끔 merge가 실패할 수도 있다. 두 브랜치에서 같은 파일의 한 부분을 동시에 수정하고 merge하면 git은 해당 부분을 merge하지 못한다. git은 자동으로 merge하지 못하기 때문에 변경사항의 충돌을 개발자가 해결해야 한다.
충돌이 일어난 부분은 아래와 같이 표시된다. 위쪽의 내용은 HEAD버전 내용이고 아래쪽은 충돌된 브랜치 내용이다. 충돌을 해결하려면 위쪽이나 아래쪽 내용 중에서 고르거나 새로 작성해 merge한다.

<<<<<<< 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 명령으로 다시 git에 저장하면 된다.

3. 브랜치 관리

git branch 명령은 아무런 옵션 없이 실행하면 브랜치의 목록을 보여준다. * 기호가 붙어있는 브랜치는 현재 checkout해서 작업하는 브랜치를 나타낸다.

git branch

git branch -v 명령을 실행하면 브랜치마다 마지막 커밋 메시지도 함께 보여준다.

git brahcn -v

현재 checkout한 브랜치를 기준으로 --merged와 --no-merged 옵션을 사용해 merge된 브랜치인지 아닌지 필터링할 수 있다.

git branch --merged
git branch --no-merged

 

4. Rebase

rebase는 한 커밋에서 변경된 사항을 Patch로 만들고 이를 다시 다른 커밋에 적용시키는 방법이다. rebase명령으로 한 브랜치에서 변경된 사항을 다른 브랜치에 적용할 수 있다.

Git 브랜치 - 4. Rebase
두개의 브랜치로 나뉜 커밋 히스토리

위의 상태에서 rebase 하면 아래 그림이 된다.
두 브랜치가 나뉘기 전인 공통 커밋으로 이동하고 나서 그 커밋부터 지금 checkout한 브랜치(experiment)가 가리키는 커밋까지 diff를 차례대로 만들어 어딘가에 임시로 저장해놓는다. rebase할 브랜치(experiment)가 합칠 브랜치(master)가 가리키는 커밋을 가리키게 하고 아까 저장해놨던 변경사항을 차례대로 적용한다.

git rebase master

Git 브랜치 - 4. Rebase
C4의 변경사항을 C3에 적용하는 Rebase 과정

그 후 master브랜치를 fast-forward시킨다.

Git 브랜치 - 4. Rebase

 

Rebase vs Merge

로컬 브랜치에서 작업할 때는 히스토리를 정리하기 위해 rebase할 수 있지만, 리모트 등 어딘가에 push로 내보낸 커밋에 대해서는 절대 rebase하지 말아야 한다.



출처 : http://www.git-scm.com/book/en/v2

'공부 > ELSE' 카테고리의 다른 글

[Unity] AR Foundation 개요  (0) 2022.10.18
Git 사용법  (0) 2022.06.27
Git  (0) 2022.06.26
[K-MOOC] 인공지능 시대의 사회적 쟁점 - Privacy  (0) 2022.05.08

댓글