본문 바로가기
Infra/GIT&GIT HUB

Git (7) : branch & merge

by jaeaemin 2021. 7. 17.

git의 기본 분기 및 병합

 ( 참고 : https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging )

 

git의 분기에는 fast forward 분기(빨리감기) , recurcive merge 분기로 나눌 수 있다.

먼저 C0 ~ C2까지 master branch에서 커밋하며 작업을 수행했다고 가정하자 

 

이 때 어떤 문제를 해결 하기 위해서 새로운 분기점 즉 새로운 branch를 만들고 동시에 전환하여서 그 branch에서 작업을 수행하려고 합니다. 

     $git branch iss53

     $git checkout iss53

그 후 문제에 대해서 해결하기 위해서 "iss53" 분기에서 커밋을 생성해가면서 작업을 진행합니다. 

    $ git commit -a -m "Create new footer [ issue 53 ]"

 

이 때 현재 배포된 프로그램(C2)에서 큰 오류가 발생하여 즉시 수정해야 한다는 상황이 발생하였다. 이 때는 master에 돌아가서 오류에 대해서 수정을 진행해야 한다. 이 때  작업 디렉터리 또는 스테이징 영역에 체크아웃하는 분기(master)와 충돌하는 커밋되지 않은 modified file이 있을 경우 git의 분기의 전환이 이루어지지 않는다. 따라서 지금은 모든 변경사항이 commit되었다고 가정한다.

     $ git checkout master 

 

그 후 오류문제를 해결하기 위해 hotfix라는 분기점을 새로 만들어 이 위급상황부터 해결한다고 가정하자

     $ git branch hotfix

     $ git checkout hotfix 

     . . . 

     $ git commit -a -m 'Fix broken email address'

위의 명령어를 통해 hotfix분기점에서 오류를 해결하기 위한 코드를 추가한 C4가 commit됬음을 확인 할 수 있다. 그 후 hotfix가 제대로 작동하는지 테스트하고 제대로 작동한다면 수정된 작업을 master branch에 병합하여 master 작업물에 포함하여 배포할 수 있다.

이 때 git merge 명령어를 통해 작업을 수행하자 

    $ git checkout master 

    $ git merge hotfix             //  master로 이동하여 merge hotfix  ==> master에 hotfix를 병합함

 

Updating f42c576..3a0874c

  Fast-forward index.html | 2 ++

  1 file changed, 2 insertions(+)

 

이 때 merge 명령어를 진행한 후에 "Fast-forward"라는 문구를 확인 할 수 있다. 병합을 하려한 branch C4가 현재 커밋(C2) 바로 앞에 있었기 때문에 새로운 commit을 만들어 복잡한 병합 처리를 할 필요 없이 C2 Git의 포인터를 단순히 C4 Git으로 이동시킨다.

즉, 첫 커밋의 히스토리를 따라 도달할 수 있는 커밋과 그 위치상의 커밋을 병합하려고 할 때 Git은 함께 병합할 분기 작업이 없기 때문에 포인터를 앞으로 이동하여 작업을 단순화한다. 이것을 Fast Forwarding ("빨리감기")라고 한다.

변경 사항은 이제 master branch가 가리키는 커밋의 스탭샷에 있으며 수정 사항을 배포할 수 있다. 

그 후 같은 C4를 가리키는 hotfix는 더 이상 필요하지 않으므로 분기를 삭제하는 것이 일반적이다. git branch -d hotfix를 통해 삭제한다.

 

 

그 후 어떤 문제를 해결하기 위해 작업중이던 iss53 분기에서의 작업을 이어나가고 C5 Git을 통해 수정을 완료하여 테스트까지 마쳤다고 하자 그렇다면 현재 Git의 분기를 도식화하면 아래와 같다.

이 때 유의할 점은 현재 master분기에 c4에는  iss53분기의 흐름의 c3 , c5에는 없는 hotfix에서의 수정본이 포함되어 있다는 점이다. 

즉 두 분기 모두 C2라는 공통된 커밋에서의 분기가 되었지만 , 각 각의 수정본이 하나의 흐름이 아닌 2개의 흐름으로 분류되어 처리되고 있다. 

이제 master분기와 iss53의 병합을 진행해보자. 위에서 언급했듯이 각 각은 다른 수정본을 포함하는 문제가 있어서 이를 위해 재귀적으로 hotfix지점 이전의 병합하려는 분기를 확인한 후 git merge 명령을 실행하여 문제를 해결 할 수 있다.

 

    $ git checkout master

Swiched to branch 'master'

    $ git merge iss53

Merge made by the 'recursice' strategy.

index.html |  1 +

1 file changed,  1 insertion(+)

 

이는 fast forwarding 분기와 다르게 수행되는데, 현재 있는 branch의 commit이 병합하려는 branch의 직계 조상이 아니기 때문에 git은 분기들이 가리키는 공통 조상과 병합하려는 분기들을로 3방향 병합을 수행한다.

일반적으로 병합에 사용되는 3개의 스냅샷

분기 포인터를 앞으로 이동하는 대신 Git은 이 3방향 병합의 결과로 새 스냅샷을 만들고 이를 가리키는 새 커밋을 자동적으로 만든다. 

이를 merge commit (병합 커밋)이라고 하고 둘 이상의 부모가 있다는 점에서 다른 commit들과 차별성을 둔다.

 

이 후 보면 새로운 C6커밋이 생성되고 c2, c4, c5를 토대로 만들어졌음을 확인할 수 있다. 이제 iss53은 필요하지 않으므로 분기를 삭제할 수 있다. 

 

 

기본 병합 충돌

 

위 과정이 매끄럽게 진행되지 않는다면, 병합하려는 두 분기에서 동일한 파일의 동일한 부분을 다르게 변경한 경우 Git에서 병합이 깔끔하게 병합되지 않는다. 

예를 들어 iss53에서 hotfix 분기에서 수정한 내용과 동일한 부분을 수정한 경우 아래와 같이 병합 충돌이 일어난다.

     $ git merge iss53

Auto-merging index.html

CONFLICT (content): Merge conflict in index.html

Automatic merge failed; fix conflicts and then commit the result.

 

Git은 새 병합 커밋을 자동으로 만들지 않는다. 충돌을 해결하는 동안 프로세스는 일시 중지되고, 병합 충돌 후 어느 시점에서 병합 해제되는지 확인하려면 git status를 사용하여 확인할 수 있다.

    $ git status

On branch master.

You have unmerged paths.

   (fix conflicts and run "git commit").

 

Unmerged paths:

   (use "git add <file>..." to mark resolution)

 

    both modified: index.html.

 

no changes added to commit (use "git add" and/or "git commit -a")

 

위의 내용을 살펴보면 병합 충돌이 생겼고, 해결되지 않은 모든 항목은 병합되지 않은 것으로 나열된다. GIT은 충돌이 있는 파일에 표준 충돌 해결 마커를 추가하고 수동으로 파일을 열어 충돌을 해결할 수 있다.

헤더를 살펴보면 master지점의 HEAD에서의 상단 부분 ===== 동안 iss53하단 부분에 모든 것을 같은 지점으로 복사하거나 , 어떤 쪽을 선택하여 콘텐츠를 직접 병합해야한다. 

반응형

'Infra > GIT&GIT HUB' 카테고리의 다른 글

Git (9) : 병합 충돌 & n way-merge  (0) 2021.07.20
Git (8) : stash (임시저장)  (0) 2021.07.18
Git (6) : branch  (0) 2021.07.12
Git (5) : Reset , Revert 기초  (0) 2021.07.09
Git (4) : 버전관리  (0) 2021.07.08