GitDownloader
Blog

Cómo descargar una carpeta de GitHub (sin clonar todo el repositorio)

Abre casi cualquier repositorio en GitHub y verás un botón verde Code que ofrece exactamente dos cosas: clonar el proyecto completo o descargar un ZIP de todo el proyecto. Entra en src/components, docs/examples o una carpeta templates, y el botón sigue ahí, pero te sigue dando todo. La propia documentación de GitHub es tajante al respecto: puedes descargar una instantánea de los archivos de un repositorio, clonarlo o hacer un fork. No hay una cuarta opción para una carpeta.

Ese vacío es la razón de que «cómo descargar una carpeta de GitHub» sea una de las preguntas más buscadas sobre GitHub, y de que las respuestas que encuentras sean tan dispares. Algunas siguen recomendando un comando SVN que dejó de funcionar en enero de 2024. Otras te dan una receta Git de cinco comandos que, en silencio, acaba descargando el repositorio entero igualmente. Esta guía cubre todos los métodos que funcionan de verdad hoy, lo que te cuesta cada uno y los errores concretos —límites de peticiones, listados de archivos truncados, archivos puntero de LFS— que determinan cuál es el adecuado para tu caso.

Respuesta rápida: elige tu método

Método Requiere instalación Repos privados Conserva el historial de Git Ideal para
Descargador de carpetas en el navegador No Sí, con un token No Descargas puntuales, carpetas de tamaños variados
ZIP del repositorio (oficial) No Sí, con un token No Repos pequeños donde necesitas la mayoría de los archivos
git sparse-checkout Git Sí, con credenciales Vas a seguir trayendo actualizaciones
API REST + curl curl, jq Sí, con un token No Scripts, CI, tareas repetibles
Copiar archivos sueltos No Sí, vía API No Dos o tres archivos de una carpeta

Si solo quieres el ZIP, la vía del navegador es la más rápida: pega la URL de la carpeta en la herramienta de la página de inicio de GitDownloader y empaquetará únicamente ese directorio. El resto del artículo explica por qué existen las otras opciones y cuándo son la mejor elección.

Por qué GitHub no tiene un botón de «descargar esta carpeta»

La limitación no es pereza; se deriva de cómo Git almacena los datos.

Un repositorio Git es un grafo dirigido de objetos. Los archivos viven en objetos blob, y los directorios son objetos tree que enumeran nombres, modos y hashes que apuntan a blobs u otros trees. Una rama es un puntero a un commit, que apunta a un tree raíz, que describe de forma transitiva la instantánea completa. Nada en esa estructura representa «la carpeta src/assets como una unidad independiente y descargable»: un subárbol solo tiene sentido dentro de su tree padre.

Subversion, en cambio, trataba los directorios como objetivos de checkout de primera clase, y por eso el viejo puente SVN era el truco clásico. El modelo de Git te da historial, ramas e integridad; el precio es que la recuperación parcial es un problema del lado del cliente, no un concepto del repositorio.

Por eso la interfaz de GitHub ofrece lo que resulta barato e inequívoco de servir:

  • Un ZIP de una ref. https://github.com/{owner}/{repo}/archive/refs/heads/{branch}.zip sirve una instantánea del tree raíz de esa rama. Útil, pero siempre la rama completa.
  • La API Git Trees, que puede listar un subárbol en una sola petición. Esta es la primitiva sobre la que se construye realmente toda herramienta de descarga de carpetas, incluida la nuestra.

Así que descargar una carpeta no es algo que GitHub haga por ti. Es algo que hace una herramienta o un script con la API de GitHub, listando los archivos bajo una ruta, obteniendo cada uno y comprimiendo el resultado en local.

Método 1 — Descargador de carpetas en el navegador (sin instalar nada)

Es el camino más corto para la mayoría de la gente, y el único que no necesita nada instalado ni una terminal.

  1. Abre la carpeta en GitHub y comprueba que el selector de ramas muestra la rama que quieres.
  2. Copia la URL de la barra de direcciones. Debería tener el aspecto https://github.com/owner/repo/tree/main/path/to/folder: la forma /tree/<branch>/<path> importa.
  3. Pégala en el campo de URL de la herramienta de la página de inicio y pulsa Download ZIP.
  4. Los archivos se listan, se descargan y se comprimen en tu navegador, y luego se guardan en tu carpeta de Descargas.

Lo que separa a una buena herramienta de una rota en este paso no es el campo de entrada, sino lo que ocurre después:

  • Ramas con barras. release/2.1 es un nombre de rama válido, así que una herramienta debe probar prefijos progresivamente más largos para deducir dónde termina la rama y dónde empieza la ruta de la carpeta, en lugar de adivinar en la primera barra.
  • Directorios muy grandes. La API Trees devuelve "truncated": true en cuanto un listado recursivo supera las 100.000 entradas o los 7 MB. Una herramienta que ignore ese flag te entregará silenciosamente un ZIP al que le faltan archivos. El comportamiento correcto es recurrir a listar los sub-trees nivel a nivel.
  • Límites de peticiones. Sin autenticación obtienes 60 peticiones a la API por hora y por dirección IP; con un token, 5.000. Las herramientas que listan directorios uno a uno agotan rápido el presupuesto no autenticado en carpetas profundas, y por eso las descargas a veces fallan a medias y vuelven a funcionar una hora después.
  • Git LFS. Los repositorios que usan Large File Storage guardan un pequeño archivo puntero en lugar del recurso real. Si nada detecta ese puntero, tu ZIP es técnicamente correcto y completamente inútil.

Para repositorios que son tuyos o a los que tienes acceso, pega un token de acceso personal de grano fino en el campo opcional de token: GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens → genera uno limitado a los repositorios concretos con Contents: Read-only. El token se guarda en tu propio navegador y solo se envía a api.github.com; no hay ningún servidor en medio leyendo tus archivos. Hay más detalles en las FAQ.

Método 2 — La vía oficial: descargar el repositorio completo

Sigue siendo la respuesta correcta con sorprendente frecuencia, y merece la pena conocer las URL directas porque se saltan la interfaz por completo.

Desde la interfaz: página del repositorio → CodeDownload ZIP. El archivo llega con el nombre repo-main.zip (o master, o cualquiera que sea la rama por defecto).

Enlaces directos que puedes guardar en marcadores o usar en scripts:

# Archivo de la rama (repos públicos, sin autenticación)
https://github.com/{owner}/{repo}/archive/refs/heads/{branch}.zip

# El mismo archivo, servido por el host de archivos
https://codeload.github.com/{owner}/{repo}/zip/refs/heads/{branch}

# Zipball de la API — funciona con repos privados si envías un token
https://api.github.com/repos/{owner}/{repo}/zipball/{ref}

Elige esto cuando el repositorio sea pequeño, cuando de verdad quieras la mayoría de sus archivos, cuando no tengas Git instalado o cuando quieras el commit exacto que hay detrás de una etiqueta de release. El coste es proporcional: un monorepo que ocupa 800 MB al clonarlo ocupa más o menos 800 MB al comprimirlo, además del tiempo empleado en extraer y borrar el 95 % que no necesitabas. Y una instantánea ZIP es solo eso: una instantánea. Sin historial, sin remoto, sin git pull.

Método 3 — git sparse-checkout, bien hecho

Cuando quieres la carpeta más un checkout de Git funcional —para poder traer actualizaciones después—, el sparse checkout es la herramienta adecuada. La mayoría de los tutoriales muestran una receta obsoleta; aquí está la moderna.

git clone --filter=blob:none --sparse https://github.com/owner/repo.git
cd repo
git sparse-checkout set path/to/folder

Lo que importa aquí:

  • --filter=blob:none lo convierte en un clon parcial: Git obtiene los objetos commit y tree, pero se salta el contenido de los archivos hasta que se hace checkout de ellos. Sin ese flag, descargas todos los blobs del repositorio y tiras la mayoría.
  • --sparse inicializa por ti el archivo de sparse-checkout, así que no tienes que escribir .git/info/sparse-checkout a mano.
  • git sparse-checkout set usa el modo cono, que coincide con directorios completos y es muchísimo más rápido en repos grandes. Añade más rutas después repitiendo el comando con varias rutas, y vuelve a ejecutar git sparse-checkout reapply si el árbol de trabajo se desvía.
  • El sparse checkout requiere Git 2.25 o superior; el clon parcial (--filter) requiere 2.19+.

El patrón antiguo que seguirás viendo en posts y respuestas de Stack Overflow —git init, luego git config core.sparseCheckout true, luego echo "path/" >> .git/info/sparse-checkout, luego git pull origin main— sí funciona, pero descarga el historial completo y todos los blobs antes de filtrar el árbol de trabajo. Acabas con la carpeta que querías más un directorio .git que puede ser fácilmente varias veces más grande que los propios archivos.

El verdadero compromiso: el sparse checkout te da un repositorio, no un archivo comprimido. Si querías un ZIP limpio para soltarlo en otro proyecto, ahora tienes un checkout con un remoto asociado, que es exactamente lo que querías si piensas contribuir, y pura sobrecarga si no.

Método 4 — Automatízalo con la API REST de GitHub

Para tareas repetibles —integrar una carpeta compartida en otro repo, traer plantillas en CI, refrescar los recursos de documentación cada noche— quieres algo que puedas ejecutar sin interfaz. La API te da dos piezas básicas.

API Trees (una petición para todo el subárbol):

GET https://api.github.com/repos/{owner}/{repo}/git/trees/{ref}?recursive=1

La respuesta contiene un array plano tree con un path y un type para cada entrada. Las entradas con type: "blob" son archivos. El problema es el techo documentado: con recursive=1 el array está limitado a 100.000 entradas y 7 MB, y en cuanto lo superas la respuesta pone "truncated": true. Cuando eso pasa, la solución documentada es obtener el tree de forma no recursiva e ir recorriendo los sub-trees tú mismo.

API Contents (una petición por directorio):

GET https://api.github.com/repos/{owner}/{repo}/contents/{path}?ref={ref}

Devuelve un listado con un download_url para cada archivo, y es lo que usaban históricamente la mayoría de las herramientas de navegador. Nunca trunca, pero cuesta una petición por directorio, y por eso los árboles profundos agotan los límites de peticiones.

Un script completo y pequeño usando la API Trees más raw.githubusercontent.com:

OWNER=octocat
REPO=Spoon-Knife
REF=main
PREFIX=src/assets
TOKEN=""   # defínelo para repos privados: export TOKEN=ghp_xxx

AUTH=()
[ -n "$TOKEN" ] && AUTH=(-H "Authorization: Bearer $TOKEN")

# 1. Comprueba que el listado no está truncado antes de confiar en él
curl -s "${AUTH[@]}" \
  "https://api.github.com/repos/$OWNER/$REPO/git/trees/$REF?recursive=1" \
  | jq -r '.truncated'

# 2. Escribe en una lista cada ruta de archivo bajo el prefijo
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. Obtén cada archivo, creando los directorios necesarios
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

Dos notas operativas. Primera, vigila las cabeceras de la respuesta: X-RateLimit-Remaining te dice cuánto presupuesto queda y X-RateLimit-Reset cuándo se recarga; sin autenticar ese presupuesto es de 60 peticiones por hora y por IP, así que una carpeta de 200 archivos fallará a medias sin un token. Segunda, raw.githubusercontent.com respeta una cabecera Authorization para repositorios privados, pero tienes que enviarla de verdad; sin ella obtienes un 404 idéntico al de un archivo borrado.

Método 5 — Coger solo un archivo de una carpeta

A veces no necesitas la carpeta en absoluto. Cada archivo tiene una URL raw que se descarga directamente:

https://raw.githubusercontent.com/{owner}/{repo}/{ref}/{path}

Desde la interfaz de GitHub, abre el archivo y haz clic en Raw (o haz clic derecho y elige «Save link as…»). Añadir ?raw=true a una URL /blob/ normal hace lo mismo. Para tres archivos, esto supera a cualquier herramienta de esta página.

El truco de SVN está muerto, y los tutoriales siguen recomendándolo

Durante aproximadamente una década, el consejo estándar fue apoyarse en el puente de Subversion de GitHub: sustituir /tree/main/ por /trunk/ en la URL y ejecutar svn checkout o svn export contra ella, lo que hacía checkout de un único directorio sin tocar Git.

Ese puente ya no existe. GitHub anunció el fin del soporte de Subversion en enero de 2023, ejecutó dos periodos de apagón en noviembre y diciembre de 2023 para desalojar a los usuarios que quedaban, y eliminó por completo el protocolo Subversion el 8 de enero de 2024. GitHub Enterprise Server le siguió en la versión 3.13. También desapareció git archive --remote, que necesita el servicio upload-archive del servidor que GitHub nunca ha habilitado: el comando falla con un error de protocolo sin importar cómo formatees la ruta.

Si una guía lista svn checkout como su primer método, esa guía es anterior a la eliminación y el resto de sus consejos también merece un examen crítico. Usa sparse checkout, la API Trees o una herramienta de navegador en su lugar.

¿Qué método deberías usar?

Método Con qué acabas Gestiona repos privados Gestiona LFS Coste principal
Descargador de carpetas en el navegador Un ZIP de la carpeta Sí, con un token de grano fino Sí, cuando la herramienta descarga los medios de LFS Necesita una URL correcta y una herramienta que respete el truncado
ZIP del repositorio Un ZIP de toda la rama Sí, vía el zipball de la API Solo punteros El ancho de banda y el tiempo escalan con el repo, no con la carpeta
git sparse-checkout Un checkout real de Git de la carpeta Sí, con credenciales Sí, con Git LFS instalado No es un archivo limpio; objetos Git extra
API REST + curl Los archivos exactos que has programado Sí, con un token Punteros salvo que los gestiones Mantienes tú el script y el presupuesto de peticiones
URL de archivo raw Archivos individuales Sí, con una cabecera de autenticación Punteros salvo que los gestiones Manual y de uno en uno

Solución de problemas: los siete fallos que encontrarás de verdad

1. Un 404 en un repositorio que claramente existe. Es privado y tu petición es anónima. Envía un token. Para cualquier cosa automatizada, usa un token de grano fino limitado a los repos concretos con Contents en solo lectura en lugar de un token clásico con el amplio scope repo.

2. Un 403 a mitad de una descarga larga. Has alcanzado el límite de peticiones de la API: 60 por hora sin autenticar, 5.000 con un token. La hora de reinicio está en la cabecera X-RateLimit-Reset. Autentícate, o usa una herramienta que liste todo un subárbol en una sola petición en lugar de una petición por directorio.

3. El indicador de progreso nunca termina, o al ZIP le faltan archivos. Síntoma clásico de un listado recursivo de árbol truncado. Confírmalo con "truncated": true en la respuesta de la API y luego obtén los sub-trees nivel a nivel en lugar de recurrir desde la raíz.

4. Archivos de unos 130 bytes. Son punteros de Git LFS que empiezan por version https://git-lfs.github.com/spec/v1. El contenido real vive en https://media.githubusercontent.com/media/{owner}/{repo}/{ref}/{path}. O clonas con Git LFS instalado, o usas una herramienta que cambie el endpoint automáticamente.

5. El ZIP no contiene la carpeta que esperabas. Estás en una rama distinta de la que suponías o, con el ZIP oficial, estás viendo la raíz de la rama y necesitas entrar antes en la carpeta. Comprueba el selector de ramas antes de copiar la URL.

6. Carpetas vacías donde debería haber un submódulo. Los submódulos son repositorios independientes referenciados por una entrada especial, no archivos dentro del padre. Clona la URL del propio submódulo para obtener su contenido.

7. Descarga bloqueada o archivo omitido en silencio. Los filtros de contenido a veces marcan nombres de archivo, y los bloqueadores de anuncios o extensiones de privacidad agresivas pueden romper las descargas en paralelo. Reintenta con las extensiones desactivadas para el sitio y revisa el registro de estado de la herramienta para ver los nombres omitidos.

FAQ

¿Puedo descargar una carpeta de un repositorio privado? Sí. Todos los métodos de aquí lo permiten, pero todos requieren autenticación: un token de acceso personal con permiso de solo lectura sobre Contents para las herramientas basadas en API, o credenciales Git normales para un clon. Nunca pegues un token de scope amplio en un sitio web de terceros que no hayas revisado.

¿La descarga de una carpeta conserva el historial de Git? No. Los archivos ZIP y las descargas por API son instantáneas del estado actual. Solo los métodos basados en git clone —incluido el sparse checkout— conservan el historial.

¿Por qué mi descarga es mucho más grande que la carpeta que quería? Porque descargaste el ZIP del repositorio en lugar de la carpeta, o porque la carpeta contiene recursos binarios grandes. Compara con el tamaño de la propia carpeta en GitHub antes de culpar a la herramienta.

¿Puedo descargar una carpeta de una rama, etiqueta o commit concretos? Sí. El segmento de ruta después de /tree/ es la ref, así que https://github.com/owner/repo/tree/v2.1.0/path/to/folder funciona, igual que pasar una etiqueta o un SHA de commit a la API Trees.

¿Es seguro descargar código de GitHub? El transporte sí lo es, pero el contenido lo sube el usuario y nadie lo revisa. Comprueba la licencia del repositorio antes de reutilizar cualquier cosa, lee el código antes de ejecutarlo y consulta las notas de privacidad de nuestras FAQ sobre cómo se gestionan los tokens.

Conclusiones clave

  • GitHub no puede descargar una sola carpeta porque el modelo de objetos de Git solo define directorios como trees dentro de una instantánea: la carpeta es un trabajo de ensamblaje del lado del cliente, no una función del servidor.
  • Para una descarga puntual, una herramienta de navegador que respete los nombres de rama, el truncado, LFS y los límites de peticiones hará el trabajo en segundos sin instalar nada.
  • Para trabajo del que seguirás trayendo cambios, usa git clone --filter=blob:none --sparse más git sparse-checkout set, no la receta antigua de .git/info/sparse-checkout que descarga todo primero.
  • Para automatización, la API Trees lista todo un subárbol en una sola petición; recuerda el techo de 100.000 entradas y el límite de 60 frente a 5.000 peticiones por hora.
  • Ignora cualquier guía que siga empezando por svn checkout. Esa vía se eliminó de GitHub el 8 de enero de 2024.

¿Listo para saltarte la configuración? Pega la URL de una carpeta en la herramienta GitDownloader y empaquetará solo ese directorio: público o privado, LFS incluido, enteramente en tu navegador.