GitHub에서 폴더만 다운로드하는 방법 (전체 저장소 클론 없이)
GitHub에서 거의 모든 저장소를 열면 초록색 Code 버튼을 볼 수 있습니다. 이 버튼이 제공하는 것은 정확히 두 가지입니다. 전체 프로젝트를 클론하거나, 전체 프로젝트의 ZIP을 다운로드하는 것입니다. src/components, docs/examples, 또는 templates 폴더로 들어가도 버튼은 그대로 있고, 역시 모든 파일을 제공합니다. GitHub 공식 문서도 이 점을 분명히 밝힙니다. 저장소 파일의 스냅샷을 다운로드하거나, 클론하거나, 포크할 수 있을 뿐입니다. 폴더를 위한 네 번째 옵션은 없습니다.
이 공백 때문에 “how to download a folder from GitHub”가 GitHub 관련 질문 중 가장 많이 검색되는 주제 중 하나가 되었고, 검색되는 답변들이 이렇게나 제각각인 것입니다. 어떤 답변은 2024년 1월에 작동을 멈춘 SVN 명령을 여전히 권장합니다. 또 다른 답변은 결국 전체 저장소를 조용히 내려받는 다섯 줄짜리 Git 레시피를 알려 줍니다. 이 가이드는 오늘 실제로 작동하는 모든 방법과 각 방법의 비용, 그리고 어떤 방법이 여러분의 상황에 맞는지를 결정하는 구체적인 오류 — 속도 제한, 잘린 파일 목록, LFS 포인터 파일 — 를 다룹니다.
빠른 답변: 방법 선택
| 방법 | 설치 필요 | 비공개 저장소 | Git 기록 유지 | 적합한 경우 |
|---|---|---|---|---|
| 브라우저 폴더 다운로더 | 아니요 | 예, 토큰 필요 | 아니요 | 일회성 다운로드, 다양한 크기의 폴더 |
| 저장소 ZIP (공식) | 아니요 | 예, 토큰 필요 | 아니요 | 대부분의 파일이 필요한 작은 저장소 |
git sparse-checkout |
Git | 예, 자격 증명 필요 | 예 | 계속 업데이트를 가져올 경우 |
REST API + curl |
curl, jq | 예, 토큰 필요 | 아니요 | 스크립트, CI, 반복 작업 |
| 단일 파일 복사 | 아니요 | 예, API 통해 가능 | 아니요 | 한 폴더에서 두세 개 파일 |
ZIP만 필요하다면 브라우저 방식이 가장 빠릅니다. 폴더 URL을 GitDownloader 홈페이지 도구에 붙여넣으면 해당 디렉터리만 압축해 줍니다. 이 글의 나머지 부분에서는 다른 옵션이 왜 존재하는지, 그리고 언제 그 옵션들이 더 적합한지 설명합니다.
GitHub에 “이 폴더 다운로드” 버튼이 없는 이유
이 제약은 게으름 때문이 아니라 Git이 데이터를 저장하는 방식에서 비롯됩니다.
Git 저장소는 객체들의 방향성 그래프입니다. 파일은 blob 객체에 담기고, 디렉터리는 이름, 모드, 그리고 blob이나 다른 tree를 가리키는 해시를 나열하는 tree 객체입니다. 브랜치는 하나의 커밋을 가리키는 포인터이고, 그 커밋은 하나의 루트 tree를 가리키며, 이 tree가 전체 스냅샷을 재귀적으로 설명합니다. 그 구조 안에 “src/assets 폴더를 독립적으로 다운로드 가능한 단위로 표현하는 것”은 없습니다. 하위 tree는 부모 tree 안에서만 의미를 가집니다.
반면 Subversion은 디렉터리를 일급 체크아웃 대상으로 취급했습니다. 그래서 예전 SVN 브리지가 고전적인 우회 방법이었습니다. Git의 모델은 기록, 브랜치, 무결성을 제공하는 대신, 부분 검색을 저장소의 개념이 아니라 클라이언트 측 문제로 만듭니다.
따라서 GitHub 인터페이스는 제공하기 저렴하고 명확한 것만 제공합니다.
- 하나의 ref에 대한 ZIP.
https://github.com/{owner}/{repo}/archive/refs/heads/{branch}.zip은 해당 브랜치 루트 tree의 스냅샷을 스트리밍합니다. 유용하지만 언제나 브랜치 전체입니다. - Git Trees API. 단일 요청으로 하위 tree를 나열할 수 있습니다. 모든 폴더 다운로드 도구가 실제로 기반으로 삼는 원시 기능이며, 저희 도구도 마찬가지입니다.
즉, 폴더 다운로드는 GitHub이 대신 해 주는 일이 아닙니다. 도구나 스크립트가 GitHub API를 이용해 경로 아래의 파일을 나열하고, 각각을 가져와, 로컬에서 압축하는 일입니다.
방법 1 — 브라우저 기반 폴더 다운로더 (설치 불필요)
대부분의 사람에게 가장 짧은 경로이며, 아무것도 설치할 필요 없고 터미널도 필요 없는 유일한 방법입니다.
- GitHub에서 폴더를 열고 브랜치 선택기가 원하는 브랜치를 표시하는지 확인합니다.
- 주소 표시줄에서 URL을 복사합니다.
https://github.com/owner/repo/tree/main/path/to/folder형태여야 하며,/tree/<branch>/<path>구조가 중요합니다. - 홈페이지 도구의 URL 입력란에 붙여넣고 Download ZIP을 누릅니다.
- 파일 목록이 조회되고 브라우저에서 가져와 압축된 뒤 다운로드 폴더에 저장됩니다.
이 단계에서 좋은 도구와 망가진 도구를 가르는 것은 입력 상자가 아니라 그다음에 벌어지는 일입니다.
- 슬래시가 포함된 브랜치.
release/2.1은 유효한 브랜치 이름이므로, 도구는 첫/에서 추측하지 않고 점점 더 긴 접두사를 시험해 브랜치가 끝나고 폴더 경로가 시작되는 지점을 찾아내야 합니다. - 매우 큰 디렉터리. 재귀 목록이 100,000개 항목 또는 7MB를 초과하면 Trees API는
"truncated": true를 반환합니다. 이 플래그를 무시하는 도구는 파일이 누락된 ZIP을 조용히 건네줍니다. 올바른 동작은 하위 tree를 한 단계씩 나열하는 방식으로 전환하는 것입니다. - 속도 제한. 인증 없이는 IP 주소당 시간당 60회의 API 요청을, 토큰이 있으면 5,000회를 사용할 수 있습니다. 디렉터리를 하나씩 나열하는 도구는 깊은 폴더에서 비인증 한도를 빠르게 소진하며, 그래서 다운로드가 중간에 실패했다가 한 시간 뒤에 다시 되는 경우가 있습니다.
- Git LFS. Large File Storage를 사용하는 저장소는 실제 자산 대신 아주 작은 포인터 파일을 저장합니다. 아무것도 그 포인터를 감지하지 못하면, 여러분의 ZIP은 기술적으로는 올바르지만 완전히 쓸모가 없습니다.
소유하거나 접근 권한이 있는 저장소라면 선택적 토큰 입력란에 세분화된 개인 액세스 토큰을 붙여넣으세요. GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens 순으로 이동해 Contents: Read-only 권한으로 특정 저장소에만 제한된 토큰을 생성하면 됩니다. 토큰은 사용자의 브라우저에 저장되고 api.github.com으로만 전송됩니다. 중간에서 파일을 읽는 서버는 없습니다. 자세한 내용은 FAQ에 있습니다.
방법 2 — 공식 경로: 전체 저장소 다운로드
놀랄 만큼 자주 여전히 정답이며, UI를 완전히 건너뛰는 직접 URL을 알아 둘 가치가 있습니다.
인터페이스를 통하는 방법: 저장소 페이지 → Code → Download ZIP. 파일은 repo-main.zip(또는 master, 기본 브랜치 이름)이라는 이름으로 다운로드됩니다.
북마크하거나 스크립트에 넣을 수 있는 직접 링크:
# 브랜치 아카이브 (공개 저장소, 인증 불필요)
https://github.com/{owner}/{repo}/archive/refs/heads/{branch}.zip
# 동일한 파일, 아카이브 호스트에서 제공
https://codeload.github.com/{owner}/{repo}/zip/refs/heads/{branch}
# API zipball — 토큰을 보내면 비공개 저장소에서도 작동
https://api.github.com/repos/{owner}/{repo}/zipball/{ref}
저장소가 작거나, 파일 대부분이 실제로 필요하거나, Git이 설치되어 있지 않거나, 릴리스 태그 뒤의 정확한 커밋이 필요할 때 이 방법을 선택하세요. 비용은 비례합니다. 클론에 800MB인 모노레포는 ZIP으로도 대략 800MB이며, 여기에 압축을 풀고 필요 없는 95%를 삭제하는 시간이 더해집니다. 그리고 ZIP 스냅샷은 말 그대로 스냅샷입니다. 기록도, 원격도, git pull도 없습니다.
방법 3 — git sparse-checkout 제대로 사용하기
나중에 업데이트를 가져올 수 있도록 폴더와 함께 작동하는 Git 체크아웃을 원한다면 sparse checkout이 적합한 도구입니다. 대부분의 튜토리얼은 구식 방법을 보여 줍니다. 여기 현대적인 방법을 소개합니다.
git clone --filter=blob:none --sparse https://github.com/owner/repo.git
cd repo
git sparse-checkout set path/to/folder
여기서 중요한 점:
--filter=blob:none은 부분 클론으로 만듭니다. Git은 커밋과 tree 객체를 가져오지만 체크아웃할 때까지 파일 내용은 건너뜁니다. 이것이 없으면 저장소의 모든 blob을 다운로드하고 대부분을 버리게 됩니다.--sparse는 sparse-checkout 파일을 대신 초기화하므로.git/info/sparse-checkout을 직접 작성할 필요가 없습니다.git sparse-checkout set은 cone 모드를 사용하며, 이는 디렉터리 전체를 매칭하고 대형 저장소에서 훨씬 빠릅니다. 나중에 여러 경로를 지정해 명령을 반복하면 경로를 더 추가할 수 있고, 작업 트리가 어긋나면git sparse-checkout reapply를 다시 실행하세요.- sparse checkout은 Git 2.25 이상이 필요하고, 부분 클론(
--filter)은 2.19 이상이 필요합니다.
블로그 글이나 Stack Overflow 답변에서 여전히 보이는 옛 방식 — git init, 그다음 git config core.sparseCheckout true, 그다음 echo "path/" >> .git/info/sparse-checkout, 그다음 git pull origin main — 도 작동은 하지만, 작업 트리를 필터링하기 전에 전체 기록과 모든 blob을 다운로드합니다. 결국 원하는 폴더와 함께, 파일 자체보다 몇 배나 큰 .git 디렉터리를 얻게 됩니다.
진짜 트레이드오프는 이것입니다. sparse checkout은 아카이브가 아니라 저장소를 줍니다. 다른 프로젝트에 넣을 깔끔한 ZIP을 원했다면, 이제 원격이 연결된 체크아웃을 가진 셈입니다. 기여할 계획이라면 정확히 원하던 것이고, 아니라면 순전한 오버헤드입니다.
방법 4 — GitHub REST API로 스크립트 작성하기
반복 작업 — 공용 폴더를 다른 저장소에 벤더링하기, CI에서 템플릿 가져오기, 매일 밤 문서 자산 갱신하기 — 에는 헤드리스로 실행할 수 있는 것이 필요합니다. API는 두 가지 구성 요소를 제공합니다.
Trees API (하위 tree 전체를 한 번의 요청으로):
GET https://api.github.com/repos/{owner}/{repo}/git/trees/{ref}?recursive=1
응답에는 각 항목의 path와 type을 담은 평탄한 tree 배열이 있습니다. type: "blob"인 항목이 파일입니다. 문제는 문서화된 상한선입니다. recursive=1일 때 배열은 100,000개 항목과 7MB로 제한되며, 이를 넘으면 응답에 "truncated": true가 설정됩니다. 그럴 때 문서에서 제시하는 해결책은 tree를 비재귀적으로 가져와 하위 tree를 직접 순회하는 것입니다.
Contents API (디렉터리당 한 번의 요청):
GET https://api.github.com/repos/{owner}/{repo}/contents/{path}?ref={ref}
이것은 각 파일의 download_url이 포함된 목록을 반환하며, 과거 대부분의 브라우저 도구가 사용하던 방식입니다. 절대 잘리지 않지만 디렉터리당 한 번의 요청이 필요하고, 그래서 깊은 tree는 속도 제한을 소진합니다.
Trees API와 raw.githubusercontent.com을 사용한 완전하고 작은 스크립트:
OWNER=octocat
REPO=Spoon-Knife
REF=main
PREFIX=src/assets
TOKEN="" # 비공개 저장소용으로 설정: export TOKEN=ghp_xxx
AUTH=()
[ -n "$TOKEN" ] && AUTH=(-H "Authorization: Bearer $TOKEN")
# 1. 목록을 신뢰하기 전에 잘리지 않았는지 확인
curl -s "${AUTH[@]}" \
"https://api.github.com/repos/$OWNER/$REPO/git/trees/$REF?recursive=1" \
| jq -r '.truncated'
# 2. 접두사 아래의 모든 파일 경로를 목록에 기록
curl -s "${AUTH[@]}" \
"https://api.github.com/repos/$OWNER/$REPO/git/trees/$REF?recursive=1" \
| jq -r --arg p "$PREFIX" \
'.tree[] | select(.type == "blob") | select(.path | startswith($p + "/")) | .path' \
> files.txt
# 3. 각 파일을 가져오며 필요하면 디렉터리 생성
while read -r path; do
mkdir -p "$(dirname "$path")"
curl -sL "${AUTH[@]}" -o "$path" \
"https://raw.githubusercontent.com/$OWNER/$REPO/$REF/$path"
done < files.txt
운영상 두 가지 참고 사항이 있습니다. 첫째, 응답 헤더를 주시하세요. X-RateLimit-Remaining은 남은 한도를, X-RateLimit-Reset은 한도가 리셋되는 시각을 알려 줍니다. 인증 없이는 그 한도가 IP당 시간당 60회이므로, 200개 파일 폴더는 토큰 없이는 중간에 실패합니다. 둘째, raw.githubusercontent.com은 비공개 저장소에 대해 Authorization 헤더를 인정하지만 실제로 보내야 합니다. 보내지 않으면 삭제된 파일과 똑같이 보이는 404를 받게 됩니다.
방법 5 — 폴더에서 파일 하나만 가져오기
때로는 폴더 자체가 전혀 필요 없을 수 있습니다. 모든 파일에는 직접 다운로드되는 raw URL이 있습니다.
https://raw.githubusercontent.com/{owner}/{repo}/{ref}/{path}
GitHub UI에서 파일을 열고 Raw를 클릭하거나(또는 마우스 오른쪽 버튼을 눌러 “다른 이름으로 링크 저장…“을 선택) 하면 됩니다. 일반 /blob/ URL에 ?raw=true를 붙여도 같은 결과가 나옵니다. 파일 세 개라면 이 방법이 이 페이지의 어떤 도구보다 낫습니다.
SVN 방법은 끝났습니다 — 그런데도 튜토리얼은 여전히 이를 권장합니다
약 10년 동안 표준적인 조언은 GitHub의 Subversion 브리지에 의존하는 것이었습니다. URL에서 /tree/main/을 /trunk/로 바꾸고 svn checkout이나 svn export를 실행하면, Git을 건드리지 않고 단일 디렉터리를 체크아웃할 수 있었습니다.
그 브리지는 더 이상 존재하지 않습니다. GitHub은 2023년 1월 Subversion 지원 종료를 발표했고, 2023년 11월과 12월에 두 차례 브라운아웃 기간을 운영해 남은 사용자를 정리했으며, 2024년 1월 8일 Subversion 프로토콜을 완전히 제거했습니다. GitHub Enterprise Server는 3.13 버전에서 뒤따랐습니다. 사라진 것은 하나 더 있습니다. git archive --remote는 GitHub이 한 번도 활성화한 적 없는 서버 측 upload-archive 서비스가 필요하며, 경로를 어떻게 구성하든 프로토콜 오류로 실패합니다.
어떤 가이드가 첫 번째 방법으로 svn checkout을 나열한다면, 그 가이드는 제거 이전에 작성된 것이며 다른 조언도 의심해 볼 가치가 있습니다. 대신 sparse checkout, Trees API, 또는 브라우저 도구를 사용하세요.
어떤 방법을 사용해야 할까요?
| 방법 | 최종 결과물 | 비공개 저장소 처리 | LFS 처리 | 주요 비용 |
|---|---|---|---|---|
| 브라우저 폴더 다운로더 | 해당 폴더의 ZIP | 예, 세분화된 토큰 필요 | 예, 도구가 LFS 미디어를 가져올 때 | 올바른 URL과 잘림을 존중하는 도구 필요 |
| 저장소 ZIP | 브랜치 전체의 ZIP | 예, API zipball 통해 가능 | 포인터만 | 대역폭과 시간이 폴더가 아니라 저장소 크기에 비례 |
git sparse-checkout |
폴더의 실제 Git 체크아웃 | 예, 자격 증명 필요 | 예, Git LFS 설치 시 | 깔끔한 아카이브가 아님; 추가 Git 객체 |
REST API + curl |
스크립트로 지정한 정확한 파일들 | 예, 토큰 필요 | 처리하지 않으면 포인터만 | 스크립트와 속도 제한 한도를 직접 관리해야 함 |
| Raw 파일 URL | 개별 파일 | 예, 인증 헤더 필요 | 처리하지 않으면 포인터만 | 수동이며 한 번에 파일 하나 |
문제 해결: 실제로 마주치는 7가지 실패
1. 분명히 존재하는 저장소에서 404. 저장소가 비공개인데 요청이 익명이기 때문입니다. 토큰을 보내세요. 자동화라면 넓은 repo 범위의 클래식 토큰 대신, 특정 저장소로 범위를 좁히고 Contents를 읽기 전용으로 설정한 세분화된 토큰을 사용하세요.
2. 긴 다운로드 도중 403. API 속도 제한에 걸린 것입니다. 인증 없이는 시간당 60회, 토큰이 있으면 5,000회입니다. 리셋 시각은 X-RateLimit-Reset 헤더에 있습니다. 인증하거나, 디렉터리당 한 번이 아니라 하위 tree 전체를 한 번의 요청으로 나열하는 도구를 사용하세요.
3. 진행 표시가 끝나지 않거나 ZIP에 파일이 누락됨. 재귀 tree 목록이 잘렸을 때의 전형적인 증상입니다. API 응답의 "truncated": true로 확인한 뒤, 루트부터 재귀하는 대신 하위 tree를 한 단계씩 가져오세요.
4. 약 130바이트짜리 파일. version https://git-lfs.github.com/spec/v1로 시작하는 Git LFS 포인터입니다. 실제 내용은 https://media.githubusercontent.com/media/{owner}/{repo}/{ref}/{path}에 있습니다. Git LFS를 설치하고 클론하거나, 엔드포인트를 자동으로 바꿔 주는 도구를 사용하세요.
5. ZIP에 예상한 폴더가 없음. 생각했던 것과 다른 브랜치에 있거나, 공식 ZIP의 경우 브랜치 루트를 보고 있어 먼저 폴더 안으로 들어가야 하는 상황입니다. URL을 복사하기 전에 브랜치 선택기를 확인하세요.
6. 서브모듈이 있어야 할 자리에 빈 폴더. 서브모듈은 부모 안의 파일이 아니라 특수 항목으로 참조되는 별도의 저장소입니다. 내용을 얻으려면 서브모듈 자체의 URL을 클론하세요.
7. 다운로드가 차단되거나 파일이 조용히 건너뛰어짐. 콘텐츠 필터가 파일 이름을 문제로 표시하기도 하고, 공격적인 광고 차단이나 개인정보 보호 확장 프로그램이 병렬 다운로드를 망가뜨릴 수 있습니다. 해당 사이트에서 확장 프로그램을 비활성화하고 다시 시도하며, 건너뛴 이름은 도구의 상태 로그에서 확인하세요.
FAQ
비공개 저장소에서 폴더를 다운로드할 수 있나요? 예. 여기 있는 모든 방법이 지원하지만, 모두 인증이 필요합니다. API 기반 도구에는 읽기 전용 Contents 권한의 개인 액세스 토큰이, 클론에는 일반 Git 자격 증명이 필요합니다. 검토하지 않은 제3자 웹사이트에 넓은 범위의 토큰을 절대 붙여넣지 마세요.
폴더를 다운로드하면 Git 기록이 유지되나요? 아니요. ZIP 아카이브와 API 다운로드는 현재 상태의 스냅샷입니다. sparse checkout을 포함해 git clone을 기반으로 한 방법만 기록을 유지합니다.
원했던 폴더보다 다운로드가 훨씬 큰 이유는 무엇인가요? 폴더가 아니라 저장소 ZIP을 다운로드했거나, 폴더에 큰 바이너리 자산이 포함되어 있기 때문입니다. 도구를 탓하기 전에 GitHub에서 해당 폴더 자체의 크기와 비교해 보세요.
특정 브랜치, 태그 또는 커밋에서 폴더를 다운로드할 수 있나요? 예. /tree/ 뒤의 경로 세그먼트가 ref이므로 https://github.com/owner/repo/tree/v2.1.0/path/to/folder가 작동하며, Trees API에 태그나 커밋 SHA를 전달해도 됩니다.
GitHub에서 코드를 다운로드하는 것은 안전한가요? 전송 자체는 안전하지만, 내용은 사용자가 업로드한 것이고 검토되지 않았습니다. 무엇이든 재사용하기 전에 저장소의 라이선스를 확인하고, 실행하기 전에 코드를 읽어 보세요. 토큰 처리 방식에 대한 개인정보 관련 설명은 FAQ에서 확인할 수 있습니다.
핵심 요약
- GitHub이 단일 폴더를 다운로드할 수 없는 이유는 Git의 객체 모델이 디렉터리를 스냅샷 내부의 tree로만 정의하기 때문입니다. 폴더는 서버 기능이 아니라 클라이언트 측 조립 작업입니다.
- 일회성 다운로드라면 브랜치 이름, 잘림, LFS, 속도 제한을 제대로 처리하는 브라우저 도구가 아무것도 설치하지 않고 몇 초 만에 작업을 끝냅니다.
- 계속 업데이트를 가져올 작업이라면 먼저 모든 것을 다운로드하는 옛
.git/info/sparse-checkout방식이 아니라git clone --filter=blob:none --sparse와git sparse-checkout set을 사용하세요. - 자동화에는 Trees API가 하위 tree 전체를 한 번의 요청으로 나열합니다. 100,000개 항목 상한과 시간당 60회 대 5,000회 제한을 기억하세요.
- 여전히
svn checkout을 앞세우는 가이드는 무시하세요. 그 경로는 2024년 1월 8일 GitHub에서 제거되었습니다.
설정을 건너뛸 준비가 되셨나요? 폴더 URL을 GitDownloader 도구에 붙여넣으면 해당 디렉터리만 압축해 줍니다. 공개든 비공개든, LFS까지 포함해, 전부 브라우저 안에서 처리됩니다.