Tech
브랜치 전략 수립을 위한 전문가의 조언들
2022. 06. 28안녕하세요, 화해 개발팀 백엔드 플랫폼 소속 이현재입니다. Git 브랜치 전략
개발자라면 누가 언급하지 않더라도 자연스레 알아야 하는 지식들이 생기죠? 그중에서 브랜치 전략에 대해 되돌아보는 시간을 가지려고 해요. 이미 갖추어진 환경에서 일한다면 크게 고민해보지 않았을 내용일 겁니다. 우리가 사용하는 브랜치 전략이 주어진 개발 프로세스에 적합한지 살펴봅시다.
브랜치 전략을 세우기 전에 필요한 현황 파악
개발자들이 코드를 만들 때 빠질 수 없는 프로그램이 바로 버전관리시스템 Version Control Systems, VCS
입니다. 코드 변경사항을 기록하는 건 물론이며, 동료들과 협업을 도와주는 도구죠. 만약 버그가 발생하여 이전 상태로 되돌아가야 할 상황에서 VCS가 없다면 곤혹스러울 겁니다. 동시에 상용 버전을 여럿 관리할 때도 마찬가지죠. 개발하며 겪기 쉬운 문제를 대응하는 수단이 VCS입니다.
VCS는 분명 훌륭한 개발도구이지만, 정책에 따라 협업 부서까지 제약을 받습니다. 정기 배포 시 통합 테스트 브랜치를 하나로 고정하면 필연적으로 소스 프리징이 발생하죠. 장기 프로젝트는 QA기간이 길잖아요? 자연스레 선행 배포가 이루어지기 전까지 다른 프로젝트는 배포 나갈 수 없는 상황이 만들어집니다. 혹여나 핫픽스로 나갈 긴급 배포 건이 발생한다면 일은 더 커지죠. 그렇다고 겪지 않을 상황까지 대비하는 전략은 개발 리소스를 낭비할 뿐입니다.
효과적으로 VCS를 사용하려면 프로젝트 여건에 어울리는 브랜치 전략을 세워야 합니다. 이를 위한 첫 번째는 바로 브랜치 전략에 대한 비교 분석입니다. Git기반으로 워크플로우를 고민해보았다면 모를 수 없는 대표 세 가지를 비교하며 살펴봅시다.
Git-flow
출처 https://nvie.com/posts/a-successful-git-branching-model/
2010년, Git-flow는 온라인에서 nvie라는 닉네임을 사용하는 한 개발자에 의하여 알려지기 시작합니다. 그는 Git을 기반으로 한 성공적인 개발 모델을 만들었다고 글을 씁니다. feature
– develop
– release
– hotfix
– master
로 브랜치를 구성하여 1년 동안 사용한 경험담이죠. 이에 감명받은 사람들을 필두로 점차 퍼지기 시작하더니 어느새 대표적인 워크플로우로 대두됩니다. 10년 넘게 흐른 지금까지도 수많은 개발자들이 이를 표준으로 여길 정도로 많은 인기를 누립니다.
이처럼 광적인 반응을 우려한 nive는 2020년 3월에 그동안 못 꺼낸 이야기를 밝힙니다.
“Git-flow has become hugely popular in many a software team to the point where people have started treating it like a standard of sorts — but unfortunately also as a dogma or panacea.”
Git-flow는 사람들이 표준처럼 다루기 시작할 정도로 많은 소프트웨어 팀에서 큰 인기를 누렸지만, 불행하게도 만병통치약으로 취급되기 시작했다.
“Web apps are typically continuously delivered, not rolled back, and you don’t have to support multiple versions of the software running in the wild.”
웹 애플리케이션은 일반적으로 롤백되지 않으며, 지속적으로 서비스를 제공하기에 소프트웨어를 다양한 버전으로 지원할 필요가 없다.
“This is not the class of software that I had in mind when I wrote the blog post 10 years ago. If your team is doing continuous delivery of software, I would suggest to adopt a much simpler workflow (like GitHub flow) instead of trying to shoehorn git-flow into your team.”
10년 전 블로그에 글을 쓸 때 이러한 소프트웨어를 염두하지 않았다. 만약 당신의 팀이 소프트웨어를 지속적으로 제공한다면 GitHub-flow와 같은 간단한 워크플로우 채택을 제안한다.
이처럼 Git-flow는 소프트웨어 버전 관리가 필요한 앱이나 솔루션, 혹은 public API에 적합한 워크플로우입니다. 웹 애플리케이션에서 Git-flow는 고려할 전략이 아닙니다.
– 정기 배포
– 버저닝이 필요한 애플리케이션
GitHub-flow
2011년, GitHub CIO인 Scott Chacon이 GitHub-flow를 처음 꺼냅니다. 그는 Git-flow가 가진 가장 큰 문제는 개발자가 요구하는 상황보다 훨씬 더 복잡한 프로세스라고 지적합니다. 워크플로우를 단순화하면 개발자들이 빨리 습득할 수 있죠. 단순할수록 오버헤드가 발생하지 않아 브랜치 전략을 이해하지 못하여 생기는 문제가 사라진다고 말합니다.
GitHub-flow는 Git-flow가 가진 복잡성을 전부 제거합니다. 유지 브랜치는 master
하나를 두는 방식으로 고수합니다. master
를 제외한 브랜치는 개발자 재량에 맡기니 복잡한 정책이 필요치 않습니다.
GitHub-flow 정책
master
는 언제든지 배포가 가능하다.- 새로운 프로젝트는
master
를 기반으로 별도 브랜치를 생성하여 작업을 진행한다. - 브랜치는 로컬에 commit하고, 정기적으로 원격 브랜치에 push한다.
- 피드백이나 도움이 필요하거나, 코드 병합할 준비가 되었다면 pull request를 만든다.
- 다른 사람이 변경된 코드를 검토한 뒤 승인하면
master
에 병합한다. - 병합된
master
는 즉시 배포할 수 있으며, 배포 해야만 한다.
이와 같은 정책을 가질 수 있는 이유는 GitHub-flow가 상시 배포 모델이기 때문입니다. Scott Chacon은 정기 배포가 가진 이점도 분명히 존재한다고 이야기하며, 다음과 같이 첨언합니다.
“만약 장기간 프로젝트가 존재하고, 핫픽스 등 유지보수를 위한 작업을 수행해야 되는 팀은 Git-flow가 타당하다. 상시 배포하는 팀은 간단한 GitHub-flow가 적합하다.”
GitHub-flow를 공개한 그의 의견처럼 이 워크플로우는 상시 배포가 가능한 프로세스에서 유효합니다.
– 상시 배포
GitLab-flow
GitLab은 GitHub-flow가 지속 배포 모범 사례라는 점에 동의합니다. 다만 배포, 환경, 릴리즈 및 소스 통합 등 다양한 이슈에 대한 궁금증을 GitHub가 답하지 않았다고 지적합니다. GitLab은 GitHub-flow를 기반으로 상황에 따라 워크플로우를 활용하는 방법에 대하여 추가적인 가이드를 제공합니다.
- 배포 기간이 정해진 경우 발생하는 통합 이슈 해결책
- 서버 환경에 따른 브랜치 구성 방법
- 릴리즈 버전이
master
와 분리되어 운영되어야 하는 상황 타개법
이 외에도 rebase를 활용한 commit 압축하기, merge commit 줄이는 방법, commit 메시지 작성 방법, 기능 분기에 대한 정책 등 다양한 방면에 대한 해답을 제시합니다. 그중에서도 GitLab이 내세운 건 이슈 기반 트래킹입니다.
‘코드를 변경하는 목적은 분명하므로 이슈로 생성하여 관리하자.’는 이념 아래로 코드 변경 사유를 투명하게 공개하자는 원칙입니다. GitLab은 동일한 repository를 사용하는 개발자들끼리 작업 내역을 알아야 된다고 말합니다. 또한 이슈를 기반으로 관리하면 브랜치 생명 주기가 보다 명확하게 파악되어 유지보수가 용이하죠.
정기 배포 웹 애플리케이션은 무얼 선택하지?
Git-flow와 GitHub-flow는 서로 다른 특징을 가진 만큼 사용 조건이 명확합니다. 자세히 살펴보면 두 워크플로우로는 한계가 드러나는 상황도 파악할 수 있죠. 만약 다음과 같은 여건이라면 어떤 브랜치 전략을 선택하시겠나요?
- 지속적으로 변하는 웹 애플리케이션
- 불필요한 버저닝 관리
- 정기 배포 체계
- 수많은 프로젝트 동시 진행
Git-flow를 널리 알린 nvie나, GitHub-flow를 주창한 Scott Chacon도 팀에 주어진 상황에 맞추어 쓰기를 권장합니다. GitLab도 마찬가지입니다. 맞지도 않은 옷을 억지로 입는 만큼 맵시나지 않는 일이 없기에 위와 같은 상황에서는 이처럼 접근해야 합니다.
주어진 상황에 맞게 워크플로우를 재구성해봤습니다. 정기 배포 웹 애플리케이션에 어울리는 프로세스를 만들기 위해 변경한 부분은 크게 세 가지입니다.
첫 번째, 정기 배포 기반인 만큼 Git-flow를 차용합니다. 다만 각기 다른 통합 테스트 환경을 구축하기 위하여 develop
를 제거합니다. 앱 애플리케이션처럼 릴리즈 버전이 정해져 있다면 Git-flow를 그대로 유지해도 괜찮지만, 동시성이 중요한 웹 프로젝트는 develop
브랜치로 인하여 지나칠 만큼 커다란 제약사항이 생깁니다.
develop
브랜치가 release
브랜치에 끼치는 영향release
브랜치가 다수 존재할 수 있어도, 이미 배포되지 않은 선행 release
가 존재한다면 배포 시점을 뒤집을 수 없어 소스 프리징이 해결되지 않는다.만약
release
브랜치까지 올렸지만, feature
로 돌려 다시 개발하는 상황이 발생하면 develop
브랜치까지 revert 해야 한다. 이 때 또 다른 release
브랜치가 존재한다면 생성된 순서에 따라 해당 브랜치까지 영향을 받는다.
두 번째, GitHub-flow에 의거하여 유지 브랜치는 master
하나만 둡니다. 또한 모든 브랜치는 master
를 통해 생성합니다. Git-flow처럼 유지 브랜치를 두 가지 이상 둔다면 정책이 지나치게 복잡해져 오버헤드 발생 여지가 커집니다. master
브랜치 전략은 GitHub-flow와 동일합니다.
세 번째, GitLab-flow에서 말했듯이 이슈 기반으로 브랜치를 관리합니다. 각기 다른 프로젝트가 동시에 진행되면 어떤 브랜치가 왜 생성이 되었는지, 더 이상 사용하지 않는 브랜치인지 commit 메시지만으로 알 방법이 요원합니다. 이를 방지하기 위해 이슈 기반으로 feature를 생성합니다.
브랜치 구성
브랜치명 | 구분 | 설명 | 비교 |
feature | 보조 브랜치 |
|
|
release | 보조 브랜치 |
|
|
hotfix | 보조 브랜치 |
|
|
master | 유지 브랜치 |
|
|
앞서 이야기한 내용을 바탕으로 도식화했습니다. 프로젝트 단위로 feature
를 생성하며, 만약 feature
하위 브랜치는 필요하다면 자율적으로 허용합니다. 기능 개발 후 테스트가 완료되면 통합 테스트를 위한 release
브랜치를 생성하고 merge합니다. 동일한 배포 시점을 다루는 release
브랜치가 존재할 경우 해당 브랜치에 merge를 진행합니다.
release
브랜치가 필요한 이유개발을 시작할 때 대략적인 배포 일정을 산정하지만, 상황에 따라 변동될 가능성이 큽니다.
feature
브랜치가 생성될 시점에서는 언제 운영 서버에 반영할지 정확히 예측할 수 없습니다. 따라서 기능 개발 브랜치와 통합 테스트 브랜치를 분리해서 관리해야 합니다.
동일한 시점에 배포를 진행하는 release
브랜치에서 통합 테스트가 마무리되면 master
에 merge request를 보냅니다. master
는 언제든지 배포할 수 있는 형태를 유지합니다. release
에서 master
로 넘어올 때 모든 충돌 이슈를 release
에서 해결합니다. master
에서 코드 충돌을 해결하지 않습니다. 따라서 release
브랜치는 코드가 배포되는 순간 master
변경 사항을 release
브랜치에 가져와 적용합니다.
– 정기 배포
– 장기 프로젝트가 존재하는 애플리케이션
– 버저닝 관리가 필요하지 않운 웹 애플리케이션
아틀라시안 BitBucket팀 조언
먼저 밝히자면 아틀라시안에서 공개한 글은 기본적으로 CC BY 2.5 AU 라이선스입니다. 라이선스에 의거하여 별도로 원작자 Nicola Paolucci의 허락을 구하지 않았으며, 아틀라시안 제품과 관련된 일부 내용을 제외하고 번역했습니다. 원글에 다소 난해하게 적힌 부분은 이해를 돕기 위해 일부 의역했습니다. 번역하는 과정에서 의역에 부합하는 문맥을 맞추기 위해 문장 순서를 바꾸었으니 참고해주세요. 원글은 다음과 같습니다.
[번역] 코드 병합 신뢰와 브랜치 간소화에 대한 첨언
브랜치를 기반으로 한 워크플로우는 아무것도 존재하지 않는 단순한 형태로 시작하였습니다. 시간이 흐르며 점차 요구사항이 늘어나다 보니 복잡하지만 견고하고 방어적인 형태로 변화합니다. 당신의 조직이 허용할 수 있는 복잡성은 어느 정도이며, 얼마나 견고한 프로세스를 원하나요?
이 글은 서로 상반되는 유연함과 견고함 사이에 존재하는 최적점을 찾기 위한 여정을 다룹니다. 당신의 선택을 도와줄 수 있도록 아틀라시안 내에서 보고 겪은 Git에 대한 경험과 교훈을 바탕으로 몇 가지 지침을 담았습니다. 조직에 어울리는 가장 효과적인 브랜치 전략을 찾아낼 통찰력을 제공하기 위하여 이 글을 작성합니다.
가이드 요약
- 코드 병합을 믿어라.
- 극단적인 브랜치 전략을 피해라.
- 가능하다면 브랜치 계층 구조를 단순화해라.
코드 병합을 믿어라.
가장 효과적인 브랜치 전략을 선택하기 앞서 선행되어야 할 첫 번째 단계는 코드 병합(merge)을 신뢰하는 것입니다. 최근에야 Git을 채택한 조직을 위해 이를 언급합니다. 이미 코드 병합에 대한 의심을 갖고 있지 않다면 이 단락은 건너뛰셔도 됩니다.
낡은 개발 체계에서는 어떤 대가를 치르더라도 병합을 피하거나, 이를 관리할 인원이 필요했습니다. 구형 시스템은 이처럼 극단적인 조치를 취해야 했지만, Git이 수행하는 코드 병합은 다음과 같은 특징 덕분에 특별한 이벤트가 아닙니다.
Git, 코드 병합과 관련된 주요 특징
- 브랜치는 매우 저렴하고 빠르므로 사이클이 짧은 브랜치와 잦은 통합을 장려합니다.
- 코드 병합은 로컬에서 이루어지므로 결과를 즉각적으로 살펴볼 수 있습니다.
- Git은 부모 브랜치를 알고 있기에 전체 작업 트리를 비교하지 않고, 연관 작업 내역만 비교하여 병합합니다. 그 덕분에 일반적인 충돌이 줄어듭니다.
- 다양한 형태를 지닌 워크플로우를 활용할 수 있습니다. 브랜치 생성과 코드 병합이 쉽다 보니 부담을 가지지 않아도 됩니다. 일부 조직은 이를 지나치게 과용하여 정반대의 문제를 겪기도 하니 인생과 마찬가지로 균형을 유지해야 합니다.
극단적인 브랜치 전략을 피해라.
Git 출현 전후로 브랜치 전략을 살펴보면 단순한 형태에서 복잡한 계층으로 이어지는 스펙트럼이 만들어집니다. 브랜치 전략 스펙트럼 중 극단에 위치한 모델은 문제가 될 수 있습니다. 브랜치 전략에 대한 두 가지 예시를 통해 당신이 겪었을 극단적인 브랜치 전략 문제점을 보여드리겠습니다.
극단적인 단일 브랜치
과거에 SVN을 사용하였을 때 모든 상황을 제어하는 단 하나의 브랜치가 존재했습니다. 수년 동안 소프트웨어 조직은 오로지 하나의 브랜치인 `trunk`에서 개발했습니다. 좋든 싫든 완성품과 개발 중인 기능이 한데 뒤섞여 있는 상태를 견뎌야 했습니다. 그로 인하여 종종 빌드가 실패하기도 합니다.
우리는 애증하는 단일 브랜치 전략과 함께 성장하였습니다. 그리고 여전히 누군가 사용하는 워크플로우입니다. 하지만 더 이상 효과적인 전략이 될 수 없습니다.
Single branch workflow – aka trunk
Git을 새로이 채택한 조직이나 기존 워크플로우를 유지하려는 팀은 동일한 구조를 재현하고 싶을 수 있습니다. 비록
trunk
를 Git에서master
라 부르지만, 동일한 구조를 만들 수 있습니다.
Getting updates via rebase
브랜치를 추가로 생성하지 않은 채 모든 작업을
master
에서 진행할 수 있습니다. rebase를 통해 최신 변경 사항을 가져오면 됩니다. SVN에서 사용하던 낡은 브랜치 전략(trunk-only)과 매우 유사합니다.
극단적인 단일 브랜치 전략을 사용할 때 가장 큰 단점이 무엇인지 아시나요?
master
가 손상되었을 때 모든 업무가 중단된다는 사실입니다. Git은 프로젝트 전체 히스토리를 자유롭게 관리할 수 있어 문제가 발생하기 전 상태로 되돌아가기 쉽지만, 다른 개발자의local
저장소는 특정 시점에 멈추어져 있습니다. 또한 rebase를 기반으로 하는 경우 콘텍스트 추적이 어려워집니다. 이에 대한 자세한 내용은 merge vs rebase 논쟁에 관한 글을 읽길 바랍니다.
현대적인 조직에서 단일 브랜치 전략을 사용하는 경우 하위 브랜치를 일부 허용(역자 주: GitHub-flow)하는 건 드문 일이 아닙니다. 이를 허용해도 squash commit을 정책으로 강제하면 위 그림과 정확히 일치하게 만들 수 있습니다.
master
히스토리가 단조롭게 유지됩니다.
지나치게 많은 계층을 가진 브랜치 전략
극단적인 단일 브랜치 전략의 반대편에는 프로세스 계층을 지나치게 세분화하여 삶을 복잡하게 만드는 워크플로우가 존재합니다. 다음 그림을 살펴봅시다.
Too many long running branches?
이 예제를 보면 각 사용자 스토리마다 브랜치를 생성합니다. 여기에서 파생되는 이슈마다 브랜치가 만들어지고, 이슈 브랜치에서 하위 작업을 위한 브랜치가 생성됩니다. 최하위 브랜치에서 개발이 완료되면 다시 순차적으로 부모 브랜치들을 거쳐
master
를 도달해야 배포할 수 있습니다.
앞서 이야기했듯이 브랜치 생성과 코드 병합은 Git에서 어려운 일이 아닙니다. 다만 워크플로우가 복잡해지면 이와 상관없이 거쳐야 할 단계가 많아져 업무 처리 속도에 악영향을 미칩니다.
가능하다면 브랜치 계층 구조를 단순화해라.
적어도 지금 우리는 극단을 피해야 한다는 사실을 배웠습니다. 그렇다면 구조적인 견고함과 함께 유연성을 지킬 수 있는 최적화된 워크플로우는 무엇일까요? 두 가지 질문을 통해 당신이 소속된 조직의 스타일을 쉽게 파악할 수 있습니다.
- 해당 프로젝트에서 장기간 유지보수해야 하는 브랜치는 최소 몇 개입니까?
- 소프트웨어 이전 버전을 유지보수해야 합니까?
소프트웨어 조직이라면 테스트로 견고함을 쌓기 위해, 조직에 대한 신뢰를 바탕으로 책임 수준을 높이기 위해, Production 이슈에 대한 내성을 갖추기 위해 적합한 브랜치 계층을 유지해야 합니다. 아틀라시안의 여러 팀은 BTF(behind the firewall)와 온디맨드(Cloud) 제품 모두에 대하여 비교적 단조로운 브랜치 전략을 사용합니다.
브랜치 생성 기준, 사용자 스토리 vs 이슈 단위
이것은 브랜치 밀도 문제입니다. 너무 많은 사람들을 함께 일하도록 강요하면 앞서 살펴본 단일 브랜치 이슈가 발생합니다. 반면 지나치게 브랜치를 많이 생성하면 전체를 파악하기 혼잡스럽고, 전반적인 과정이 부풀어집니다. 아틀라시안 개발 조직은 ‘이슈 당 브랜치 하나‘로 만들 때 가장 효과적으로 프로젝트를 관리할 수 있다는 걸 찾아냈습니다.
Sane Workflow # 1 : 안정적인 단일 마스터, 브랜치를 활용하지만 단순하게 유지
지속적인 배포를 위해 간단한 브랜치 전략을 세울 수 있습니다. 이 전략이 가진 핵심은
master
는 언제든지 배포 나갈 수 있다는 점입니다.master
로 넘어온 commit은 태그가 지정된 배포 단위로 보면 됩니다. 웹 애플리케이션이나 SaaS, 그리고 버전 관리가 필요치 않는 소프트웨어에 적합한 워크플로우입니다.
Sane Workflow # 2 : 단순하게 유지하면서 이전 릴리스 유지
이전 버전의 제품을 유지 관리하고 지원해야 할 경우 단일 유지 브랜치만으로 충분하지 않습니다. 다양한 버전을 지원하기 위해서는 조직에서 지원해야 하는 각 버전에 대하여 장기적인 릴리즈 브랜치를 보유해야 합니다. 변경 사항은 항상 이전 브랜치에서 최신 브랜치로 흐르며 반대 방향은 성립하지 않습니다. 그 이유에 대해 궁금하다면 ‘브랜치 기반 워크플로우의 본질‘을 참고하세요.
Long running release branches
필요하다면 통합 브랜치를 생성합니다.
배포 시점이 동일하지만, 별도로 격리하여 작업을 진행해야 한다면 브랜치를 분리해서 개발해야 합니다. 이렇게 나누어진 브랜치들을 모아서
master
에 합치기 위해 통합 브랜치를 생성할 수 있습니다. BitBucket Server 팀은 릴리스 주기(대략 6 주) 당 추가적인 통합 브랜치를 한두 번 만듭니다.
최종 병합에 대한 히스토리를 가볍게 유지하기 위해 가능한 자주
master
에 반영된 최신 코드로 브랜치를 갱신합시다.
브랜치 전략에 정해진 정답은 없습니다.
국내에서 워크플로우와 관련된 글을 찾아보면 브랜치 전략 설계 방법론을 다루는 글이 보이지 않았어요. 어느 기술 블로그든 막론하여 대부분 Git-flow, GitHub-flow를 소개하는 걸로 그쳤죠. 기껏해야 GitHub-flow 부족한 점을 메우는 GitLab-flow만 언급될 뿐입니다.
브랜치 전략에 대하여 깊이 고민하지 않았다면 국내에 드러난 자료가 두 브랜치 전략뿐이니 자연스레 Git-flow와 GitHub-flow만 워크플로우라 오해하기 쉽습니다. 해당 브랜치 전략들은 분명 워크플로우의 정수이지만, 만병통치약은 될 수 없습니다. 이는 Git-flow를 처음 세상에 알린 nive가 재작년에 직접 언급한 이야기입니다.
따라서 조직에 어울리는 브랜치 전략을 고안할 때 주어진 여건이 무엇인지 정확히 인지해야 합니다. 만약 주어진 상황에 어울리는 전략이 없다면 상황에 맞게 새로운 플로우를 만드세요. 리소스를 낭비하면서 틀에 얽매일 필요는 없습니다. 위에서 소개한 정기배포 웹 애플리케이션 플로우는 실제로 기업에서 사용하는 브랜치 전략이며, 제가 직접 구상했습니다. 자세한 배경은 참고자료로 대신합니다.
다음번에 기회가 닿는다면 화해에서 사용하는 브랜치 전략과 시나리오를 소개해드리겠습니다. 감사합니다.
참고자료
- https://nvie.com/posts/a-successful-git-branching-model/
- http://scottchacon.com/2011/08/31/github-flow.html
- https://guides.github.com/introduction/flow/
- https://docs.gitlab.com/ee/topics/gitlab_flow.html
- https://www.atlassian.com/git/articles/trust-the-merge-and-branch-simplification-musings
- https://www.atlassian.com/blog/git/git-team-workflows-merge-or-rebase
- https://www.atlassian.com/blog/git/the-essence-of-branch-based-workflows
- https://saramin.github.io/2020-11-17-SSG/
이 글이 마음에 드셨다면 백엔드 플랫폼의 다른 콘텐츠도 확인해보세요!
✅ Git Internal API를 활용한 .git 탐험