GitDownloader
Blog

Comment télécharger un dossier depuis GitHub (sans cloner tout le dépôt)

Ouvrez presque n’importe quel dépôt sur GitHub et vous trouverez un bouton vert Code qui propose exactement deux choses : cloner l’intégralité du projet ou télécharger un ZIP de l’intégralité du projet. Cliquez sur src/components, docs/examples ou un dossier templates : le bouton est toujours là, mais il vous donne encore tout. La documentation de GitHub est sans détour à ce sujet : vous pouvez télécharger un instantané des fichiers d’un dépôt, le cloner ou le forker. Il n’existe pas de quatrième option pour un dossier.

Cet écart explique pourquoi « comment télécharger un dossier depuis GitHub » est l’une des questions les plus recherchées sur GitHub, et pourquoi les réponses que vous trouvez sont si incohérentes. Certaines recommandent encore une commande SVN qui a cessé de fonctionner en janvier 2024. D’autres vous donnent une recette Git en cinq commandes qui télécharge discrètement tout le dépôt malgré tout. Ce guide couvre toutes les méthodes qui fonctionnent réellement aujourd’hui, ce que chacune vous coûte, et les erreurs précises — limites de débit, listes de fichiers tronquées, fichiers pointeurs LFS — qui déterminent laquelle est la bonne dans votre cas.

Réponse rapide : choisissez votre méthode

Méthode Installation requise Dépôts privés Conserve l’historique Git Idéal pour
Téléchargeur de dossier via navigateur Non Oui, avec un jeton Non Téléchargements ponctuels, tailles de dossiers variées
ZIP du dépôt (officiel) Non Oui, avec un jeton Non Petits dépôts dont vous voulez la plupart des fichiers
git sparse-checkout Git Oui, avec des identifiants Oui Vous continuerez à tirer les mises à jour
API REST + curl curl, jq Oui, avec un jeton Non Scripts, CI, tâches reproductibles
Copier des fichiers isolés Non Oui, via l’API Non Deux ou trois fichiers d’un même dossier

Si vous voulez simplement le ZIP, la voie du navigateur est la plus rapide — collez l’URL du dossier dans l’outil de la page d’accueil GitDownloader et il n’empaquette que ce répertoire. Le reste de cet article explique pourquoi les autres options existent et quand elles sont plus adaptées.

Pourquoi GitHub n’a pas de bouton « télécharger ce dossier »

Cette limitation n’est pas de la paresse ; elle découle de la façon dont Git stocke les données.

Un dépôt Git est un graphe orienté d’objets. Les fichiers vivent dans des objets blob, et les répertoires sont des objets tree qui listent des noms, des modes et des hachages pointant vers des blobs ou d’autres trees. Une branche est un pointeur vers un commit, qui pointe vers un tree racine, qui décrit de manière transitive l’intégralité de l’instantané. Rien dans cette structure ne représente « le dossier src/assets comme une unité indépendante et téléchargeable » — un sous-arbre n’a de sens qu’à l’intérieur de son tree parent.

Subversion, en revanche, traitait les répertoires comme des cibles de checkout de premier ordre, ce qui explique pourquoi l’ancien pont SVN était la solution classique. Le modèle de Git vous offre l’historique, les branches et l’intégrité ; le prix à payer est que la récupération partielle est un problème côté client, pas un concept du dépôt.

L’interface de GitHub propose donc ce qui est peu coûteux et sans ambiguïté à servir :

  • Un ZIP d’une seule ref. https://github.com/{owner}/{repo}/archive/refs/heads/{branch}.zip envoie un instantané du tree racine de cette branche. Utile, mais toujours la branche entière.
  • L’API Git Trees, qui peut lister un sous-arbre en une seule requête. C’est la primitive sur laquelle repose réellement tout outil de téléchargement de dossier — y compris le nôtre.

Ainsi, télécharger un dossier n’est pas quelque chose que GitHub fait pour vous. C’est quelque chose qu’un outil ou un script fait avec l’API de GitHub, en listant les fichiers sous un chemin, en récupérant chacun d’eux et en zippant le résultat localement.

Méthode 1 — Téléchargeur de dossier dans le navigateur (sans installation)

C’est le chemin le plus court pour la majorité des gens, et le seul qui ne nécessite rien d’installé ni de terminal.

  1. Ouvrez le dossier sur GitHub et assurez-vous que le sélecteur de branche affiche la branche souhaitée.
  2. Copiez l’URL depuis la barre d’adresse. Elle doit ressembler à https://github.com/owner/repo/tree/main/path/to/folder — la forme /tree/<branch>/<path> est importante.
  3. Collez-la dans le champ URL de l’outil de la page d’accueil et cliquez sur Download ZIP.
  4. Les fichiers sont listés, récupérés et zippés dans votre navigateur, puis enregistrés dans votre dossier Téléchargements.

Ce qui distingue un bon outil d’un outil cassé à cette étape n’est pas le champ de saisie : c’est ce qui se passe ensuite :

  • Les branches avec des slashes. release/2.1 est un nom de branche valide, donc un outil doit tester des préfixes de plus en plus longs pour déterminer où se termine la branche et où commence le chemin du dossier, au lieu de deviner au premier /.
  • Les répertoires très volumineux. L’API Trees renvoie "truncated": true dès qu’une liste récursive dépasse 100 000 entrées ou 7 Mo. Un outil qui ignore ce drapeau vous remettra silencieusement un ZIP auquel il manque des fichiers. Le comportement correct consiste à revenir à un listage des sous-arbres niveau par niveau.
  • Les limites de débit. Sans authentification, vous disposez de 60 requêtes API par heure et par adresse IP ; avec un jeton, 5 000. Les outils qui listent les répertoires un par un épuisent rapidement le quota non authentifié sur les dossiers profonds, ce qui explique pourquoi les téléchargements échouent parfois à mi-parcours et refonctionnent une heure plus tard.
  • Git LFS. Les dépôts qui utilisent Large File Storage stockent un minuscule fichier pointeur à la place du véritable actif. Si rien ne détecte ce pointeur, votre ZIP est techniquement correct et totalement inutilisable.

Pour les dépôts que vous possédez ou auxquels vous avez accès, collez un jeton d’accès personnel à granularité fine dans le champ de jeton facultatif : GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens → générez-en un limité aux dépôts concernés avec Contents: Read-only. Le jeton est stocké dans votre propre navigateur et envoyé uniquement à api.github.com ; aucun serveur intermédiaire ne lit vos fichiers. Plus de détails dans la FAQ.

Méthode 2 — La voie officielle : télécharger tout le dépôt

Étonnamment souvent la bonne réponse, et il vaut la peine de connaître les URL directes car elles contournent complètement l’interface.

Via l’interface : page du dépôt → CodeDownload ZIP. Le fichier arrive nommé repo-main.zip (ou master, ou le nom de la branche par défaut).

Liens directs que vous pouvez mettre en favori ou scripter :

# Archive d’une branche (dépôts publics, sans authentification)
https://github.com/{owner}/{repo}/archive/refs/heads/{branch}.zip

# Même fichier, servi par l’hôte d’archives
https://codeload.github.com/{owner}/{repo}/zip/refs/heads/{branch}

# zipball de l’API — fonctionne pour les dépôts privés si vous envoyez un jeton
https://api.github.com/repos/{owner}/{repo}/zipball/{ref}

Choisissez cette méthode lorsque le dépôt est petit, lorsque vous voulez réellement la plupart de ses fichiers, lorsque Git n’est pas installé, ou lorsque vous voulez le commit exact derrière un tag de release. Le coût est proportionnel : un monorepo de 800 Mo à cloner représente environ 800 Mo à zipper, plus le temps passé à extraire et à supprimer les 95 % dont vous n’aviez pas besoin. Et un instantané ZIP n’est que cela — un instantané. Pas d’historique, pas de remote, pas de git pull.

Méthode 3 — git sparse-checkout, correctement utilisé

Quand vous voulez le dossier plus un checkout Git fonctionnel — afin de pouvoir tirer les mises à jour plus tard — le sparse checkout est le bon outil. La plupart des tutoriels montrent une recette obsolète ; voici la version moderne.

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

Ce qui compte ici :

  • --filter=blob:none en fait un clone partiel : Git récupère les objets commit et tree mais ignore le contenu des fichiers jusqu’à leur checkout. Sans cette option, vous téléchargez tous les blobs du dépôt et en jetez la plupart.
  • --sparse initialise le fichier sparse-checkout pour vous, ce qui évite d’écrire .git/info/sparse-checkout à la main.
  • git sparse-checkout set utilise le mode cone, qui correspond à des répertoires entiers et est nettement plus rapide sur les gros dépôts. Ajoutez d’autres chemins plus tard en répétant la commande avec plusieurs chemins, et relancez git sparse-checkout reapply si l’arbre de travail dérive.
  • Le sparse checkout nécessite Git 2.25 ou plus récent ; le clone partiel (--filter) nécessite 2.19+.

L’ancien schéma que vous verrez encore dans des articles et des réponses Stack Overflow — git init, puis git config core.sparseCheckout true, puis echo "path/" >> .git/info/sparse-checkout, puis git pull origin main — fonctionne, mais il télécharge l’historique complet et chaque blob avant de filtrer l’arbre de travail. Vous vous retrouvez avec le dossier voulu plus un répertoire .git qui peut facilement être plusieurs fois plus volumineux que les fichiers eux-mêmes.

Le véritable compromis : le sparse checkout vous donne un dépôt, pas une archive. Si vous vouliez un ZIP propre à déposer dans un autre projet, vous avez maintenant un checkout auquel est attaché un remote — ce qui est exactement ce que vous vouliez si vous prévoyez de contribuer, et une pure surcharge sinon.

Méthode 4 — Scriptez-la avec l’API REST de GitHub

Pour les tâches reproductibles — vendorer un dossier partagé dans un autre dépôt, récupérer des templates en CI, rafraîchir les actifs de documentation chaque nuit — vous voulez quelque chose que vous pouvez exécuter sans interface. L’API vous fournit deux briques de base.

API Trees (une requête pour tout le sous-arbre) :

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

La réponse contient un tableau plat tree avec un path et un type pour chaque entrée. Les entrées de type: "blob" sont des fichiers. Le hic, c’est le plafond documenté : avec recursive=1, le tableau est limité à 100 000 entrées et 7 Mo, et dès que vous le dépassez, la réponse définit "truncated": true. Dans ce cas, le correctif documenté consiste à récupérer l’arbre de manière non récursive et à parcourir vous-même les sous-arbres.

API Contents (une requête par répertoire) :

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

Cette API renvoie une liste avec un download_url pour chaque fichier, et c’est ce que la plupart des outils de navigateur utilisaient historiquement. Elle ne tronque jamais, mais elle coûte une requête par répertoire, ce qui explique pourquoi les arbres profonds épuisent les limites de débit.

Un petit script complet utilisant l’API Trees plus raw.githubusercontent.com :

OWNER=octocat
REPO=Spoon-Knife
REF=main
PREFIX=src/assets
TOKEN=""   # à définir pour les dépôts privés : export TOKEN=ghp_xxx

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

# 1. Vérifier que la liste n’est pas tronquée avant de s’y fier
curl -s "${AUTH[@]}" \
  "https://api.github.com/repos/$OWNER/$REPO/git/trees/$REF?recursive=1" \
  | jq -r '.truncated'

# 2. Écrire chaque chemin de fichier sous le préfixe dans une liste
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. Récupérer chaque fichier, en créant les répertoires au besoin
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

Deux remarques opérationnelles. Premièrement, surveillez les en-têtes de réponse : X-RateLimit-Remaining vous indique le budget restant et X-RateLimit-Reset le moment où il se recharge — sans authentification, ce budget est de 60 requêtes par heure et par IP, donc un dossier de 200 fichiers échouera à mi-parcours sans jeton. Deuxièmement, raw.githubusercontent.com respecte un en-tête Authorization pour les dépôts privés, mais vous devez réellement l’envoyer ; sans cela, vous obtenez un 404 qui ressemble exactement à un fichier supprimé.

Méthode 5 — Récupérer un seul fichier d’un dossier

Parfois vous n’avez pas besoin du dossier du tout. Chaque fichier dispose d’une URL raw qui le télécharge directement :

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

Depuis l’interface GitHub, ouvrez le fichier et cliquez sur Raw (ou faites un clic droit dessus et choisissez « Save link as… »). Ajouter ?raw=true à une URL /blob/ normale produit le même effet. Pour trois fichiers, cela bat tous les outils de cette page.

L’astuce SVN est morte — et les tutoriels la recommandent encore

Pendant environ une décennie, le conseil standard était de s’appuyer sur le pont Subversion de GitHub : remplacer /tree/main/ par /trunk/ dans l’URL et exécuter svn checkout ou svn export dessus, ce qui extrait un seul répertoire sans toucher à Git.

Ce pont n’existe plus. GitHub a annoncé l’arrêt du support de Subversion en janvier 2023, a mené deux périodes de coupure partielle en novembre et décembre 2023 pour déloger les utilisateurs restants, et a supprimé entièrement le protocole Subversion le 8 janvier 2024. GitHub Enterprise Server a suivi en version 3.13. Disparu également : git archive --remote, qui nécessite le service côté serveur upload-archive que GitHub n’a jamais activé — la commande échoue avec une erreur de protocole quelle que soit la façon dont vous formatez le chemin.

Si un guide liste svn checkout comme première méthode, ce guide est antérieur à la suppression et ses autres conseils méritent aussi un examen critique. Utilisez plutôt le sparse checkout, l’API Trees ou un outil de navigateur.

Quelle méthode choisir ?

Méthode Ce que vous obtenez Gère les dépôts privés Gère LFS Coût principal
Téléchargeur de dossier via navigateur Un ZIP du dossier Oui, avec un jeton à granularité fine Oui, quand l’outil récupère les médias LFS Nécessite une URL correcte et un outil qui respecte la troncature
ZIP du dépôt Un ZIP de toute la branche Oui, via le zipball de l’API Pointeurs uniquement La bande passante et le temps évoluent avec le dépôt, pas avec le dossier
git sparse-checkout Un véritable checkout Git du dossier Oui, avec des identifiants Oui, avec Git LFS installé Pas une archive propre ; des objets Git supplémentaires
API REST + curl Les fichiers exacts que vous avez scriptés Oui, avec un jeton Pointeurs sauf si gérés Vous maintenez le script et le budget de limite de débit
URL de fichiers raw Des fichiers individuels Oui, avec un en-tête d’authentification Pointeurs sauf si gérés Manuel et un fichier à la fois

Dépannage : les sept échecs que vous rencontrerez réellement

1. Un 404 sur un dépôt qui existe manifestement. Il est privé et votre requête est anonyme. Envoyez un jeton. Pour tout ce qui est automatisé, utilisez un jeton à granularité fine limité aux dépôts concernés avec Contents en lecture seule plutôt qu’un jeton classique doté d’un large scope repo.

2. Un 403 à mi-parcours d’un long téléchargement. Vous avez atteint la limite de débit de l’API : 60 requêtes par heure sans authentification, 5 000 avec un jeton. L’heure de réinitialisation se trouve dans l’en-tête X-RateLimit-Reset. Authentifiez-vous, ou utilisez un outil qui liste tout un sous-arbre en une seule requête au lieu d’une requête par répertoire.

3. L’indicateur de progression ne se termine jamais, ou il manque des fichiers dans le ZIP. Symptôme classique d’une liste d’arbre récursive tronquée. Confirmez-le avec "truncated": true dans la réponse de l’API, puis récupérez les sous-arbres niveau par niveau au lieu de récurser depuis la racine.

4. Des fichiers d’environ 130 octets. Ce sont des pointeurs Git LFS commençant par version https://git-lfs.github.com/spec/v1. Le vrai contenu se trouve à https://media.githubusercontent.com/media/{owner}/{repo}/{ref}/{path}. Soit vous clonez avec Git LFS installé, soit vous utilisez un outil qui bascule automatiquement le point de terminaison.

5. Le ZIP ne contient pas le dossier attendu. Vous êtes sur une branche différente de celle que vous supposez, ou — avec le ZIP officiel — vous regardez la racine de la branche et devez d’abord naviguer dans le dossier. Vérifiez le sélecteur de branche avant de copier l’URL.

6. Des dossiers vides là où devrait se trouver un sous-module. Les sous-modules sont des dépôts distincts référencés par une entrée spéciale, et non des fichiers à l’intérieur du parent. Clonez l’URL du sous-module lui-même pour obtenir son contenu.

7. Téléchargement bloqué ou fichier ignoré silencieusement. Les filtres de contenu signalent parfois certains noms de fichiers, et des extensions agressives de blocage de publicités ou de protection de la vie privée peuvent casser les téléchargements parallèles. Réessayez en désactivant les extensions pour le site et consultez le journal d’état de l’outil pour connaître les noms ignorés.

FAQ

Puis-je télécharger un dossier depuis un dépôt privé ? Oui. Toutes les méthodes présentées ici le permettent, mais toutes exigent une authentification : un jeton d’accès personnel avec la permission Contents en lecture seule pour les outils basés sur l’API, ou des identifiants Git normaux pour un clone. Ne collez jamais un jeton à large portée dans un site tiers que vous n’avez pas examiné.

Le téléchargement d’un dossier préserve-t-il l’historique Git ? Non. Les archives ZIP et les téléchargements via l’API sont des instantanés de l’état actuel. Seules les méthodes basées sur git clone — y compris le sparse checkout — conservent l’historique.

Pourquoi mon téléchargement est-il bien plus volumineux que le dossier voulu ? Parce que vous avez téléchargé le ZIP du dépôt plutôt que le dossier, ou parce que le dossier contient de gros actifs binaires. Comparez avec la taille du dossier lui-même sur GitHub avant d’accuser l’outil.

Puis-je télécharger un dossier d’une branche, d’un tag ou d’un commit précis ? Oui. Le segment de chemin après /tree/ est la ref, donc https://github.com/owner/repo/tree/v2.1.0/path/to/folder fonctionne, tout comme le fait de passer un tag ou un SHA de commit à l’API Trees.

Télécharger du code depuis GitHub est-il sûr ? Le transport l’est, mais le contenu est téléversé par des utilisateurs et non vérifié. Vérifiez la licence du dépôt avant de réutiliser quoi que ce soit, lisez le code avant de l’exécuter, et consultez les notes de confidentialité dans notre FAQ pour savoir comment les jetons sont traités.

Points clés à retenir

  • GitHub ne peut pas télécharger un dossier unique, car le modèle objet de Git ne définit les répertoires que comme des trees à l’intérieur d’un instantané — le dossier est un travail d’assemblage côté client, pas une fonctionnalité serveur.
  • Pour un téléchargement ponctuel, un outil de navigateur qui respecte les noms de branches, la troncature, LFS et les limites de débit terminera le travail en quelques secondes sans rien installer.
  • Pour un travail que vous continuerez à tirer, utilisez git clone --filter=blob:none --sparse plus git sparse-checkout set — et non l’ancienne recette .git/info/sparse-checkout qui télécharge tout d’abord.
  • Pour l’automatisation, l’API Trees liste tout un sous-arbre en une seule requête ; rappelez-vous le plafond de 100 000 entrées et la limite de 60 contre 5 000 requêtes par heure.
  • Ignorez tout guide qui commence encore par svn checkout. Ce chemin a été supprimé de GitHub le 8 janvier 2024.

Prêt à éviter toute la configuration ? Collez l’URL d’un dossier dans l’outil GitDownloader et il n’empaquettera que ce répertoire — public ou privé, LFS inclus, entièrement dans votre navigateur.