Git Bash를 이용한 git 기초 학습( branch와 merge )

2021. 2. 27. 01:23개발/Git

 몇가지 상황을 통해 로컬 저장소 생성, Commit, Branch 생성, Checkout(브랜치 이동), Merge, Merge 시 발생한 Conflict 해소에 대해서 정리합니다. Git을 사용하기 위한 툴은 git Bash를 사용했습니다.

 

 

작업 폴더명은 practice이며 (당연히) 텅텅 비어있다.

폴더생성

이제 이 practice 폴더를 로컬 저장소로 사용하려고 한다. 

git init 명령을 실행한다. 

git init 실행

 

 git init 명령어를 실행하고 폴더를 보면 .git이라는 폴더가 생긴걸 알 수 있다. .init은 로컬 저장소에 대한 각종 정보를 담고있다. ( 커밋 history , HEAD 포인터의 위치 등 ) 

.git 폴더 생성

경로 옆에 (master)가 생겼다. 이는 현재 내가 작업중인(HEAD가 가르키는) 브랜치가 master 브랜치라는 뜻이다.

 

sampe1.txt를 만들어 sample1.txt 파일을 작성하고 commit을 수행한다. 

sample1.txt 작성

생성한 파일을 staging 영역으로 보내고(add 명령어) commit을 수행했다.

 

현재 상태를 그림으로 그려보면 이렇다. 위에서 commit을 함으로써 70a507d로 시작하는 16자리 체크섬을 가지는 커밋 객체가 생성되었다. ( Git은 이 16자리 체크섬을 통해 commit 객체의 무결성을 보장한다. 편의를 위해 보통 앞 7자리만 표시된다. )

 

그리고 master branch가 commit객체를 가르키고 있는데 이뜻은 현재 브랜치가 70a507d 커밋의 스냅샷에 있다는 뜻이다. HEAD는 브랜치를 가르키는 포인터인데, 현재 작업중인 브랜치를 카르킨다. 아래 그림에서는 master 브랜치에서 작업 하고 있다는 걸 알려준다.

 

위 관계를 git Bash로도 확인할 수 있는데 git log --oneline --decorate --graph --all 명령어를 사용하면 된다. 

 

 

sample2.txt 라는 파일(This is sample2 라는 내용을 작성했다 )을 하나 만들고 commit을 수행한다. 

 

master 브랜치에서 작업을 하고 있기 때문에 commit을 하면 master branch의 포인터가 이동한다.

여기서 브랜치를 하나 추가해보자. 이름은 간단하게 feature로 했다. 

feature 라는 브랜치를 만들긴 했지만 HEAD를 옮기진 않았다. 

브랜치를 이동해보자. checkout 명령어를 사용한다. 

HEAD의 위치가 변경 된것을 알 수 있다. 

이제 sample2.txt 파일을 수정하고(Here is feature Branch!!!! 추가) commit을 해보자. 

 

(HEAD가 가르키는)feature에서 commit을 했기때문에 feature 브랜치만 이동한것을 알 수 있다.

그림으로 그려보면 아래같은 모양이다. 

 개발을 하다가 특정 기능을 한번 넣어보고 싶은데 master를 안정적으로 유지해야 하는경우라면 위 예시처럼 feature 브랜치를 생성하여 master에 영향을 주지않고 개발 및 테스트를 진행 할 수있다. 

 

만약 추가 기능을 성공적으로 테스트 했다면 master 브랜치를 최신의 커밋 객체를 가르키도록 할 차례다. 여기서는 master브랜치를 feature 브랜치가 가르키는 커밋 객체를 가르키도록 해보자.

이 경우 merge 명령어를 사용한다. 

 

먼저 checkout을 통해 branch를 이동한다. 

 master로 이동 후 잠깐 sample2.txt를 확인해보면 This is feature branch!!!! 라는 문구가 없다.

master에서 feature로 Merge 하기 위해서 merge 명령어를 사용한다. 로그를 확인해보면 master와 feature가 같은 commit 객체를 가르키는 것을 알 수 있다.

 그림으로 나타내면 아래와 같다. 이렇게 단순히 master 브랜치를 대상이 되는 feature 브랜치가 가르키는 커밋객체로 포인터만 이동하는 merge 방식을 fast-forward 라고 한다. ( 여기서는 master 브랜치가 feature 브랜치를 따라잡음 )

feature 브랜치에서 sample2.txt를 수정하고 commit을 하고 master 브랜치에서도 sample2.txt를 수정해서 커밋을 해보자. 

 

그 후 로그를 살펴 봤더니 커밋이 갈라져서 나온다.

 

그림으로 표현하면 아래와 같다.

feature 브랜치에서 sample2.txt를 수정했다. 그리고 master 브랜치에서도 sample2.txt가 수정되었다. 

master에서 merge 명령어를 수행해보자. 

CONFLICT(충돌)가 발생했으면 자동으로 merge 할 수 없다는 문구가 나온다.

 

git status 명령어를 통해 충돌이 발생한 파일을 확인할 수 있다.

 

sample2.txt 파일을 열어보니 아래와 같이 내용이 수정되어있다. 

=======를 기준으로 보면된다. 붉은색 부분이 HEAD가 가르키고 있던(master) 브랜치의 내용이다.

파란색 부분이 대상이 되는(feature) 브랜치의 내용이다.  그 윗부분인 This is sample2는 두 브랜치가 같은 위치에 같은 문자로 존재했기 때문에 충돌이 발생한 라인에서 제외되었다. 

사용자는 git이 제공한 정보를 보면서 직접 소스코드를 수정하면 된다. 

 

내용을 아래와 같이 수정했다.

문제의 sample2.txt를 staging Area에 올리고(add 명령어) commit을 하자.

로그를 찍어보니 2c86812 커밋 객체가 생성되면서 merge가 되었다. 

이를 그림으로 표현해보면 아래와 같다. 

위 merge 과정에서 생성된 2c86812 커밋 객체를 merge 객체라고 부르기도 한다. 이렇게 2개의 분리된 commit 객체를 하나로 합치는 방식을 3-way merge라고 한다.

 

feature 브랜치가 할 일을 다했다고 판단되면 이제 삭제해도 좋다. git branch -d 명령어를 사용한다.

로그를 확인해보면 feature 브랜치가 삭제된것을 확인할 수 있다.