04. branch, merge

branch란?

소프트웨어를 개발할 때 동일한 소스코드를 함께 다루게 된다. 어떤 개발자는 버그를 수정하고, 어떤 개발자는 새로운 기능을 추가하고...
따라서 여러 사람이 동일한 소스코드를 기반으로 서로 다른 작업을 할 때는 각각 서로 다른 버전의 파일이 만들어 질 수 밖에 없다.

이런 경우, 동시에 다양한 작업을 할 수 있게 만들어주는 것이 branch(브랜치)다. branch는 독립적인 작업 영역에서 작업을 할 수 있게 해준다.

나뉘어진 branch들은 다른 branch와 merge를 통해 하나의 branch로 합칠 수 있다.
Pasted image 20231010112129.png

main(master) branch

repository를 처음 만들면 main이라는 이름의 branch를 만든다. 모든 branch의 기본이 되는 branch다.

branch의 종류

Integration Branch (통합 브랜치)

언제나 배포할 수 있는 버전을 가진 branch다. 버그나 새로운 기능을 추가해야 하는 일이 생길 때, 통합 branch에서 토픽 branch를 만든다.
일반적으로 master branch를 통합 branch로 사용한다.

Topic Branch (토픽 브랜치)

버그 수정이나 기능 추가와 같은 단위 작업을 위한 branch이다. 필요한 수 만큼 branch를 생성할 수 있다. 보통 통합 branch로부터 만들어내며 토픽 branch에서 작업이 완료되면 다시 통합 branch로 merge한다.

branch 만들기

다음과 같은 명령어로 branch를 만들 수 있다.

git branch <branchname>

Pasted image 20231010112831.png|400

옵션을 지정하지 않고 branch 명령어를 실행하면 생성된 전체 branch 목록을 확인할 수 있다. (* 가 붙은 branch가 현재 branch다.)

git branch

Pasted image 20231010113114.png|400

branch 전환하기

branch를 전환할 때는 checkout 명령어를 사용한다.

git checkout <branchname>

Pasted image 20231010113215.png|400

현재 시점에서 HEAD가 master에서 first-branch로 넘어갔다.

HEAD

HEAD란 현재 branch의 선두 부분을 나타내는 이름이다. 기본적으로는 master의 선두 부분을 나타낸다. HEAD를 이동하면 현재 branch가 변경 된다.

-b

checkout 명령어에 -b 옵션을 넣으면 branch 생성과 checkout을 동시에 할 수 있다.

git checkout -b `<branchname>` 

branch 병합하기 (merge)

현재까지 이력은 다음과 같다.
Pasted image 20231010114610.png|400

branch 병합은 merge 명령어로 실행한다. 명령어에 merge할 commit 이름을 넣으면 지정한 commit 내용이 HEAD가 가리키고 있는 branch에 넣어진다.
따라서 현재 상황에서는 master branch에 first-branch를 넣기 위해서는 HEAD가 master branch를 가리키게 만들어야 한다.

git checkout master

branch를 변경 후 수정했던 파일을 다시 열어보면 수정 이전으로 되돌아 간것을 확인할 수 있다. 이제 merge를 해보자.

git merge first-branch

Pasted image 20231010114828.png|400

이제 master branch가 가리키는 commit이 first-branch와 같은 위치로 이동했다. 이런 식의 merge 방법을 fast-foward (빨리감기) 병합이라고 한다.

branch 삭제하기

first-branch의 내용이 master branch와 통합되었기 때문에 더 이상 first-branch가 필요 없어졌으므로 삭제를 해보자. 다음과 같이 branch를 삭제할 수 있다.

git branch -d <branchname>

Pasted image 20231010115039.png|400

동시에 병렬적으로 branch 작업 해보기

우선 브랜치를 2개 만들고 첫 번째 만든 branch로 checkout 해보자.

Pasted image 20231010115146.png|400

이 상태에서 work tree 안에 있는 파일을 수정 후 commit 하자

Pasted image 20231010115337.png|400

이제 bug2로 checkout 한 뒤 파일을 수정하고 commit을 해보자.

Pasted image 20231010115457.png|400

현재까지 상황을 그림으로 표현하면 다음과 같다.
Pasted image 20231010122258.png|400

conflict 해결하기

이제 branch bug1과 bug2를 master branch에 merge 해보자.
우선 master로 checkout 한 후 bug1 branch를 merge 한다.

Pasted image 20231010122533.png|400

Pasted image 20231010122642.png|400

이제 bug2 branch를 merge 하자.

Pasted image 20231010122709.png|400

그러면 충돌이 일어났다는 알림 메시지가 출력된다. 충돌이 일어난 파일을 열어 충돌난 부분을 수정한 후 다시 커밋하자.

지금까지의 이력을 보면 다음과 같다.
Pasted image 20231010123634.png|400

conflict

git에서 branch간 merge를 진행하다보면 conflict(충돌)이 발생하는 경험을 한 번쯤은 겪을 것이다. merge를 더 쉽게 하기 위해선 우선 conflict가 왜 발생하는 것인지 알아보자.

merge 전략에는 크게 2가지가 존재한다.

2 way merge

마지막 commit 2개만을 비교하는 전략이다.

base 내가 작업 동료가 작업 merge 결과
A A A A
B B1 B Conflict
C C C1 Conflict
D D1 D2 Conflict
즉, 내가 작업한 마지막 commit과 동료가 작업한 마지막 commit만을 비교한다. 따라서 A를 제외한 나머지는 서로 commit내역이 다르기 때문에 conflict가 발생한다.

3 way merge

branch의 마지막 commit과 base (공통 부모)를 비교하는 전략이다.

base 내가 작업 동료가 작업 merge 결과
A A A A
B B1 B B1
C C C1 C1
D D1 D2 Conflict

공통 조상도 같이 비교를 하기 때문에

  1. A의 경우 나도, 동료도 작업내역이 없으므로 A
  2. 나는 B1으로 작업했고, 동료는 B로 작업했다. 하지만 base를 보니 B였고, 동료는 작업하지 않은 것으로 간주하여 B1으로 merge된다.
  3. 나는 C로 작업했고, 동료는 C1으로 작업했다. 하지만 base를 보니 C였고, 나는 작업하지 않은 것으로 간주하여 C1으로 merge된다.
  4. 나는 D1으로 작업했고, 동료는 D2로 작업했다. base와 비교해보니 둘 다 일치하지 않았다. 이 경우는 conflict가 발생한다.

다음 글: 05. stash