Git

Git: 브랜치(Branch) 1. 브랜치 생성, 변경, merge, 제거

vcxz 2023. 11. 20. 08:50

 

 


브랜치에 대하여

브랜치는 커밋 사이를 이동할 수 있도록 만든 포인터라고 볼 수 있습니다.

브랜치와 커밋 히스토리

위 그림에서 'v1.0' 브랜치와 'master' 브랜치 모두 f30ab 커밋을 가리키고 있습니다.

HEAD는 현재 보고 있는 브랜치를 가리키는 것으로, 그림에서 HEAD는 master 브랜치를 가리키고 있으므로 현재 master 브랜치에서 작업 중인 상황임을 알 수 있습니다.

 

동일하게 포인터 역할인 태그와 비교하면, 브랜치는 커밋을 할 경우 이를 따라간다는 차이점이 있습니다. 즉 브랜치는 그 이름처럼 가지를 트는 것과 비슷합니다. 프로젝트의 여러 부분을 작업 공간을 분리하여 작업하거나, 여러 사람이 서로에게 직접적으로 영향을 주지 않으면서 작업을 할 수 있습니다.

 

또한 브랜치는 다른 브랜치로 갈라졌다가도 다시 하나로 합쳐질(merge) 수 있다는 점이 핵심입니다. 이는 결국 한 저장소의 모든 브랜치는 동일한 조상(커밋)을 갖기 때문에 가능합니다. 따라서 프로젝트의 어떤 부분을 따로 분리해서 작업하다가 완성되면 현행 프로젝트(브랜치 시점으로부터 변경이 있는 경우에도)에 다시 합치는 방법 등으로 사용할 수 있습니다.

브랜치 생성하기

git branch <브랜치 이름>

만들어진 브랜치는 현재 작업 중인 커밋 버전을 가리킵니다. 따라서 특정 커밋을 가리키는 브랜치를 만드려면 해당 커밋 버전을 꺼낸 후 생성해야 합니다.

testing 브랜치 생성

'testing'이라는 브랜치를 만들었을 경우 위와 같은 모양새가 됩니다.

현재 보고 있는 브랜치를 가리키는 HEAD가 아직 master 브랜치를 가리키고 있습니다.

브랜치 바꾸기

# 브랜치 바꾸기
git checkout <브랜치 이름>
git switch <브랜치 이름>

# 브랜치 생성하면서 바꾸기
git checkout -b <브랜치 이름>
git switch -c <브랜치 이름>

testing 브랜치로 변경

testing 브랜치로 바꾸면 HEAD가 testing 브랜치를 가리키게 됩니다.

이 상태에서 커밋을 하면 아래의 상황이 됩니다.

testing에서 커밋

master는 여전히 브랜치 생성 시점 커밋을 가리키지만(behind) testing은 한 커밋 더 앞서(ahead) 있습니다.

여기서 다시 master 브랜치로 변경하면 HEAD가 master를 향합니다.

다시 master 브랜치로 변경

master 브랜치로 변경하였으므로, 다시 워킹 디렉토리도 마지막으로 master 브랜치에서 작업하였던 상태가 됩니다.

여기서 아까 testing에서 커밋한 내용과는 다르게 커밋을 하면,

master에서 커밋

master와 testing이 서로 다른 방향을 향하게 되었으므로 더 이상 연속상에 있지 않습니다.

다만 나중에 merge하여 두 브랜치를 합치는 건 가능합니다.

이러한 상황은 git log --oneline --decorate --graph --all을 실행하여 쉽게 확인할 수 있습니다.

브랜치 합치기

# 현재 작업 중인 브랜치와 특정 브랜치를 합침
git merge <브랜치 이름>

브랜치를 합쳤을 때 어느 쪽도 제거되지는 않습니다. 두 브랜치 모두 같은 커밋을 가리키게 될 뿐입니다.

 

master 브랜치를 기본 브랜치로 두고, 각각 다른 작업을 위주로 하는 hotfix와 iss53 두 브랜치가 존재하는 시나리오로 예를 들어보겠습니다.

master&#44; hotfix&#44; iss53 브랜치

master 브랜치가 가리키는 C2를 기점으로 hotfix는 C4, iss53은 C3에 있습니다.

이때 hotfix 브랜치의 역할을 다 하였다면 master와 합칩니다.

master와 hotfix 합치기

hotfix는 master의 연속상에 있는 것이므로, 이 merge는 단순히 master를 hotfix로 옮깁니다. 이를 fast forward라고 합니다.

이제 hotfix 브랜치를 제거하고, iss53에서의 작업을 마무리합니다.

iss53 마무리

iss53 작업을 마무리했다면 다시 master와 합칩니다. 이는 master와 iss53이 C2 커밋이라는 공통 조상 커밋을 갖고 있으므로 가능합니다. C2를 기반으로, (C2, C5)의 변경점과 (C2, C4)의 변경점을 합쳐 새로운 커밋을 만듭니다. 이를 3-way merge라고 합니다.

3-way merge

fast forward와 달리 새로운 커밋(C6)이 생성되었으며, 두 경로가 다시 하나로 합쳐졌습니다.

merge 커밋

Merge 충돌

3-way merge는 서로 연속되지 않은 브랜치를 합치는데, 각 브랜치가 동일한 이름의 파일이지만 다른 내용을 갖고 있을 수 있습니다. 그러면 merge가 불가능한데, 이런 상황을 merge 충돌이라고 합니다. 이때는 개발자가 직접 해당 파일을 건드려야 합니다.

 

우선 git status를 사용하여 어떤 파일이 충돌되는지 살펴볼 수 있습니다. 그리고 현재 워킹 디렉토리에서 해당 파일을 열어보면 충돌한 부분이 표시되어 있습니다.

# 충돌 내용 예시
<<<<<<< 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로 stage한 후 커밋하면 merge를 완료할 수 있습니다.

브랜치 정보 확인하기

# 브랜치 목록 출력
git branch
#  iss53
#* master
#  testing

*이 붙은 브랜치가 현재 checkout 중인(HEAD가 가리키는) 브랜치입니다. 위 출력 예시에서는 master가 해당합니다.

따라서 브랜치 변경 없이 커밋을 하면 master 브랜치가 한 단계 나아가게 됩니다.

# 브랜치별 마지막 커밋에 대한 체크섬과 커밋 메시지 출력
git branch -v
#  iss53   93b412c fix javascript issue
#* master  7a98805 Merge branch 'iss53'
#  testing 782fd34 add scott to the author list in the readmes

-v 옵션을 사용하면 브랜치별 정보를 확인할 수 있습니다.

# 현재 브랜치와의 merge 여부 확인
git branch --merged
#  iss53
#* master
git branch --no-merged
#  testing

# 특정 브랜치와의 merge 여부 확인
git branch --merged <브랜치 이름>
git branch --no-merged <브랜치 이름>

--merged 옵션은 현재 브랜치와 merge된 브랜치 목록을 출력하고(현재 브랜치 포함), 반대로 --no-merged는 현재 브랜치와 merge되지 않은 브랜치 목록을 출력합니다.

위 출력 예시에서 iss53은 master와 merge된 상태이므로, master와 동일하기 때문에 제거해도 데이터를 잃지 않습니다.

반면 testing은 master와 merge되지 않은 상태이므로, master에 없는 데이터가 있기 때문에 제거하면 데이터를 잃습니다. 또한 강제 제거하지 않는 이상 제거할 수도 없습니다.

브랜치 제거하기

git branch -d <브랜치 이름>

다만 현재 HEAD가 가리키는 지점에서 갈 수 없는(merge되지 않은) 브랜치는 삭제할 수 없습니다.

그러한 브랜치를 제거하려면 현재 브랜치와 merge를 완료 후 제거하거나, 강제로 제거해야 합니다.

git branch -D <브랜치 이름>

 

 

 

 


위 내용은 Git Book을 바탕으로 작성하였습니다.

 

Git - 브랜치란 무엇인가

3.1 Git 브랜치 - 브랜치란 무엇인가 모든 버전 관리 시스템은 브랜치를 지원한다. 개발을 하다 보면 코드를 여러 개로 복사해야 하는 일이 자주 생긴다. 코드를 통째로 복사하고 나서 원래 코드와

git-scm.com