ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 모노레포 환경을 더욱 가볍게 - git sparse checkout
    개발 블로깅/팀 문화 및 시스템 2022. 5. 28. 00:46

     

    현재 모노레포를 사용하면서 어떻게 하면 우리 팀원 모두가 모노레포를 더욱 안정적으로 사용할 수 있을지 많은 고민과 실험 중에 있다.

    여러 개선할 점 중 하나가, 모노레포를 내 로컬에서 이용할 때 너무 무거운 느낌, 그리고 여러 프로젝트가 함께 섞여 있다 보니 파일 찾는 점에 어려움이 있다는 단점이 많은 팀원들의 의견이다.

    그래서 어떻게 하면 많은 파일들을 가지고 있는 모노레포를 조금이라도 안정적으로 가볍게 사용해볼 수 있을까 리서치를 하다가 팀원 중 능력자 @yeoul을 통해 git sparse checkout라는 멋진 git 커맨드를 알게 되어서 이를 한번 정리해 보려고 한다.

    그전에 우리가 평소 사용하던 git checkout이란 기능에 대해 더 자세히 알 필요가 있다. 우리가 흔히 새로운 브랜치를 따거나, 다른 브랜치로 커밋 상태를 이동할 때 사용하는 git checkout은 어떤 방식으로 동작하는 것일까?

     

    # git checkout

    일반적으로 git clone 및 checkout을 하면, 해당 레포지토리 전체적으로 그 브랜치의 커밋 상태로 이동하면서 기존에 켜져 있던 파일들은 내 로컬에서 사라지고 커밋 당시의 파일 상태들이 화면에 띄어지게 된다.

    git에서는 어떻게 이전의 히스토리를 자유롭게 내 로컬 PC에 띄울 수 있는 것일까?

    https://marklodato.github.io/visual-git-guide/index-ko.html

     

    git의 구조를 보면 git commit을 할 때마다 새롭게 생성한 hash 값을 이용하여 git tree에 추가되는 형식이다. 우리가 git add를 하고 git commit을 하면 프로젝트 내 .git 폴더 안의 데이터들과 해시들이 현재 내 커밋 당시의 파일들의 정보로 저장하게 된다. 그리고 각 저장된 commit 단위를 hashID로 관리하게 된다.

    이러한 여러 커밋 중, 하나의 커밋에 대해 checkout을 하게되면, 당시에 커밋했을 때에 대한 내용들이 Working Directory라는 공간에 새롭게 추가가 되면서 우리 로컬 PC에 해당 커밋 상태의 파일들이 표시되게 되는 것이다.

    따라서 git checkout이란, 특정 커밋 상태의 요소를 working Directory 공간으로 넣는 작업이라 정리할 수 있겠다.

     

    모노레포에서 git checkout에 대한 문제점

    git commit 현재 프로젝트의 모든 파일 상태를 기준으로 커밋 상태를 저장하게 된다. 그리고 git checkout은 그 커밋의 모든 상태를 working Directory로 가져오게 된다.

     

    그런데 모노레포에서 각 개발자들이 작업할 때는 레포 내 파일 전체에서 극히 일부만 확인하는 반면에, git checkout으로 Working Directory로 파일 정보를 가져올 때는 모노레포 전체 파일 대상으로 Working Directory로 가져오게 된다.

    모노레포 내 관리하는 프로젝트가 많아질수록, Working Directory에 옮겨지는 불필요한 파일 수가 많아지게 된다.

     

    예를 들어 아래와 같은 모노레포가 있다고 생각해보자.

    client/
        android/
        electron/
        iOS/
    service/
        common/
        identity/
        list/
        photos/
    web/
        browser/
        editor/
        friends/
    boostrap.sh
    LICENSE.md
    README.md

     

    위와 같이 client, service, web이라는 크게 3개의 디렉토리를 가지고 있고, 현재 내가 작업할 부분은 client 프로젝트 중 일부인 android 프로젝트이다.

    그러나 막상 작업하려고 git checkout을 하면, 내 로컬 PC에 모노레포 내에 있는 모든 코드들이 전체적으로 checkout 한 커밋 상태로 변경이 일어나면서 Working Directory로 옮겨지게 된다. 따라서 내가 실제로 작업할 코드뿐 아니라 모든 코드들이 내 로컬에서 존재하게 되면서 모노레포 이용에 복잡함을 느낄 수 있다.

     

    그러면, 전체 커밋 파일에서 내가 실제로 들여다 볼 파일들만 Working Directory로 가져오고 싶으면 어떻게 할 수 있을까?
    이때 사용할 수 있는 것이 git sparse checkout이다.

     

    # git sparse checkout

    git sparse checkout을 이용하면, 내가 원하는 디렉토리 및 파일들만 working directory로 가져와서 로컬 PC에 보이도록 할 수 있다.
    git sparse checkout 기능은 Git 2.25.0 이상부터 사용이 가능하다.

    기본적인 사용법은 아래와 같다.

    // 루트에 있는 index.ts 파일만 가져올 경우 
    $ git sparse-checkout set /index.ts
    
    // src/index.ts 파일만 가져올 경우
    $ git sparse-checkout set /src/index.ts
    
    // src 디렉토리와 하위 전체 내용을 가져올 경우
    $ git sparse-checkout set /src/
    
    // 루트에 있는 index.ts 파일과 src 디렉토리를 전체 가져올 경우
    $ git sparse-checkout set /index.ts /src/

    https://github.blog/2020-01-17-bring-your-monorepo-down-to-size-with-sparse-checkout/

     

    그럼 이제 위 예시처럼, 모노레포에서 'Android Client Dev' 작업에 필요한 요소들만 WorkingDirectory로 가져와보자.

    git sparse-checkout set /bootstrap.sh /LICENSE.md /README.md /client/android/

     

    그러면 지정했던 파일 및 디렉토리 외에는 모두 working Directory에서 빠지며 내 로컬에서 보여지지 않게 된다.

    이 상태에서, 현재 sparse-checkout 된 디렉토리 요소들이 무엇인지 확인하기 위해서는 아래처럼 할 수 있다.

    $ git sparse-checkout list
    
    // 출력
    /bootstrap.sh 
    /LICENSE.md 
    /README.md 
    /client/android/

     

    만약 원래대로 되돌리고 싶으면 아래처럼 하면 된다.

    $ git sparse-checkout disable

     

    만약 이미 sparse-checkout된 상태에서, git-tree에 있는 파일 및 디렉토리 중에 추가로 Working Directory로 가져오고 싶다면, 아래처럼 할 수 있다.

    // /public 디렉토리를 추가로 가져오고 싶은 경우
    $ git sparse-checkout set /public

     

    모노레포에서 git sparse checkout 쉽게 활용하기

     

    여러 멤버, 여러 팀들이 하나의 모노레포에서 각자 자신이 작업할 내용들과 관련된 요소들만 git sparse checkout을 통해 가져오게 될 것이다. 그런데 항상 이러한 경우가 있을 때마다 일일이 파일 및 디렉토리명을 치면서 working Directory로 가져와야 할까?

    이때는 스크립트를 활용해서, 각 팀별로 주로 사용되는 디렉토리들을 git sparse checkout 해서 가져오도록 스크립트 코드로 미리 만들어둔다면, 명령어 한 번으로 해당하는 요소들만 빠르게 내 Working Directory로 가져올 수 있다.

     

    아까 앞에서 본 'Android Client Dev' 혹은 'Web Browser Dev'와 같이, 지정된 묶음으로 한번에 Working Directory로 가져오는 스크립트를 만든다면 아래 같이 할 수 있다.

    #!/bin/bash
    
    PROJECT=$1
    
    case $PROJECT in
    "Android-Client-Dev")
      FOLDERS="
        /client/android/ /bootstrap.sh /LICENSE.md /README.md
      ";;
    
    "Identity-Service-Dev")
      FOLDERS="
        /service/common/
        /service/identity/
        /bootstrap.sh /LICENSE.md /README.md
      ";;
    "Web-Browser-Dev")
      FOLDERS="
        /service/
        /web/browser/
        /bootstrap.sh /LICENSE.md /README.md
      ";;
    
    esac
    
    # add specific service directory
    echo "Running 'git sparse-checkout set $FOLDERS"
    git sparse-checkout set $FOLDERS

     

    위처럼 shell Script 파일을 생성 후에, 아래처럼 실행시켜보자.

    $ sh bootstrap.sh Web-Browser-Dev

     

    그러면 아래처럼 Web Browser Dev 팀에 필요로 한 파일들만 빠르게 가져올 수 있는 것을 확인할 수 있다.

    $ git sparse-checkout list
    service
    web/browser
    bootstrap.sh 
    LICENSE.md 
    README.md

     

    모노레포에서 git sparse checkout 이용에 대한 주의사항

    모노레포에는 각 프로젝트 내에 package.json이 존재할 수 있다.
    현재 우리 모노레포 같은 경우에는 yarn workspace를 이용하여 모노레포 환경을 구축하였는데, 모든 package.json의 dependency 정보를 읽고 동일하게 사용되는 모듈은 최상단으로 Hoisting을 하고, 각 프로젝트의 Dependency 정보는 최상단 yarn.lock에서 관리하게 된다.

    그러나 모노레포 내에 전체 package.json 중에, git sparse checkout로 인해 Working Directory에 일부의 package.json만 있는 상태에서 새롭게 install을 한다던가 새로운 모듈 추가를 위해 yarn add를 하는 순간, yarn은 Working Directory에만 존재하는 package.json만을 확인하고, 현재 보이지 않는 package.json의 정보들은 더 이상 이용되지 않는 Dependency라 판단하고 yarn.lock에서 정보들을 지워버리게 된다.

     

    우선 이 문제에 대해 가장 쉬운 해결 방법은, git sparse checkout을 할 때마다 항상 각 프로젝트의 package.json을 남기는 것이긴 한데, 뭔가 좋은 방법이 아니라 임시방편인 느낌이다. 

    이 부분을 조금 더 멋지게 처리할 수 있는 방법에 대해 알아보는 중이다.
    이를 해결하게 추가로 업데이트 할 예정이다.

     

     

    Reference

     

    Bring your monorepo down to size with sparse-checkout

    Git 2.25.0 includes a new experimental git sparse-checkout command that makes the existing feature easier to use, along with some important performance benefits for large repositories.

    github.blog

     

    반응형

    댓글

Designed by Tistory.