ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [git] git 잘 사용하기.
    카테고리 없음 2024. 7. 15. 16:09
    728x90

    [git] git 잘 사용하기.

     

    cmd + z는 mac os에서 변경사항을 이전으로 되돌릴 수 있는 단축키이다. 이 단축키 덕분에 무언가를 작성하거나 만들다가 실수를 하여도 되돌릴 수 있기 때문에 걱정이 없다.

     

    우리가 개발을 할 때에도 코드를 작성하다 문제가 생기면 cmd + z, cmd +shift + z를 사용하여 되돌리고, 되돌린 걸 되돌리는 것이 가능하다. 그런데 이렇게 되돌리는 것은 부분적으로만 가능하지, 프로젝트 전체의 형상을 되돌리기는 불가능하다.

    이런 문제를 해결하기 위해 사용 가능한 것이 git이다. git은 프로젝트의 특정 시점을 저장하고, 원하는 시점으로 이동할 수 있게 도와준다. 마치 4차원 세계의 w 축처럼 말이다.

     

    git으로 모든 문제가 해결되었다면 다행이다. 하지만 그렇지 않다. git은 형상 관리를 해주지만, 여러 팀원과 함께 협업할 경우에는 쉽지 않다. 소스코드를 공용 클라우드에 저장하여 공용으로 형상관리를 할 수 있도록 도와주는 것이 git hub이다. git hub에서는 소스코드 호스팅뿐만 아니라 pull request나 git hub action과 같은 git을 활용한 다양한 도구를 제공해 준다.

     

    git과 git hub을 잘 활용하기 위해 채택할 수 있는 방법은 여러 가지가 있지만, 오늘은 그중에서도 merge 방법과 브랜치 전략에 대해 집중적으로 생각해 볼 것이다.

     

    git flow

    git에는 branch라는 아주 중요한 요소가 있다. 예를 들어 비빔밥을 만든다고 해보자. 계란프라이도 만들고, 나물도 무치고, 밥도 짓고 해야 하겠지? 그런데 이 모든 것을 하나의 프라이팬에서만 요리한다면 어떻게 될까. 각 요리가 다른 요리에 영향을 끼치고 순서도 뒤엉킬 것이다. 이런 문제를 해결하기 위해 branch를 사용한다. branch가 개별의 프라이팬, 냄비, 밥솥의 역할을 한다. 물론 완성된 음식이 나오는 그릇의 역할을 하는 branch, 다 만들어진 음식에 소스를 추가하기 위한 국자의 역할을 하는 branch도 있다.

     

    git flow는 가장 대표적인 branch 관리 전략이다.

     

    git flow는 main, develop, feature, release, hotfix의 5가지 branch로 구성되어 있다.

    • main branch에서는 배포된 서비스의 형상을 관리한다.
    • develop branch에서는 다음으로 출시할 버전을 개발한다.
    • feature branch에서는 세부적인 기능을 개발한다.
    • release branch에서는 새로운 버전의 release를 준비한다.
    • hotfix branch에서는 긴급 수정사항을 처리한다.

    각 branch들이 기능별로 git에 정의되어 있는 것은 아니고, 사용자가 유동적으로 이름을 붙이고 처리할 수 있다. non-blocking i/o처럼 제어권은 사용자에게 있다.

     

    merge

    어떤 branch 전략을 채택하든 간에 branch가 있다면 merge는 꼭 해야 한다. merge는 두 개 이상의 branch를 하나로 병합하는 것을 말하는데, 이도 여러 방법으로 나뉜다

     

    fast forward merge

    • 병합 대상인 branch가 최신 커밋 바로 뒤에 있을 경우 사용한다. 
    • 병합 커밋을 생성하지 않고 단순히 포인터만 가져온다.
    • 병합 이력이 남지 않아 깔끔하지만, 추적하기 어렵다.

    no fast forward merge

    • 항상 병합 커밋을 생성한다.
    • 병합 이력이 명확하게 남아 추적에 용이하다.
    • 히스토리가 복잡해질 수 있다.

    squash merge

    • 병합할 branch의 모든 커밋을 하나로 압축하여 병합한다.
    • 히스토리가 깔끔해져 단순한 상태를 유지할 수 있다.
    • 개별 커밋이 사라져 세부 사항 추적이 어렵다.

    rebase and merge

    • 병합할 branch의 커밋을 현재 브랜치 위로 재적용 한다.
    • 히스토리가 깔끔해지며, 직렬화된다.
    • 충돌 시의 해결이 복잡해질 수 있다.

     

    이렇게 다양한 merge 방법이 있는데, 도대체 뭘 사용해야 할까? 일반적으로는 develop에 feature를 merge 할 때에는 feature의 지저분한 이력을 간소화하기 위해 squash merge를 사용하고, main에 develop을 merge할 때에는 선형 히스토리를 위해 rebase and merge를 사용한다고 알고 있었다.

     

    그런데 이건 틀렸다. 잘 생각해 보자. squash merge는 그동안의 커밋들을 하나로 압축하여 깔끔한 히스토리를 유지시켜 준다고 했다. 그런데 git은 어떤 도구인가? 형상 관리 도구이다. 기록된 오던 형상들을 하나로 압축시켜서 단지 보기에 깔끔한 것이 과연 좋은 것일까?

     

    최근 nextjs와 shadcn ui base의 모노레포를 만지다 어느 순간부터 shadcn ui 컴포넌트에 스타일이 입혀져있지 않은 모습을 보았다. 로컬에 유지되어 있는 형상으로는 도저히 문제의 원인을 확인할 수 없었다. 그래서 develop branch의 커밋 히스토리를 이진탐색으로 뒤져보았고, 금방 문제가 되는 커밋을 확인할 수 있었다. 이 시점까지는 no fast forward merge를 채택했기 때문에 다행이지만, 만약 squash merge를 채택했었다면? 커밋 히스토리가 하나로 묶여 있었을 거 기 때문에 아마 문제가 되는 커밋을 찾는 데까지 굉장히 많은 리소스를 소모해야 하지 않았을까?

     

    결론.

    그래서 git을 잘 사용하는 방법은 무엇일까?

    바로 위 이야기에 따르면 no fast forward merge가 가장 좋은 건가? 하고 생각할 수 있다. 지금 내 시점에서는 그렇지만, 절대적이지 않다. 내 선배분의 회사에서는 바쁜 나머지 git 히스토리를 신경 쓰지 못해 나이스하게 관리가 되지 않아 squash merge를 사용하여 관리한다고 하였다. 결국 본질적인 이유에 대해 이해하고, 상황에 따라 적절한 방법을 채택하는 것이 git을 가장 잘 사용할 수 있는 방법이라 생각한다.

     

     

    마지막으로 현재 우리 팀에서 논의 중인 git flow base의 branch 전략을 공유하고 마무리한다.

    `merge: ->`
    
    ### branch
    `main`: 배포 branch
    `develop`: 다음 출시 버전 개발
    `feature/**`: 새로운 기능 개발
    `release/**`: 새로운 버전의 릴리스 준비
    `hotfix/**`: 긴급 수정 처리
    
    ### workflow
    기능 개발: main -> feature 생성. feature -> develop 병합
    
    개발 테스트: feature -> develop 병합 이후 develop 테스트
    
    릴리스 준비: main -> release 생성. develop -> release 병합. 혹은, feature -> release 병합(긴급 기능)
    
    최종 릴리스: release -> main 병합
    
    개발 브랜치 최신화: main 형상으로 develop hard reset
    
    긴급 수정
    - release 존재 시: release -> hotfix 생성.
    - release 부재 시: main -> hotfix 생성.
    728x90
Designed by Frorong.