Est-il possible de faire une extraction clairsemée sans avoir d'abord vérifié l'intégralité du référentiel?

171

Je travaille avec un référentiel avec un très grand nombre de fichiers dont l'extraction prend des heures. J'étudie la possibilité de savoir si Git fonctionnerait bien avec ce type de référentiel maintenant qu'il prend en charge les extractions éparses, mais chaque exemple que je peux trouver fait ce qui suit:

git clone <path>
git config core.sparsecheckout true
echo <dir> > .git/info/sparse-checkout
git read-tree -m -u HEAD

Le problème avec cette séquence de commandes est que le clone d'origine effectue également une extraction. Si vous ajoutez -n à la commande de clonage d'origine, la commande read-tree génère l'erreur suivante:

erreur: l'extraction éparse ne laisse aucune entrée sur le répertoire de travail

Comment faire l'extraction parcimonieuse sans avoir d'abord extrait tous les fichiers?

dromodel
la source
4
duplication possible de Existe
Chronial du
Remarque: git worktree add --no-checkoutfonctionnera aussi (pas seulement git clone --no-checkout) avec git 2.9 (juste 2016). Voir ma réponse ci
VonC
Après avoir essayé toutes les solutions ici, la seule qui télécharge simplement le répertoire (sans pousser après!) Est la suivante .
LondonRob

Réponses:

24

En 2020, il existe un moyen plus simple de gérer les extractions éparses sans avoir à se soucier des fichiers .git. Voici comment je l'ai fait:

git clone <URL> --no-checkout <directory>
cd <directory>
git sparse-checkout init --cone # to fetch only root files
git sparse-checkout set apps/my_app libs/my_lib # etc, to list sub-folders to checkout
# they are checked out immediately after this command, no need to run git pull

Notez qu'il nécessite l'installation de la version 2.25 de git. En savoir plus ici: https://github.blog/2020-01-17-bring-your-monorepo-down-to-size-with-sparse-checkout/

METTRE À JOUR:

La git clonecommande ci-dessus clonera toujours le dépôt avec son historique complet, mais sans extraire les fichiers. Si vous n'avez pas besoin de l'historique complet, vous pouvez ajouter le paramètre --depth à la commande, comme ceci:

# create a shallow clone,
# with only 1 (since depth equals 1) latest commit in history
git clone <URL> --no-checkout <directory> --depth 1
Alexey Grinko
la source
1
C'est vrai, bon point. Vote positif. J'ai suivi la sparse-checkout --conefonctionnalité dans stackoverflow.com/a/59515426/6309
VonC
Cela vaudrait la peine d'ajouter un clone partiel ( --filter) à votre réponse ici.
Tao
@ alexey-grinko, la première commande devait encore cloner tout le dépôt en question, même si elle ne l'avait pas vérifié ... Je cherchais à gagner du temps en ne clonant pas tout ce dont je n'ai pas besoin. .
mropp
1
@mropp, j'ai mis à jour la réponse en ajoutant un --depthparamètre qui nous permet de faire un clone superficiel. Cela aidera-t-il? @Tao, je ne sais pas comment utiliser --filterdans ce cas, je ne l'ai pas essayé. Pourriez-vous donner un exemple ou publier une autre réponse à ce sujet?
Alexey Grinko
4
notez que cela ne fonctionne pas de la même manière dans la version 2.27 - je ne sais pas pourquoi.
Blazes le
162

Veuillez noter que cette réponse télécharge une copie complète des données à partir d'un référentiel. La git remote add -fcommande clonera tout le référentiel. Depuis la page de manuel degit-remote :

Avec l' -foption, git fetch <name>s'exécute immédiatement après la configuration des informations distantes.


Essaye ça:

mkdir myrepo
cd myrepo
git init
git config core.sparseCheckout true
git remote add -f origin git://...
echo "path/within_repo/to/desired_subdir/*" > .git/info/sparse-checkout
git checkout [branchname] # ex: master

Vous constaterez maintenant que vous avez une extraction "élaguée" avec uniquement les fichiers de chemin / within_repo / vers / souhaité_subdir présents (et dans ce chemin).

Notez que sur la ligne de commande Windows vous ne devez pas citer le chemin, c'est à dire que vous devez changer la 6ème commande avec celle-ci:

echo path/within_repo/to/desired_subdir/* > .git/info/sparse-checkout

si vous ne le faites pas, vous obtiendrez les guillemets dans le fichier de retrait épars, et cela ne fonctionnera pas

Apenwarr
la source
3
Je ne peux pas utiliser la commande "git checkout [branchname]" (également trouvé une erreur: Sparse checkout ne laisse aucune entrée sur le répertoire de travail). J'ai utilisé "git pull origin master" et cela fonctionne correctement.
Natty
2
Avec la version 1.7.2.5 de git sur linux, j'ai obtenu les résultats suivants: echo 'dir / *' extrait uniquement les fichiers dans dir / mais pas dans ses sous-répertoires; echo 'dir /' (pas d'astérisque!) vérifie correctement l'arborescence entière sous dir /. HTH
pavek
37
Cela n'a tout simplement pas fonctionné pour moi - la commande "git remote" a entraîné l'extraction de tout le dépôt - bam! - droit alors; donc le "git config ..." et la spécification d'un sous-répertoire d'intérêt dans les commandes suivantes n'ont eu aucun effet. L'URL du dépôt est-elle spécifiée dans la commande "git remote" uniquement le chemin vers le fichier .git de niveau supérieur? Ou devrait-il s'agir d'un chemin vers le sous-répertoire d'intérêt?
Rob Cranfill
10
voici une version simplifiée (pas besoin de créer manuellement le répertoire, de faire un init et un ajout à distance, il suffit de faire le cycle git clone + checkout normal avec l'option --no-checkout comme mentionné par @onionjake): git clone --no-checkout <project> cd <project> echo <dir>> .git / info / sparse-checkout git checkout <branch>
Gregor
22
La git remote addcommande télécharge tout parce que c'est ce qui -ffait - lui dit de récupérer immédiatement, avant que vous ayez défini les options d'extraction éparses. Mais omettre ou réorganiser cela ne va pas aider. Les extractions éparses n'affectent que l'arborescence de travail, pas le référentiel. Si vous souhaitez que votre référentiel adopte un régime à la place, vous devez plutôt regarder les options --depthou --single-branch.
Miral du
43

Git clone a une option ( --no-checkoutou -n) qui fait ce que vous voulez.

Dans votre liste de commandes, changez simplement:

git clone <path>

Pour ça:

git clone --no-checkout <path>

Vous pouvez ensuite utiliser la caisse clairsemée comme indiqué dans la question.

oignon
la source
7
ouais, il ne fait pas de paiement, mais fait toujours une recherche pour télécharger l'intégralité de l'historique du dépôt
Jason S
9
@JasonS, la question portait spécifiquement sur le fait de ne pas payer. Si vous ne le souhaitez pas, tout l'historique utilisez l' --depth <depth>option sur git clone. Cela ne téléchargera que les derniers <depth>commits de l'historique. Actuellement, il n'y a aucun moyen de télécharger partiellement un seul commit avec git, mais si votre télécommande le prend en charge, vous pouvez l'utiliser git archive --remotepour télécharger des ensembles partiels de fichiers.
onionjake
Vous pouvez maintenant également «vérifier» un commit sans télécharger de fichiers en utilisant vfsforgit.org . Cela peut être utile si quelqu'un essaie de ne retirer qu'un petit sous-ensemble d'un seul commit.
onionjake
22

J'ai eu un cas d'utilisation similaire, sauf que je voulais extraire uniquement le commit d'une balise et élaguer les répertoires. L'utilisation --depth 1rend les choses vraiment rares et peut vraiment accélérer les choses.

mkdir myrepo
cd myrepo
git init
git config core.sparseCheckout true
git remote add origin <url>  # Note: no -f option
echo "path/within_repo/to/subdir/" > .git/info/sparse-checkout
git fetch --depth 1 origin tag <tagname>
git checkout <tagname>
sourcedelica
la source
3
--depth 1 est appelé un clone peu profond, juste pour info.
Mark Allison
1
Cela a aidé! Merci
kp123
1
Merci pour cela. J'ai bien compris après avoir essayé de nombreuses autres façons d'empêcher le téléchargement de l'ensemble du dépôt.
J ... S
12

J'ai trouvé la réponse que je cherchais dans le one-liner posté plus tôt par pavek (merci!) Donc je voulais fournir une réponse complète en une seule réponse qui fonctionne sous Linux (GIT 1.7.1):

1--> mkdir myrepo
2--> cd myrepo
3--> git init
4--> git config core.sparseCheckout true
5--> echo 'path/to/subdir/' > .git/info/sparse-checkout
6--> git remote add -f origin ssh://...
7--> git pull origin master

J'ai un peu changé l'ordre des commandes mais cela ne semble pas avoir d'impact. La clé est la présence de la barre oblique de fin "/" à la fin du chemin à l'étape 5.

JF Bergeron
la source
3
êtes-vous sûr que c'est ce que vous voulez? le -f signifie récupérer toutes les données, vous obtenez toujours toutes les autres informations que vous ne voulez pas et c'est lent. (Ceci est toujours "en train de vérifier tout le dépôt")
Shuman
1
J'ai essayé les étapes ci-dessus dans Windows mais le paiement de rechange ne fonctionne pas dans l'invite de commande, j'ai donc essayé le shell Git Bash et cela a fonctionné !!. L'invite de commande est capable d'exécuter toutes les commandes git telles que push, pull, etc., mais quand il s'agit d'une extraction éparse, elle échoue.
user593029
Comment faire uniquement les fichiers du sous-répertoire. Je veux uniquement récupérer les fichiers dans un sous-répertoire spécifique.
Babish Shrestha
@BabishShrestha voir le commentaire de onionjake sur une autre réponse FWIW: |
rogerdpack
9

Malheureusement, aucune de ces solutions n'a fonctionné pour moi, alors j'ai passé très longtemps à essayer différentes combinaisons de sparse-checkout fichiers.

Dans mon cas, je voulais ignorer les dossiers avec les configurations IntelliJ IDEA.

Voici ce que j'ai fait:


Courir git clone https://github.com/myaccount/myrepo.git --no-checkout

Courir git config core.sparsecheckout true

Créé .git\info\sparse-checkoutavec le contenu suivant

!.idea/*
!.idea_modules/*
/*

Exécutez 'git checkout -' pour obtenir tous les fichiers.


La chose essentielle pour le faire fonctionner était d'ajouter /* après le nom du dossier.

J'ai git 1.9

expert
la source
3
Non, il télécharge toujours tout, tous les commits et tous les fichiers, git 2.3.2
Tyguy7
6
Les extractions éparses n'affectent que l'arborescence de travail. Ils n'affectent pas la taille du référentiel ou ce qui est récupéré. Vous avez besoin de différentes options si vous le souhaitez.
Miral du
Essayez Git Bash Shell la prochaine fois si vous travaillez sous Windows et utilisez les étapes ci-dessus par 'pbetkier', cela fonctionne bien
user593029
6

Oui, possibilité de télécharger un dossier au lieu de télécharger tout le référentiel. Même tout / dernier commit

Belle façon de faire ça

D:\Lab>git svn clone https://github.com/Qamar4P/LolAdapter.git/trunk/lol-adapter -r HEAD
  1. -r HEAD téléchargera uniquement la dernière révision, ignore tout l'historique.

  2. Remarque tronc et / dossier spécifique

Copiez et modifiez l'URL avant et après /trunk/. J'espère que cela aidera quelqu'un. Prendre plaisir :)

Mis à jour le 26 sept. 2019

Qamar
la source
applicable uniquement pour ceux qui proviennent ou utilisent svn. Je ne voterai pas pour celui-ci.
C Johnson
@CJohnson comme vous pouvez le voir, je clone le dossier git repo. Fonctionnement bien
Qamar
1
Notez que ce n'est pas quelque chose que git propose hors de la boîte, mais c'est quelque chose que le hub Git offre à côté de l'offre Git standard. Cependant, cela fonctionne à merveille lorsque vous pouvez l'utiliser. Merci!
Qix - MONICA A ÉTÉ BRUYÉE
1
Parmi la myriade de suggestions sur le SO, la vôtre est la solution la plus concise et la plus claire.
boardrider
5

Réponse mise à jour 2020:

Il y a maintenant une commande git sparse-checkout, que je présente en détail avec Git 2.25 (Q1 2020)

La réponse de nicono illustre son utilisation:

git sparse-checkout init --cone # to fetch only root files
git sparse-checkout add apps/my_app
git sparse-checkout add libs/my_lib

Il a évolué avec Git 2.27 et sait comment "réappliquer" une extraction éparse, comme ici .
Notez qu'avec Git 2.28, git statusmentionnera que vous êtes dans un référentiel extrait de manière fragmentée

Réponse originale: 2016

git 2.9 (juin 2016) généralisera l' --no-checkoutoption à git worktree add(la commande qui permet de travailler avec plusieurs arbres de travail pour un dépôt )

Voir commit ef2a0ac (29 mars 2016) par Ray Zhang ( OneRaynyDay) .
Aide: Eric Sunshine ( sunshineco) et Junio ​​C Hamano ( gitster) .
(Fusionné par Junio ​​C Hamano - gitster- in commit 0d8683c , 13 avril 2016)

La git worktreepage de manuel comprend désormais:

--[no-]checkout:

Par défaut, addchèques <branch>, cependant, --no-checkoutpeuvent être utilisés à la caisse afin suppress d'effectuer les personnalisations, telles que la configuration de la caisse-clairsemée .

VonC
la source
4

Étapes à suivre pour extraire uniquement un dossier spécifique:

1) git clone --no-checkout  <project clone url>  
2) cd <project folder>
3) git config core.sparsecheckout true   [You must do this]
4) echo "<path you want to sparce>/*" > .git/info/sparse-checkout
    [You must enter /* at the end of the path such that it will take all contents of that folder]
5) git checkout <branch name> [Ex: master]
SANDEEP MACHIRAJU
la source
Pour info, dans la première (1) étape, vous n'avez pas besoin d'utiliser --no-checkout. Clonez simplement l'ensemble du dépôt, puis exécutez toutes les étapes 2 à 5 ci-dessous (mentionnées ci-dessus), vous obtiendrez le résultat souhaité. Faites-moi savoir si vous ne l'avez pas compris.
SANDEEP MACHIRAJU
4

Sur la base de cette réponse d' apenwarr et de ce commentaire de Miral, j'ai proposé la solution suivante qui m'a permis d'économiser près de 94% d'espace disque lors du clonage local du référentiel linux git tout en ne voulant qu'un sous-répertoire de documentation:

$ cd linux
$ du -sh .git .
2.1G    .git
894M    .
$ du -sh 
2.9G    .
$ mkdir ../linux-sparse-test
$ cd ../linux-sparse-test
$ git init
Initialized empty Git repository in /…/linux-sparse-test/.git/
$ git config core.sparseCheckout true
$ git remote add origin ../linux
# Parameter "origin master" saves a tiny bit if there are other branches
$ git fetch --depth=1 origin master
remote: Enumerating objects: 65839, done.
remote: Counting objects: 100% (65839/65839), done.
remote: Compressing objects: 100% (61140/61140), done.
remote: Total 65839 (delta 6202), reused 22590 (delta 3703)
Receiving objects: 100% (65839/65839), 173.09 MiB | 10.05 MiB/s, done.
Resolving deltas: 100% (6202/6202), done.
From ../linux
 * branch              master     -> FETCH_HEAD
 * [new branch]        master     -> origin/master
$ echo "Documentation/hid/*" > .git/info/sparse-checkout
$ git checkout master
Branch 'master' set up to track remote branch 'master' from 'origin'.
Already on 'master'
$ ls -l
total 4
drwxr-xr-x 3 abe abe 4096 May  3 14:12 Documentation/
$  du -sh .git .
181M    .git
100K    .
$  du -sh
182M    .

Je suis donc passé de 2,9 Go à 182 Mo, ce qui est déjà très agréable.

Je n'ai cependant pas réussi à faire fonctionner cela git clone --depth 1 --no-checkout --filter=blob:none file:///…/linux linux-sparse-test( suggéré ici ) car les fichiers manquants ont tous été ajoutés en tant que fichiers supprimés à l'index. Donc, si quelqu'un connaît l'équivalent de git clone --filter=blob:nonefor git fetch, nous pouvons probablement économiser encore plus de mégaoctets. (La lecture de la page de manuel de git-rev-listindique également qu'il existe quelque chose comme--filter=sparse:path=… , mais je n'ai pas réussi à faire fonctionner cela non plus.

(Tous ont été essayés avec git 2.20.1 de Debian Buster.)

Axel Beckert
la source
1
Commentaires intéressants. Vote positif. Je ne sais pas non --filter=sparse:path=…plus.
VonC
3

Je suis nouveau sur git mais il semble que si je fais git checkout pour chaque répertoire, cela fonctionne. En outre, le fichier d'extraction éparse doit avoir une barre oblique à la fin de chaque répertoire, comme indiqué. Quelqu'un de plus d'expérience, veuillez confirmer que cela fonctionnera.

Fait intéressant, si vous extrayez un répertoire qui ne se trouve pas dans le fichier d'extraction éparse, cela ne semble pas faire de différence. Ils n'apparaissent pas dans l'état git et git read-tree -m -u HEAD ne le supprime pas. git reset --hard n'entraîne pas non plus la suppression du répertoire. Quelqu'un de plus expérimenté voudrait commenter ce que Git pense des répertoires qui sont extraits mais qui ne sont pas dans le fichier d'extraction clairsemé?

dromodel
la source
1

Dans git 2.27, il semble que git sparse checkout ait évolué. La solution dans cette réponse ne fonctionne pas exactement de la même manière (par rapport à git 2.25)

git clone <URL> --no-checkout <directory>
cd <directory>
git sparse-checkout init --cone # to fetch only root files
git sparse-checkout set apps/my_app libs/my_lib # etc, to list sub-folders to checkout
# they are checked out immediately after this command, no need to run git pull

Ces commandes fonctionnaient mieux:

git clone --sparse <URL> <directory>
cd <directory>
git sparse-checkout init --cone # to fetch only root files
git sparse-checkout add apps/my_app
git sparse-checkout add libs/my_lib

Voir aussi: git-clone --sparse et git-sparse-checkout add

nicono
la source
1
Bonne mise à jour. Vote positif. J'ai édité ma propre réponse en conséquence. J'ai présenté cette commande en décembre 2019: stackoverflow.com/a/59515426/6309
VonC
0

Dans mon cas, je souhaite ignorer le Podsdossier lors du clonage du projet. Je l'ai fait étape par étape comme ci-dessous et cela fonctionne pour moi. J'espère que ça aide.

mkdir my_folder
cd my_folder
git init
git remote add origin -f <URL>
git config core.sparseCheckout true 
echo '!Pods/*\n/*' > .git/info/sparse-checkout
git pull origin master

Mémo, si vous voulez sauter plus de dossiers, ajoutez simplement plus de ligne dans le fichier de retrait clairsemé.

Eric long
la source