3. Git Branch (분기점)

정현우·2021년 9월 11일
2

Git Basic to Advanced

목록 보기
3/9
post-thumbnail

Git branch

git의 사용 이유와 정수를 보여주는 '가지치기' (1장에서 언급)에 대해 알아보자

Git branch란?

  • 독립적으로 어떤 작업을 진행하기 위한 개념이다.
  • 각각의 branch는 다른 branch의 영향을 받지 않는다. (merge 등의 작업을 하지 않는 이상)
  • 브랜치를 만들고, 여러 작업을 독립적으로 진행 한 뒤, 각 브랜치들을 하나로 모두 병합하는 것을 살펴보자.

1. branch 생성하기

  • git branch like_feature(이름)으로 브랜치를 생성할 수 있다.
  • 그러면 아래와 같이된다. master는 자동으로 생성되는, 기본이 되는 브랜치다.

2. branch 이동하기

  • checkout이라고 불리는 개념이다.
git branch # branch list를 확인할 수 있다. 
git checkout like_feature # 해당 브랜치로 브랜치를 변경할 수 있다. 
git checkout -b like_feature # 브랜치를 만들고, 바로 이동까지 하는 명령어다.
  • checkout을 하면 아래 그림과 같이 HEAD가 우리가 만들고, 지금 이동한 브랜치를 가르키고 있다. HEAD는 (2)장 '파일 상태 되돌리기' 에서 잠깐 언급을 했었다.

  • checkout은 branch를 전환하는데 사용할 수 있고, 아래와 같이 git log 로 확인한 snapshot을 넘나들때도 사용이 가능하다.
  • 아래 사진에서 git log로 snap shot hash값을 보고, 옮기면 된다.
  • git checkout <snapshot hash>

  • snapshot의 hash값 이용해 과거의 파일 내용을 확인 할 수 있다.

Git branch 병합, merge

1. fast-forward 방식의 병합

  • 위 브랜치 like_feature 로 이동해서 작업을 했고, add와 commit을 했다고 하자.

  • 그러면 위와 같이 HEAD는 like_feature를 가르키고 있는 상태에서, 새로운 커밋이 생기고 저장저이 생긴것이다. master 브랜치로 이동해서, like_feature를 합쳐보자.
git checkout master
git merge like_feature # 해당 브랜치를 '합친다' 는 명령어다
  • 위와 같이 merge를 진행하면, 아래 그림과 같이 c2(커밋2)를 가르키던 master브랜치는 c3으로, head는 master로, like_feature의 모든 내용들은 master로 합쳐진다.

  • like_feature 의 이력은 master의 이력을 모두 포함하고 있고, '업데이트 된 내용(새로운 내용)'만 가지고 있는 브랜치를 merge해서 곧바로 되고, 이렇게 이뤄지는 merge가 fast-forward 방식이다.

2. merge commit (non fast-forward)

  • 위와 다르게, 아래 그림처럼 브랜치가 갈라지고, 합쳐져야 할 두 브랜치의 이력(커밋)이 다르다면 어떻게 되는 것일까?

git checkout master
git merge like_feature
  • fast-forward 와 같은 방식으로 merge를 진행하면 아래 그림과 같이 진행이 된다.

  • fast-forward와 다르게 커밋 지점이 c5로, 이전 경우와 다르게 새로운 지점을 가르키고 있다.
  • like_feature 브랜치는 목적을 다 달성 했기 때문에 삭제를 진행하면 된다. -> 여기서 알 수 있듯이, 흔히 'feature'를 붙이는 브랜치 명은 '해당 브랜치 당 하나의 목적 / 기능'을 명시하고 있다.
  • git branch -d like_feature 로 브랜치 삭제가 가능하다.

  • git log --graph --pretty=oneline --all 명령어를 통해서 해당 커밋지점과 같이 브랜치들이 어디에서 나오고, 어디에 합쳐지는지 확인이 가능하다.
  • 사실 fast-forward 경우, merge 옵션을 아래와 같이 줘서 무조건 새로운 커밋 지점을 만들고 병합하는 non fast-forward 도 가능합니다.
  • git merge --no-ff like_feature # 즉 디폴트는 그냥 --ff 옵션이라는 것

3. 3way 방식의 병합

  • 실제 협업을 하면서 가장 많이 이뤄지는 방식의 merge 형태다. 위 like_featrue로 다루는 것이 아니라, 전혀 다른 경우를 살펴보자. 출처 / 클릭

  • 위 fast-foward 방식에서 다시 출발해 보자. 아래의 다른 사진이지만, 같은 경우이다. master는 그냥 c3 커밋을 가르키기만 하면 fast-forward merge의 끝이다.

  • 하지만 위 상황에서 master 에서 hot fix를 해결하는 코드를 만들기 위해 'hotfix'브랜치를 하나 파서 코딩 후 add, commit을 했다고 가정을 하자. 그러면 아래 그림과 같이 된다.

  • 그러면 위 같은 그림이 된다. master 입장에서는 두 개를 차근 차근 순차적으로 병합을 할 것 이다. hotfix 브랜치 부터 merge를 해보자.

  • hotfix는 해결이 되었으나, iss53 브랜치는 기능 개발을 따로 계속 진행 중이다. / 실제로 우리가 협업으로 버전관리를 할때는 브랜치들이 다 따로 기능개발을 하고 있을 테니 말이다.

  • 이제 master는 non fast-foward로 c4 기점으로 merge를 했고, iss53 브랜치 기능 개발이 끝나 이제 merge를 해야한다.
  • 여기서 핵심은 C4가 C5와는 같은 조상이 아니라서 (위에서 분기점이 갈린 점을 생각하자) 절대 fast-forward merge를 하지 않는다.

  • 3way merge의 최종 결과는 위 이미지와 같다. 3way merge의 결과를 별도의 커밋으로 만들고 해당 브랜치가 그 커밋을 가리키도록 이동시킨다. 그 커밋은 C6이고 해당 커밋의 부모는 여러개가 되어있는 것을 볼 수 있다.
  • 이때, 3way merge에서 merge conflict가 발생할 수 있는 것이다. merge하는 두 브랜치에서 같은 파일의 같은 부분을 동시에 수정하게 되면 git은 해당 부분을 merge를 하지 못한다.

Git merge conflict

conflict 해결

  • merge한 두 branch에서 '같은 파일' 을 변경했을 때 충돌이 발생한다. (충돌 발생의 예시는 사실 3way merge에서 그 이유가 상세하게 드러난다!!)
  • 충돌이 발생했으면, git에서 automatic merge를 해주진 않고, 개발자가 해당 부분을 해결하고 다시 merge를 해줘야만 한다!

  • 위 사진의 경우 conflict를 해결해 보자.
  • git status로 어느 파일에서 충돌이 발생했는지 확인이 가능하다.
  • 위 명령어를 치면 "both modified" 라고 어떤 파일에서 동시 수정이 일어났는지 가르쳐 준다. 해당 파일을 확인해보자.

  • head가 무엇인지 충분히 이제 숙지를 했을 것이다. head가 가르키는 commit의 snapshot에서는 해당 내용이, like_feature 브랜치의 commit의 snapshot에서는 아래의 내용이 있다는 것을 명시한다.
  • 이제 충돌이 난 두 코드 중 어떤 부분을 선택할지 또는 둘 다 혼합할지 직접 수정을 해줘야 한다.

  • 특수 기호가 포함 된 부분을 모두 삭제해주고 다시 git add / git commit 을 다시 진행하면 conflict가 풀리고 merge 진행이 된다.

conflict 방지, 정리

  • 우선 conflict는 무조건 날 수 있다. conflict를 무조건 적으로 막는 것이 아니라, 당연히 일어날 수 있는 부분은 수용을 하고 해당 commit을 잘 '정리' 해줘야 한다.
  • 그리고 기본적으로 master가 되는 브랜치는 직접 수정을 하거나 접근하는 일은 없도록 해야 올바른 브랜치 사용이자 기본적은 충돌 예방이다. master는 무조건 배포가 바로 가능한 안정적인 버전만 유지되어야 한다.
  • commit을 정리 하는 방법에 대해서는 rebase / commit --amend / merge --squash (스쿼시 머지) 정도로 볼 수 있다. 물론 때에 적절한 reset은 당연하다.
  • 위 '정리' 에 대해 다음 장에서 rebase를 살펴보며 살펴보자.
profile
도메인 중심의 개발, 깊이의 가치를 이해하고 “문제 해결” 에 몰두하는 개발자가 되고싶습니다. 그러기 위해 항상 새로운 것에 도전하고 노력하는 개발자가 되고 싶습니다!

0개의 댓글