Comment cloner un sous-répertoire uniquement d'un référentiel Git?


1410

J'ai mon dépôt Git qui, à la racine, a deux sous-répertoires:

/finisht
/static

Lorsque cela était dans SVN , a /finishtété vérifié à un endroit, alors qu'il a /staticété vérifié ailleurs, comme ceci:

svn co svn+ssh://admin@domain.com/home/admin/repos/finisht/static static

Existe-t-il un moyen de le faire avec Git?



1
Pour un utilisateur de 2014, quelle est la git clonecommande la plus simple ?? J'ai utilisé cette réponse simple . S'il y a quelque chose de plus simple, veuillez commenter
Peter Krauss

Pour ceux qui essaient de cloner le contenu du référentiel (ne pas créer le dossier racine), c'est une solution très simple: stackoverflow.com/questions/6224626/...
Marc

@JoachimBreitner: Cette question concerne la vérification des sous-répertoires dans Git (ce qui est facile), alors que cette question concerne le clonage des sous-répertoires dans Git (ce qui est impossible).
Jörg W Mittag

@NickSergeant: Depuis Git 2.19, sorti il ​​y a 3 semaines, c'est enfin possible, comme on peut le voir dans cette réponse: stackoverflow.com/a/52269934/2988 Envisagez d'accepter celui-là maintenant. Remarque: dans Git 2.19, seule la prise en charge côté client est implémentée, la prise en charge côté serveur est toujours manquante, elle ne fonctionne donc que lors du clonage de référentiels locaux. Notez également que les gros hébergeurs Git, par exemple GitHub n'utilisent pas réellement le serveur Git, ils utilisent leur propre implémentation, donc même si le support apparaît sur le serveur Git, cela ne signifie pas automatiquement qu'il fonctionne sur les hébergeurs Git. (OTOH, ils pourraient l'implémenter plus rapidement.)
Jörg W Mittag

Réponses:


612

EDIT : Depuis Git 2.19, c'est enfin possible, comme on peut le voir dans cette réponse .

Pensez à voter pour cette réponse.

Remarque: dans Git 2.19, seule la prise en charge côté client est implémentée, la prise en charge côté serveur est toujours manquante, elle ne fonctionne donc que lors du clonage de référentiels locaux. Notez également que les gros hébergeurs Git, par exemple GitHub, n'utilisent pas réellement le serveur Git, ils utilisent leur propre implémentation, donc même si le support apparaît dans le serveur Git, cela ne signifie pas automatiquement qu'il fonctionne sur les hébergeurs Git. (OTOH, car ils n'utilisent pas le serveur Git, ils pourraient l'implémenter plus rapidement dans leurs propres implémentations avant qu'il n'apparaisse dans le serveur Git.)


Non, ce n'est pas possible dans Git.

Implémenter quelque chose comme ça dans Git serait un effort substantiel et cela signifierait que l'intégrité du référentiel côté client ne pourrait plus être garantie. Si vous êtes intéressé, recherchez des discussions sur "clone clairsemé" et "extraction clairsemée" sur la liste de diffusion git.

En général, le consensus dans la communauté Git est que si vous avez plusieurs répertoires qui sont toujours vérifiés indépendamment, alors ce sont vraiment deux projets différents et devraient vivre dans deux référentiels différents. Vous pouvez les coller de nouveau ensemble à l'aide des sous-modules Git .


6
Selon le scénario, vous pouvez utiliser git subtree au lieu de git submodule. Voir alumnit.ca/~apenwarr/log/?m=200904#30
C Pirate

9
@StijndeWitt: des extractions clairsemées ont lieu pendant git-read-tree, ce qui est longtemps après get-fetch. La question n'était pas de vérifier uniquement un sous-répertoire, il s'agissait de cloner uniquement un sous-répertoire. Je ne vois pas comment les extractions clairsemées pourraient éventuellement faire cela, car git-read-trees'exécute une fois le clone terminé.
Jörg W Mittag

9
Plutôt que ce "talon", aimeriez-vous que je supprime cette réponse afin que Chronial puisse flotter vers le haut? Vous ne pouvez pas le supprimer vous-même, car il est accepté, mais un modérateur le peut. Vous conserveriez la réputation que vous en avez acquise, car elle est si ancienne. (Je suis tombé sur cela parce que quelqu'un l'a signalé comme "link-only". :-)
Cody Gray

1
@CodyGray: La réponse chronale clone toujours le référentiel entier, et pas seulement un sous-répertoire. (Le dernier paragraphe le dit même explicitement.) Le clonage d'un seul sous-répertoire n'est pas possible dans Git. Le protocole réseau ne le prend pas en charge, le format de stockage ne le prend pas en charge. Chaque réponse unique à cette question clone toujours l'ensemble du référentiel. La question est une simple question Oui / Non, et la réponse est à deux caractères: Non. Si c'est le cas, ma réponse est inutilement longue , pas courte.
Jörg W Mittag

1
@ JörgWMittag: La réponse de Ciro Santili semble vous contredire.
Dan Dascalescu

1525

Ce que vous essayez de faire s'appelle une caisse creuse , et cette fonctionnalité a été ajoutée dans git 1.7.0 (février 2012). Les étapes pour faire un clone clairsemé sont les suivantes:

mkdir <repo>
cd <repo>
git init
git remote add -f origin <url>

Cela crée un référentiel vide avec votre télécommande et récupère tous les objets mais ne les extrait pas. Alors fais:

git config core.sparseCheckout true

Vous devez maintenant définir les fichiers / dossiers que vous souhaitez réellement extraire. Cela se fait en les répertoriant .git/info/sparse-checkout, par exemple:

echo "some/dir/" >> .git/info/sparse-checkout
echo "another/sub/tree" >> .git/info/sparse-checkout

Enfin, mettez à jour votre référentiel vide avec l'état de la télécommande:

git pull origin master

Vous aurez maintenant des fichiers «extraits» pour some/diret another/sub/treesur votre système de fichiers (avec ces chemins toujours), et aucun autre chemin présent.

Vous voudrez peut-être jeter un coup d'œil au didacticiel étendu et vous devriez probablement lire la documentation officielle pour un paiement clairsemé .

En tant que fonction:

function git_sparse_clone() (
  rurl="$1" localdir="$2" && shift 2

  mkdir -p "$localdir"
  cd "$localdir"

  git init
  git remote add -f origin "$rurl"

  git config core.sparseCheckout true

  # Loops over remaining args
  for i; do
    echo "$i" >> .git/info/sparse-checkout
  done

  git pull origin master
)

Usage:

git_sparse_clone "http://github.com/tj/n" "./local/location" "/bin"

Notez que cela téléchargera toujours le référentiel entier depuis le serveur - seule la caisse est réduite en taille. Pour le moment, il n'est pas possible de cloner un seul répertoire. Mais si vous n'avez pas besoin de l'historique du référentiel, vous pouvez au moins économiser de la bande passante en créant un clone peu profond. Voir la réponse d'udondan ci-dessous pour plus d'informations sur la façon de combiner un clone peu profond et un paiement clairsemé.


Depuis git 2.25.0 (janvier 2020), une commande expérimentale de vérification clairsemée est ajoutée dans git:

git sparse-checkout init
# same as: 
git config core.sparseCheckout true

git sparse-checkout set "A/B"
# same as:
echo "A/B" >> .git/info/sparse-checkout

git sparse-checkout list
# same as:
cat .git/info/sparse-checkout

14
sur Apple, le périmètre «-f» ne fonctionne pas. faites juste git remote ajoutez origin <url> sans -f
Anno2001

135
C'est une amélioration mais il faut toujours télécharger et stocker une copie complète du référentiel distant d'origine, ce que l'on voudrait éviter du tout s'il n'est intéressé que par des parties de la base de code (ou s'il y a des sous-dossiers de documentation comme dans mon cas) )
a1an

56
Existe-t-il un moyen de cloner le contenu du répertoire souhaité (pas le répertoire lui-même) directement dans mon référentiel? Par exemple, je veux cloner le contenu de https://github.com/Umkus/nginx-boilerplate/tree/master/srcdroit dans/etc/nginx
mac

25
@Chronial, @ErikE: vous avez tous les deux raison / erreur: P La git remote addcommande n'implique pas une extraction, mais git remote add -f, comme utilisée ici, oui! Voilà ce que cela -fsignifie.
ntc2

21
En utilisant cela et --depth=1j'ai cloné Chromium Devtools dans 338 Mo au lieu de 4,9 Go de source Blink complète + historique. Excellent.
Rudie

445

git clone --filter de Git 2.19

Cette option sautera en fait la récupération des objets inutiles du serveur. Incluant également --filter=tree:0Git 2.20 et le --filter=combinefiltre composite ajouté dans Git 2.24, nous nous retrouvons avec:

git clone \
  --depth 1 \
  --filter=combine:blob:none+tree:0 \
  --no-checkout \
  "file://$(pwd)/server_repo" \
  local_repo \
;
cd local_repo
git checkout master -- mydir/

Le serveur doit être configuré avec:

git config --local uploadpack.allowfilter 1
git config --local uploadpack.allowanysha1inwant 1

Une extension a été apportée au protocole distant Git pour prendre en charge cette fonctionnalité v2.19.0et ignorer la récupération d'objets inutiles, mais il n'y a pas de prise en charge de serveur pour le moment. Mais il peut déjà être testé localement.

Répartition des commandes:

Le format de --filterest documenté sur man git-rev-list.

Documents sur l'arbre Git:

Testez-le

#!/usr/bin/env bash
set -eu

list-objects() (
  git rev-list --all --objects
  echo "master commit SHA: $(git log -1 --format="%H")"
  echo "mybranch commit SHA: $(git log -1 --format="%H")"
  git ls-tree master
  git ls-tree mybranch | grep mybranch
  git ls-tree master~ | grep root
)

# Reproducibility.
export GIT_COMMITTER_NAME='a'
export GIT_COMMITTER_EMAIL='a'
export GIT_AUTHOR_NAME='a'
export GIT_AUTHOR_EMAIL='a'
export GIT_COMMITTER_DATE='2000-01-01T00:00:00+0000'
export GIT_AUTHOR_DATE='2000-01-01T00:00:00+0000'

rm -rf server_repo local_repo
mkdir server_repo
cd server_repo

# Create repo.
git init --quiet
git config --local uploadpack.allowfilter 1
git config --local uploadpack.allowanysha1inwant 1

# First commit.
# Directories present in all branches.
mkdir d1 d2
printf 'd1/a' > ./d1/a
printf 'd1/b' > ./d1/b
printf 'd2/a' > ./d2/a
printf 'd2/b' > ./d2/b
# Present only in root.
mkdir 'root'
printf 'root' > ./root/root
git add .
git commit -m 'root' --quiet

# Second commit only on master.
git rm --quiet -r ./root
mkdir 'master'
printf 'master' > ./master/master
git add .
git commit -m 'master commit' --quiet

# Second commit only on mybranch.
git checkout -b mybranch --quiet master~
git rm --quiet -r ./root
mkdir 'mybranch'
printf 'mybranch' > ./mybranch/mybranch
git add .
git commit -m 'mybranch commit' --quiet

echo "# List and identify all objects"
list-objects
echo

# Restore master.
git checkout --quiet master
cd ..

# Clone. Don't checkout for now, only .git/ dir.
git clone --depth 1 --quiet --no-checkout --filter=blob:none "file://$(pwd)/server_repo" local_repo
cd local_repo

# List missing objects from master.
echo "# Missing objects after --no-checkout"
git rev-list --all --quiet --objects --missing=print
echo

echo "# Git checkout fails without internet"
mv ../server_repo ../server_repo.off
! git checkout master
echo

echo "# Git checkout fetches the missing directory from internet"
mv ../server_repo.off ../server_repo
git checkout master -- d1/
echo

echo "# Missing objects after checking out d1"
git rev-list --all --quiet --objects --missing=print

GitHub en amont .

Sortie dans Git v2.19.0:

# List and identify all objects
c6fcdfaf2b1462f809aecdad83a186eeec00f9c1
fc5e97944480982cfc180a6d6634699921ee63ec
7251a83be9a03161acde7b71a8fda9be19f47128
62d67bce3c672fe2b9065f372726a11e57bade7e
b64bf435a3e54c5208a1b70b7bcb0fc627463a75 d1
308150e8fddde043f3dbbb8573abb6af1df96e63 d1/a
f70a17f51b7b30fec48a32e4f19ac15e261fd1a4 d1/b
84de03c312dc741d0f2a66df7b2f168d823e122a d2
0975df9b39e23c15f63db194df7f45c76528bccb d2/a
41484c13520fcbb6e7243a26fdb1fc9405c08520 d2/b
7d5230379e4652f1b1da7ed1e78e0b8253e03ba3 master
8b25206ff90e9432f6f1a8600f87a7bd695a24af master/master
ef29f15c9a7c5417944cc09711b6a9ee51b01d89
19f7a4ca4a038aff89d803f017f76d2b66063043 mybranch
1b671b190e293aa091239b8b5e8c149411d00523 mybranch/mybranch
c3760bb1a0ece87cdbaf9a563c77a45e30a4e30e
a0234da53ec608b54813b4271fbf00ba5318b99f root
93ca1422a8da0a9effc465eccbcb17e23015542d root/root
master commit SHA: fc5e97944480982cfc180a6d6634699921ee63ec
mybranch commit SHA: fc5e97944480982cfc180a6d6634699921ee63ec
040000 tree b64bf435a3e54c5208a1b70b7bcb0fc627463a75    d1
040000 tree 84de03c312dc741d0f2a66df7b2f168d823e122a    d2
040000 tree 7d5230379e4652f1b1da7ed1e78e0b8253e03ba3    master
040000 tree 19f7a4ca4a038aff89d803f017f76d2b66063043    mybranch
040000 tree a0234da53ec608b54813b4271fbf00ba5318b99f    root

# Missing objects after --no-checkout
?f70a17f51b7b30fec48a32e4f19ac15e261fd1a4
?8b25206ff90e9432f6f1a8600f87a7bd695a24af
?41484c13520fcbb6e7243a26fdb1fc9405c08520
?0975df9b39e23c15f63db194df7f45c76528bccb
?308150e8fddde043f3dbbb8573abb6af1df96e63

# Git checkout fails without internet
fatal: '/home/ciro/bak/git/test-git-web-interface/other-test-repos/partial-clone.tmp/server_repo' does not appear to be a git repository
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

# Git checkout fetches the missing directory from internet
remote: Enumerating objects: 1, done.
remote: Counting objects: 100% (1/1), done.
remote: Total 1 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (1/1), 45 bytes | 45.00 KiB/s, done.
remote: Enumerating objects: 1, done.
remote: Counting objects: 100% (1/1), done.
remote: Total 1 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (1/1), 45 bytes | 45.00 KiB/s, done.

# Missing objects after checking out d1
?8b25206ff90e9432f6f1a8600f87a7bd695a24af
?41484c13520fcbb6e7243a26fdb1fc9405c08520
?0975df9b39e23c15f63db194df7f45c76528bccb

Conclusions: tous les blobs de l'extérieur de d1/sont manquants. Par exemple 0975df9b39e23c15f63db194df7f45c76528bccb, qui n'est d2/bpas là après le départ d1/a.

Notez que root/rootet mybranch/mybranchsont également manquants, mais les --depth 1masquent dans la liste des fichiers manquants. Si vous supprimez --depth 1, ils apparaissent sur la liste des fichiers manquants.

J'ai un rêve

Cette fonctionnalité pourrait révolutionner Git.

Imaginez avoir toute la base de code de votre entreprise dans un seul référentiel sans outils tiers laids commerepo .

Imaginez que vous stockiez d'énormes blobs directement dans le référentiel sans aucune extension tierce laide .

Imaginez si GitHub autoriserait par métadonnées par fichier / répertoire comme les étoiles et les autorisations, afin que vous puissiez stocker toutes vos données personnelles sous un seul dépôt.

Imaginez si les sous - modules étaient traités exactement comme des répertoires normaux : demandez simplement un arbre SHA, et un mécanisme de type DNS résout votre demande , en regardant d'abord votre serveur local~/.git , puis d'abord vers des serveurs plus proches (miroir / cache de votre entreprise) et se retrouvant sur GitHub.


Curieusement, sur macOS avec git version 2.20.1 (Apple Git-117), il se plaint que "plusieurs spécifications de filtre ne peuvent pas être combinées"
muru

1
Malheureusement, pas de chance avec la version macOS git. fatal: invalid filter-spec 'combine:blob:none+tree:0'Merci quand même! Peut-être que cela fonctionnera avec des versions plus récentes.
muru

1
Cela échoue lorsque vous l'essayez sur Windows 10 à l'aide de GIT 2.24.1 (lance des tonnes de "impossible de lire le fichier sha1 de .." + "Échec de la dissociation du fichier xxx."). Fonctionne comme un charme avec la même version sur Linux.
Oyvind

1
@Ciro Santilli Cela échoue toujours avec "impossible de lire le fichier sha1 de ..." dans la version 2.26.1.windows.1 de git. J'ai ouvert un rapport de bug: github.com/git-for-windows/git/issues/2590
nharrer


405

Vous pouvez combiner l' extraction clairsemée et les fonctionnalités de clonage superficiel . Le clone superficiel coupe l'historique et la vérification clairsemée extrait uniquement les fichiers correspondant à vos modèles.

git init <repo>
cd <repo>
git remote add origin <url>
git config core.sparsecheckout true
echo "finisht/*" >> .git/info/sparse-checkout
git pull --depth=1 origin master

Vous aurez besoin de git 1.9 minimum pour que cela fonctionne. Je l'ai testé moi-même uniquement avec 2.2.0 et 2.2.2.

De cette façon, vous pourrez toujours pousser , ce qui n'est pas possible avec git archive.


21
C'est utile et peut être la meilleure réponse disponible, mais cela clone toujours le contenu qui ne vous intéresse pas (si c'est sur la branche que vous tirez), même s'il n'apparaît pas dans la caisse.
nobar

1
Quelle est votre version git? Selon l'aide de git, l'option de profondeur est-elle disponible?
udondan

2
ne fonctionne pas pour moi lorsque la dernière commande n'est pas git pull --depth=1 origin mastermais git pull --depth=1 origin <any-other-branch>. c'est tellement étrange, voir ma question ici: stackoverflow.com/questions/35820630/…
Shuman

5
Sous Windows, l'avant-dernière ligne doit omettre les guillemets, sinon l'extraction échoue.
nateirvin

4
Cela télécharge toujours toutes les données! Trouvé cette solution, en utilisant svn: stackoverflow.com/a/18324458/2302437
electronix384128

157

Pour les autres utilisateurs qui souhaitent simplement télécharger un fichier / dossier à partir de github, utilisez simplement:

svn export <repo>/trunk/<folder>

par exemple

svn export https://github.com/lodash/lodash.com/trunk/docs

(oui, c'est svn ici. apparemment en 2016 vous avez toujours besoin de svn pour simplement télécharger des fichiers github)

Courtoisie: télécharger un dossier ou un répertoire unique à partir d'un référentiel GitHub

Important - Assurez-vous de mettre à jour l'URL github et de le remplacer /tree/master/par '/ trunk /'.

En tant que script bash:

git-download(){
    folder=${@/tree\/master/trunk}
    folder=${folder/blob\/master/trunk}
    svn export $folder
}

Remarque Cette méthode télécharge un dossier, ne le clone pas / ne l'extrait pas. Vous ne pouvez pas repousser les modifications dans le référentiel. D'un autre côté - cela se traduit par un téléchargement plus petit par rapport à une caisse creuse ou une caisse peu profonde.


9
seule version qui a fonctionné pour moi avec github. Les commandes git ont extrait> 10k fichiers, le svn n'exporte que les 700 que je voulais. Merci!
Christopher Lörken

4
J'ai essayé de faire cela avec https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/trunk/udacitymais j'ai eu une svn: E170000: URL 'https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/trunk/udacity' doesn't existerreur :(
zthomas.nc

9
@ zthomas.nc Vous devez supprimer le 'tronc' précédant l'udacity et remplacer / tree / master / par / trunk / à la place.
Speedy

2
Cette commande a été celle qui a fonctionné pour moi! Je voulais juste obtenir une copie d'un fichier d'un dépôt afin de pouvoir le modifier localement. Bon vieux SVN à la rescousse!
Michael J

3
cela fonctionne, mais semble lent. prend un peu pour démarrer, puis les fichiers défilent relativement lentement
Aryeh Beitz

73

Si vous ne prévoyez jamais d'interagir avec le référentiel à partir duquel vous avez cloné, vous pouvez faire un clone complet de git et réécrire votre référentiel en utilisant git filter-branch --subdirectory-filter . De cette façon, au moins l'histoire sera préservée.


11
Pour les gens qui ne connaissent pas la commande, c'estgit filter-branch --subdirectory-filter <subdirectory>
Jaime Hablutzel

9
Cette méthode a l'avantage que le sous-répertoire que vous choisissez devient la racine du nouveau référentiel, qui se trouve être exactement ce que je veux.
Andrew Schulman

C'est sans aucun doute l'approche la meilleure et la plus simple à utiliser. Voici une commande en une étape utilisant un sous-répertoire-filtregit clone https://github.com/your/repo_xx.git && cd repo_xx && git filter-branch --subdirectory-filter repo_xx_subdir
Alex

66

Cela semble beaucoup plus simple:

git archive --remote=<repo_url> <branch> <path> | tar xvf -

17
Lorsque je fais cela sur github, je suis fatal: opération non prise en charge par le protocole. Fin inattendue du flux de commandes
Michael Fox

1
L'erreur de protocole peut être due à HTTPS ou à: dans l'URL du dépôt. Cela pourrait également être dû à la clé ssh manquante.
Umair A.

2
Si vous utilisez github, vous pouvez utiliser à la svn exportplace
Milo Wielondek

2
Ne fonctionnera pas avec Github -> Commande non valide: 'git-upload-archive' xxx / yyy.git '' Vous semblez utiliser ssh pour cloner une URL git: //. Assurez-vous que votre option de configuration core.gitProxy et la variable d'environnement GIT_PROXY_COMMAND ne sont PAS définies. fatal: L'extrémité éloignée a raccroché de façon inattendue
Nianliang

3
La raison pour laquelle cela ne fonctionne pas avec GitHub: "Nous ne prenons pas en charge l'utilisation de git-archive pour extraire une archive directement à partir de GitHub. Vous pouvez soit cloner le dépôt localement et exécuter git-archive, soit cliquer sur le bouton Télécharger ZIP sur la page de repo. " github.com/xuwupeng2000/capistrano-scm-gitcopy/issues/16
Donn Lee

63

Git 1.7.0 a des «caisses clairsemées». Voir «core.sparseCheckout» dans la page de manuel de git config , «Sparse checkout» dans la page de manuel de git read-tree et «Skip-worktree bit» dans la page de manuel de git update-index .

L'interface n'est pas aussi pratique que celle de SVN (par exemple, il n'y a aucun moyen d'effectuer une extraction clairsemée au moment d'un clone initial), mais la fonctionnalité de base sur laquelle des interfaces plus simples pourraient être construites est maintenant disponible.


37

Il n'est pas possible de cloner un sous-répertoire uniquement avec Git, mais voici quelques solutions de contournement.

Branche de filtre

Vous voudrez peut-être réécrire le référentiel pour qu'il ressemble à trunk/public_html/sa racine de projet et supprimer tous les autres historiques (en utilisant filter-branch), essayez déjà la branche de paiement:

git filter-branch --subdirectory-filter trunk/public_html -- --all

Remarques: le --qui sépare les options de branche de filtre des options de révision et le --allpour réécrire toutes les branches et balises. Toutes les informations, y compris les heures de validation d'origine ou les informations de fusion, seront conservées . Cette commande honore le .git/info/graftsfichier et les références dans l' refs/replace/espace de noms, donc si vous avez refsdéfini des greffons ou des remplacements , l'exécution de cette commande les rendra permanents.

Attention! L'historique réécrit aura des noms d'objet différents pour tous les objets et ne convergera pas avec la branche d'origine. Vous ne pourrez pas facilement pousser et distribuer la branche réécrite au-dessus de la branche d'origine. Veuillez ne pas utiliser cette commande si vous ne connaissez pas toutes les implications et évitez de l'utiliser de toute façon, si une simple validation suffit pour résoudre votre problème.


Caisse clairsemée

Voici des étapes simples avec une approche de vérification clairsemée qui remplira le répertoire de travail de manière clairsemée, de sorte que vous pouvez dire à Git quel (s) dossier (s) ou fichier (s) du répertoire de travail mérite d'être vérifié.

  1. Clonez le dépôt comme d'habitude ( --no-checkoutest facultatif):

    git clone --no-checkout git@foo/bar.git
    cd bar
    

    Vous pouvez ignorer cette étape si votre référentiel est déjà cloné.

    Astuce: pour les grands dépôts, considérez clone ( --depth 1) superficiel pour extraire uniquement la dernière révision ou / et --single-branchuniquement.

  2. Activer l' sparseCheckoutoption:

    git config core.sparseCheckout true
    
  3. Spécifiez le (s) dossier (s) pour une extraction clairsemée ( sans espace à la fin):

    echo "trunk/public_html/*"> .git/info/sparse-checkout
    

    ou modifier .git/info/sparse-checkout.

  4. Commander la succursale (par exemple master):

    git checkout master
    

Vous devriez maintenant avoir sélectionné des dossiers dans votre répertoire actuel.

Vous pouvez envisager des liens symboliques si vous avez trop de niveaux de répertoires ou de branche de filtrage à la place.



Est-ce que la branche Filtrer vous le permettrait encore pull?
sam

2
@sam: non. filter-branchréécrirait les validations parentes afin qu'elles aient des ID SHA1 différents, et donc votre arborescence filtrée n'aurait aucune validation en commun avec l'arborescence distante. git pullne saurait d'où essayer de fusionner.
Peter Cordes

Cette approche est surtout une réponse satisfaisante à mon cas.
Abbas

10

Je viens d' écrire un script pour GitHub .

Usage:

python get_git_sub_dir.py path/to/sub/dir <RECURSIVE>

11
Pour info, c'est uniquement pour GitHub .
Sz.

9
Et apparemment, c'est pour télécharger un répertoire, pas pour cloner un morceau d'un dépôt avec toutes ses métadonnées ... non?
LarsH

5
Vous devez inclure votre code ici et pas ailleurs.
2018 à 7h13

urllib2.HTTPError: Erreur HTTP 403: limite de débit dépassée
diyisme

9

Cela clonera un dossier spécifique et supprimera tout l'historique qui ne lui est pas lié.

git clone --single-branch -b {branch} git@github.com:{user}/{repo}.git
git filter-branch --subdirectory-filter {path/to/folder} HEAD
git remote remove origin
git remote add origin git@github.com:{user}/{new-repo}.git
git push -u origin master

Voilà des dragons. Vous êtes accueilli par AVERTISSEMENT: git-filtre branche a une surabondance de gotchas générant réécritures de l' histoire .. mutilées . Ensuite, les documents git-filter-branch ont une liste d'avertissement assez longue.
Oyvind

6

Voici un script shell que j'ai écrit pour le cas d'utilisation d'une extraction fragmentaire d'un seul sous-répertoire

coSubDir.sh

localRepo=$1
remoteRepo=$2
subDir=$3


# Create local repository for subdirectory checkout, make it hidden to avoid having to drill down to the subfolder
mkdir ./.$localRepo
cd ./.$localRepo
git init
git remote add -f origin $remoteRepo
git config core.sparseCheckout true

# Add the subdirectory of interest to the sparse checkout.
echo $subDir >> .git/info/sparse-checkout

git pull origin master

# Create convenience symlink to the subdirectory of interest
cd ..
ln -s ./.$localRepo/$subDir $localRepo

2
Beau script, seul le lien symbolique devrait être corrigé, devrait être à la ln -s ./.$localRepo/$subDir $localRepoplace deln -s ./.$localRepo$subDir $localRepo
valentin_nasta

2

J'ai écrit un .gitconfig [alias]pour effectuer une "caisse clairsemée". Vérifiez-le (sans jeu de mots):

Sous Windows, exécutez cmd.exe

git config --global alias.sparse-checkout "!f(){ [ $# -eq 2 ] && L=${1##*/} L=${L%.git} || L=$2; mkdir -p \"$L/.git/info\" && cd \"$L\" && git init --template= && git remote add origin \"$1\" && git config core.sparseCheckout 1; [ $# -eq 2 ] && echo \"$2\" >> .git/info/sparse-checkout || { shift 2; for i; do echo $i >> .git/info/sparse-checkout; done }; git pull --depth 1 origin master;};f"

Autrement:

git config --global alias.sparse-checkout '!f(){ [ $# -eq 2 ] && L=${1##*/} L=${L%.git} || L=$2; mkdir -p "$L/.git/info" && cd "$L" && git init --template= && git remote add origin "$1" && git config core.sparseCheckout 1; [ $# -eq 2 ] && echo "$2" >> .git/info/sparse-checkout || { shift 2; for i; do echo $i >> .git/info/sparse-checkout; done }; git pull --depth 1 origin master;};f'

Utilisation :

# Makes a directory ForStackExchange with Plug checked out
git sparse-checkout https://github.com/YenForYang/ForStackExchange Plug

# To do more than 1 directory, you have to specify the local directory:
git sparse-checkout https://github.com/YenForYang/ForStackExchange ForStackExchange Plug Folder

Les git configcommandes sont «minifiées» pour plus de commodité et de stockage, mais voici l'alias développé:

# Note the --template= is for disabling templates.
# Feel free to remove it if you don't have issues with them (like I did)
# `mkdir` makes the .git/info directory ahead of time, as I've found it missing sometimes for some reason
f(){
    [ "$#" -eq 2 ] && L="${1##*/}" L=${L%.git} || L=$2;
    mkdir -p "$L/.git/info"
        && cd "$L"
        && git init --template=
        && git remote add origin "$1"
        && git config core.sparseCheckout 1;
    [ "$#" -eq 2 ]
        && echo "$2" >> .git/info/sparse-checkout
        || {
            shift 2;
            for i; do
                echo $i >> .git/info/sparse-checkout;
            done
        };
    git pull --depth 1 origin master;
};
f

Pourquoi ça marche L=${1##*/} L=${L%.git}:? L'espace est-il un opérateur?
Gulzt

2

Vous utilisez Linux? Et vous voulez seulement un arbre de travail facile d'accès et propre? sans déranger le reste du code sur votre machine. essayez les liens symboliques !

git clone https://github.com:{user}/{repo}.git ~/my-project
ln -s ~/my-project/my-subfolder ~/Desktop/my-subfolder

Tester

cd ~/Desktop/my-subfolder
git status

1

Juste pour clarifier certaines des bonnes réponses ici, les étapes décrites dans de nombreuses réponses supposent que vous avez déjà un référentiel distant quelque part.

Éléments fournis: un référentiel git existant, par exemple git@github.com:some-user/full-repo.git, avec un ou plusieurs répertoires que vous souhaitez extraire indépendamment du reste du référentiel, par exemple les répertoires nommés app1etapp2

En supposant que vous ayez un dépôt git comme ci-dessus ...

Ensuite: vous pouvez exécuter des étapes comme les suivantes pour extraire uniquement des répertoires spécifiques de ce référentiel plus important:

mkdir app1
cd app1
git init
git remote add origin git@github.com:some-user/full-repo.git
git config core.sparsecheckout true
echo "app1/" >> .git/info/sparse-checkout
git pull origin master

Je pensais à tort que les options de caisse clairsemée devaient être définies sur le référentiel d'origine: ce n'est pas le cas. Vous définissez les répertoires que vous souhaitez localement, avant de tirer de la télécommande. J'espère que cette clarification aide quelqu'un d'autre.


0

Bien que je déteste avoir à utiliser svn pour traiter avec git repos: / je l'utilise tout le temps;

function git-scp() (
  URL="$1" && shift 1
  svn export ${URL/blob\/master/trunk}
)

Cela vous permet de copier à partir de l'url de github sans modification. Usage;

--- /tmp » git-scp https://github.com/dgraph-io/dgraph/blob/master/contrib/config/kubernetes/helm                                                                                                                  1 ↵
A    helm
A    helm/Chart.yaml
A    helm/README.md
A    helm/values.yaml
Exported revision 6367.

--- /tmp » ls | grep helm
Permissions Size User    Date Modified    Name
drwxr-xr-x     - anthony 2020-01-07 15:53 helm/

0

Si vous n'êtes réellement intéressé que par les derniers fichiers de révision d'un répertoire, Github vous permet de télécharger un référentiel en tant que fichier Zip, qui ne contient pas d'historique. Le téléchargement est donc beaucoup plus rapide.


0

J'ai donc tout essayé dans cette bande de roulement et rien n'a fonctionné pour moi ... Il s'avère que sur la version 2.24 de Git (celle qui est livrée avec cpanel au moment de cette réponse), vous n'avez pas besoin de le faire

echo "wpm/*" >> .git/info/sparse-checkout

tout ce dont vous avez besoin est le nom du dossier

wpm/*

Donc en bref vous faites ça

git config core.sparsecheckout true

vous modifiez ensuite le .git / info / sparse-checkout et ajoutez les noms de dossier (un par ligne) avec / * à la fin pour obtenir les sous-dossiers et les fichiers

wpm/*

Enregistrez et exécutez la commande d'extraction

git checkout master

Le résultat était le dossier attendu de mon dépôt et rien d'autre Upvote si cela fonctionnait pour vous

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.