Come posso clonare una sottodirectory solo di un repository Git?


1410

Ho il mio repository Git che, alla radice, ha due sottodirectory:

/finisht
/static

Quando questo era in SVN , è /finishtstato estratto in un posto, mentre è /staticstato verificato altrove, in questo modo:

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

C'è un modo per farlo con Git?



1
Per un utente del 2014, qual è il git clonecomando più semplice ?? Ho usato questa semplice risposta . Se c'è qualcosa di più semplice, per favore commenta
Peter Krauss,

Per coloro che cercano di clonare il contenuto del repository (senza creare la cartella principale), questa è una soluzione molto semplice: stackoverflow.com/questions/6224626/…
Marc

@JoachimBreitner: Questa domanda riguarda il controllo delle sottodirectory in Git (che è facile), mentre questa domanda riguarda la clonazione delle sottodirectory in Git (che è impossibile).
Jörg W Mittag,

@NickSergeant: A partire da Git 2.19, rilasciato 3 settimane fa, questo è finalmente possibile, come si può vedere in questa risposta: stackoverflow.com/a/52269934/2988 Considerare di accettarlo ora. Nota: in Git 2.19 è implementato solo il supporto lato client, manca ancora il supporto lato server, quindi funziona solo quando si clonano repository locali. Si noti inoltre che i grandi hoster Git, ad esempio GitHub, in realtà non usano il server Git, usano la propria implementazione, quindi anche se il supporto viene visualizzato nel server Git, ciò non significa automaticamente che funzioni sugli hoster Git. (OTOH, potrebbero implementarlo più velocemente.)
Jörg W Mittag

Risposte:


612

EDIT : A partire da Git 2.19, questo è finalmente possibile, come si può vedere in questa risposta .

Valuta la possibilità di votare quella risposta.

Nota: in Git 2.19 è implementato solo il supporto lato client, manca ancora il supporto lato server, quindi funziona solo quando si clonano repository locali. Si noti inoltre che i grandi hoster Git, ad esempio GitHub, in realtà non usano il server Git, usano la propria implementazione, quindi anche se il supporto viene mostrato nel server Git, ciò non significa automaticamente che funzioni sugli hoster Git. (OTOH, poiché non usano il server Git, potrebbero implementarlo più velocemente nelle proprie implementazioni prima che venga visualizzato nel server Git.)


No, non è possibile in Git.

L'implementazione di qualcosa del genere in Git sarebbe uno sforzo sostanziale e significherebbe che l'integrità del repository sul lato client non può più essere garantita. Se sei interessato, cerca discussioni su "sparse clone" e "sparse fetch" nella mailing list di git.

In generale, il consenso nella comunità Git è che se hai diverse directory che vengono sempre estratte in modo indipendente, allora si tratta in realtà di due progetti diversi e dovrebbero vivere in due diversi repository. Puoi incollarli di nuovo insieme usando i sottomoduli Git .


6
A seconda dello scenario, potresti voler usare git subtree invece di git submodule. Vedi alumnit.ca/~apenwarr/log/?m=200904#30
C Pirate

9
@StijndeWitt: checkout sparsi si verificano durante git-read-tree, che è molto tempo dopo get-fetch. La domanda non riguardava il controllo solo di una sottodirectory, si trattava di clonare solo una sottodirectory. Non vedo come checkout sparsi potrebbero farlo, dato che git-read-treeviene eseguito dopo che il clone è già stato completato.
Jörg W Mittag,

9
Piuttosto che questo "stub", vorresti che cancellassi questa risposta in modo che Chronial potesse fluttuare in cima? Non puoi eliminarlo da solo, perché è accettato, ma un moderatore può farlo. Manterresti la reputazione che ti sei guadagnato, dal momento che è così vecchio. (Mi sono imbattuto in questo perché qualcuno lo ha contrassegnato come "solo collegamento". :-)
Cody Gray

1
@CodyGray: la risposta cronologica clona ancora l'intero repository e non solo una sottodirectory. (L'ultimo paragrafo lo dice anche esplicitamente.) Clonare solo una sottodirectory non è possibile in Git. Il protocollo di rete non lo supporta, il formato di archiviazione non lo supporta. Ogni singola risposta a questa domanda clona sempre l'intero repository. La domanda è una semplice domanda Sì / No, e la risposta è di due caratteri: No. Se mai , la mia risposta è inutilmente lunga , non breve.
Jörg W Mittag,

1
@JörgWMittag: la risposta di Ciro Santili sembra contraddirti.
Dan Dascalescu,

1525

Quello che stai cercando di fare è chiamato checkout sparse , e quella funzionalità è stata aggiunta in git 1.7.0 (febbraio 2012). I passaggi per eseguire un clone rado sono i seguenti:

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

Questo crea un repository vuoto con il telecomando e recupera tutti gli oggetti ma non li controlla. Quindi fa:

git config core.sparseCheckout true

Ora devi definire quali file / cartelle vuoi effettivamente estrarre. Questo viene fatto elencandoli in .git/info/sparse-checkout, ad esempio:

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

Ultimo ma non meno importante, aggiorna il tuo repository vuoto con lo stato dal telecomando:

git pull origin master

Ora avrai i file "estratti" per some/dire another/sub/treesul tuo file system (con quei percorsi ancora) e nessun altro percorso presente.

Potresti dare un'occhiata al tutorial esteso e probabilmente dovresti leggere la documentazione ufficiale per il checkout scarso .

Come una funzione:

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
)

Uso:

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

Si noti che questo scaricherà comunque l'intero repository dal server - solo il checkout è di dimensioni ridotte. Al momento non è possibile clonare solo una singola directory. Ma se non hai bisogno della cronologia del repository, puoi almeno risparmiare sulla larghezza di banda creando un clone superficiale. Vedi la risposta di udondan di seguito per informazioni su come combinare il clone superficiale e il checkout sparse.


A partire da git 2.25.0 (gennaio 2020) in git è stato aggiunto un comando sperimentale di checkout sparse :

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
su Apple il perimetro '-f' non funziona. basta fare git remote aggiungi origin <url> senza -f
Anno2001,

135
È un miglioramento, ma deve comunque scaricare e archiviare una copia completa del repository remoto in origine, cosa che si potrebbe desiderare di evitare se è interessato solo a parti della base di codice (o se ci sono sottocartelle di documentazione come nel mio caso )
a1,

56
C'è un modo per clonare il contenuto della directory desiderata (non la directory stessa) direttamente nel mio repository? Ad esempio, voglio clonare i contenuti di https://github.com/Umkus/nginx-boilerplate/tree/master/srcright in/etc/nginx
mac

25
@Chronial, @ErikE: hai ragione / torto: P Il git remote addcomando non implica un recupero, ma git remote add -f, come usato qui, lo fa! Questo è ciò che -fsignifica.
ntc2,

21
Usando questo e --depth=1ho clonato Chromium Devtools in 338 MB invece di 4,9 GB di sorgente Blink completa + cronologia. Eccellente.
Rudie,

444

git clone --filter da Git 2.19

Questa opzione salterà effettivamente il recupero di oggetti non necessari dal server. Includendo anche --filter=tree:0da Git 2.20 e il --filter=combinefiltro composito aggiunto in Git 2.24, finiamo con:

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/

Il server deve essere configurato con:

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

È stata creata un'estensione al protocollo remoto Git per supportare questa funzione v2.19.0e in realtà saltare il recupero di oggetti non necessari, ma al momento non è disponibile alcun supporto server. Ma può già essere testato localmente.

Ripartizione del comando:

Il formato di --filterè documentato su man git-rev-list.

Documenti sull'albero Git:

Provalo

#!/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 a monte .

Uscita in 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

Conclusioni: d1/mancano tutte le macchie dall'esterno . Ad esempio 0975df9b39e23c15f63db194df7f45c76528bccb, che d2/bnon è presente dopo il check-out d1/a.

Si noti che root/roote mybranch/mybranchmancano anche, ma lo --depth 1nasconde dall'elenco dei file mancanti. Se rimuovi --depth 1, verranno visualizzati nell'elenco dei file mancanti.

ho un sogno

Questa funzione potrebbe rivoluzionare Git.

Immagina di avere tutta la base di codice della tua azienda in un singolo repository senza brutti strumenti di terze parti comerepo .

Immagina di archiviare enormi BLOB direttamente nel repository senza brutte estensioni di terze parti .

Immagina se GitHub consentirebbe metadati per file / directory come stelle e autorizzazioni, in modo da poter archiviare tutte le tue cose personali in un unico repository.

Immagina se i sottomoduli sono stati trattati esattamente come le normali directory : basta richiedere un albero SHA e un meccanismo simile a DNS risolve la tua richiesta , cercando prima il tuo locale~/.git , poi prima i server più vicini (mirror / cache della tua azienda) e finendo su GitHub.


Stranamente, su macOS con git versione 2.20.1 (Apple Git-117), si lamenta che "non è possibile combinare più specifiche di filtro"
muru,

1
Purtroppo, nessuna fortuna con la versione macOS git. fatal: invalid filter-spec 'combine:blob:none+tree:0'Grazie comunque! Forse funzionerà con le versioni più recenti.
Muru

1
Questo fallisce quando lo provi su Windows 10 usando GIT 2.24.1 (genera tonnellate di "impossibile leggere il file sha1 di .." + "Scollegamento del file xxx fallito."). Ha funzionato come un incantesimo con la stessa versione su Linux.
Oyvind

1
@Ciro Santilli Questo non riesce ancora con "impossibile leggere il file sha1 di ..." nella versione 2.26.1.windows.1 di git. Ho aperto una segnalazione di bug: github.com/git-for-windows/git/issues/2590
nharrer

1
@nharrer grazie per le informazioni!
Ciro Santilli 18 冠状 病 六四 事件 法轮功

405

È possibile combinare il checkout sparse e il funzionalità di clonazione superficiale . Il clone superficiale interrompe la cronologia e il checkout sparso estrae solo i file corrispondenti ai tuoi schemi.

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

Avrai bisogno di git minimo 1.9 per farlo funzionare. Provato io stesso solo con 2.2.0 e 2.2.2.

In questo modo sarai ancora in grado di spingere , cosa impossibile con git archive.


21
Questo è utile e può essere la migliore risposta disponibile, ma clona comunque il contenuto che non ti interessa (se è sul ramo che tiri), anche se non viene visualizzato nel checkout.
nobar,

1
Qual è la tua versione di git? Secondo git help è disponibile l'opzione di profondità?
udondan,

2
non funziona per me quando l'ultimo comando non è git pull --depth=1 origin masterma git pull --depth=1 origin <any-other-branch>. è così strano, vedi la mia domanda qui :stackoverflow.com/questions/35820630/…
Shuman

5
Su Windows, la penultima riga deve omettere le virgolette oppure il pull non riesce.
nateirvin,

4
Questo scarica ancora tutti i dati! Trovato questa soluzione, usando svn: stackoverflow.com/a/18324458/2302437
electronix384128

157

Per gli altri utenti che desiderano semplicemente scaricare un file / una cartella da github, utilizzare semplicemente:

svn export <repo>/trunk/<folder>

per esempio

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

(sì, è svn qui. Apparentemente nel 2016 hai ancora bisogno di svn per scaricare semplicemente alcuni file github)

Per gentile concessione: scarica una singola cartella o directory da un repository GitHub

Importante : assicurati di aggiornare l'URL github e sostituirlo/tree/master/ con '/ trunk /'.

Come script bash:

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

Nota Questo metodo scarica una cartella, non la clona / verifica. Non è possibile rinviare le modifiche al repository. D'altra parte, ciò si traduce in un download più piccolo rispetto al checkout scarso o al checkout superficiale.


9
unica versione che ha funzionato per me con github. I comandi git hanno estratto> 10k file, lo svn esporta solo i 700 che volevo. Grazie!
Christopher Lörken,

4
https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/trunk/udacitysvn: E170000: URL 'https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/trunk/udacity' doesn't exist
Ho

9
@ zthomas.nc È necessario rimuovere il 'trunk' che precede udacity e sostituire / tree / master / con / trunk /.
Speedy

2
Questo comando è stato quello che ha funzionato per me! Volevo solo ottenere una copia di un file da un repository in modo da poterlo modificare localmente. Buon vecchio SVN in soccorso!
Michael J,

3
funziona, ma sembra lento. ci vuole un po 'per iniziare e poi i file passano relativamente lentamente
Aryeh Beitz il

73

Se non prevedi mai di interagire con il repository da cui hai clonato, puoi fare un clone git completo e riscrivere il tuo repository usando git filter-branch --subdirectory-filter . In questo modo, almeno la storia sarà preservata.


11
Per le persone che non conoscono il comando, lo ègit filter-branch --subdirectory-filter <subdirectory>
Jaime Hablutzel,

9
Questo metodo ha il vantaggio che la sottodirectory scelta diventa la radice del nuovo repository, che sembra essere esattamente quello che voglio.
Andrew Schulman,

Questo è sicuramente l'approccio migliore e più semplice da usare. Ecco un comando in un passaggio che utilizza il filtro della sottodirectorygit clone https://github.com/your/repo_xx.git && cd repo_xx && git filter-branch --subdirectory-filter repo_xx_subdir
Alex

66

Questo sembra molto più semplice:

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

17
Quando lo faccio su github, divento fatale: operazione non supportata dal protocollo. Fine imprevista del flusso di comandi
Michael Fox,

1
L'errore del protocollo potrebbe essere dovuto a HTTPS o: nell'URL repo. Potrebbe anche essere a causa della mancanza del tasto SSH.
Umair A.

2
Se stai usando github puoi svn exportinvece usare
Milo Wielondek il

2
Non funzionerà con Github -> Comando non valido: 'git-upload-archive' xxx / yyy.git '' Sembra che tu stia usando ssh per clonare un git: // URL. Assicurati che l'opzione di configurazione core.gitProxy e la variabile di ambiente GIT_PROXY_COMMAND NON siano impostate. fatale: l'estremità remota riattaccò inaspettatamente
Nianliang il

3
Il motivo per cui questo non funziona con GitHub: "Non supportiamo l'utilizzo di git-archive per estrarre un archivio direttamente da GitHub. Puoi clonare il repository localmente ed eseguire git-archive oppure fare clic sul pulsante Scarica ZIP su la pagina repo ". github.com/xuwupeng2000/capistrano-scm-gitcopy/issues/16
Donn Lee

63

Git 1.7.0 ha "checkout sparsi". Vedi “core.sparseCheckout” nella manpage git config , “Sparse checkout” nella manpage git read-tree e “Skip-worktree bit” nella manpage git update-index .

L'interfaccia non è conveniente come quella di SVN (ad es. Non è possibile effettuare un checkout sparso al momento di un clone iniziale), ma ora sono disponibili le funzionalità di base su cui è possibile costruire interfacce più semplici.


37

Non è possibile clonare la sottodirectory solo con Git, ma di seguito sono riportate alcune soluzioni alternative.

Filiale del filtro

Potresti voler riscrivere il repository per apparire come se trunk/public_html/fosse stato il suo root di progetto, e scartare tutta la cronologia (usando filter-branch), provare sul ramo di checkout già:

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

Note: il --che separa le opzioni di filtro-ramo dalle opzioni di revisione e il --allper riscrivere tutti i rami e tag. Tutte le informazioni, inclusi i tempi di commit originali o le informazioni di unione, verranno conservate . Questo comando onora il .git/info/graftsfile e i riferimenti nello refs/replace/spazio dei nomi, quindi se hai refsdefinito innesti o sostituzioni , l'esecuzione di questo comando li renderà permanenti.

Avvertimento! La cronologia riscritta avrà nomi di oggetti diversi per tutti gli oggetti e non convergeranno con il ramo originale. Non sarà possibile spingere e distribuire facilmente il ramo riscritto sopra il ramo originale. Si prega di non utilizzare questo comando se non si conoscono le implicazioni complete ed evitare comunque di usarlo, se fosse sufficiente un singolo commit per risolvere il problema.


Cassa sparsa

Ecco alcuni semplici passaggi con un approccio di checkout sparso che popolerà scarsamente la directory di lavoro, quindi puoi dire a Git quali cartelle o file nella directory di lavoro meritano di essere verificati.

  1. Clona repository come al solito ( --no-checkoutè facoltativo):

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

    Puoi saltare questo passaggio, se il tuo repository è già stato clonato.

    Suggerimento: per repository di grandi dimensioni, prendere in considerazione shallow clone ( --depth 1) per verificare solo l'ultima revisione o / e --single-branchsolo.

  2. Abilita sparseCheckoutopzione:

    git config core.sparseCheckout true
    
  3. Specifica le cartelle per il checkout sparse ( senza spazio alla fine):

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

    o modifica .git/info/sparse-checkout.

  4. Verifica la filiale (ad es. master):

    git checkout master
    

Ora dovresti aver selezionato le cartelle nella tua directory corrente.

Puoi prendere in considerazione collegamenti simbolici se hai troppi livelli di directory o rami di filtro.



Sarebbe ramo Filtro ancora ti permettono di pull?
Sam,

2
@sam: no. filter-branchriscriverebbe i commit dei genitori in modo che avessero ID SHA1 diversi, e quindi l'albero filtrato non avrebbe alcun commit in comune con l'albero remoto. git pullnon saprei dove provare a fondermi.
Peter Cordes,

Questo approccio è per lo più una risposta soddisfacente al mio caso.
Abbas,

10

Ho appena scritto una sceneggiatura per GitHub .

Uso:

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

11
Cordiali saluti, questo è solo per GitHub .
Sz.

9
E apparentemente questo serve per scaricare una directory, non clonare un pezzo di un repository con tutti i suoi metadati ... giusto?
LarsH,

5
Dovresti includere il tuo codice qui e non altrove.
gennaio

urllib2.HTTPError: errore HTTP 403: limite di velocità superato
diyismo

9

Questo clonerà una cartella specifica e rimuoverà tutta la cronologia non correlata ad essa.

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

Ecco i draghi. Vieni accolto da AVVISO: git-filter-branch ha un eccesso di gotcha che generano riscritture della storia alterate . Quindi i documenti git-filter-branch hanno un elenco di avvisi piuttosto lungo.
Oyvind

6

Ecco uno script di shell che ho scritto per il caso d'uso di una singola sottodirectory checkout sparse

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
Lo script carino, solo qualcosa che dovrebbe essere corretto è il link simbolico, dovrebbe essere ln -s ./.$localRepo/$subDir $localRepoinvece diln -s ./.$localRepo$subDir $localRepo
valentin_nasta

2

Ho scritto a .gitconfig [alias] per aver eseguito un "checkout sparse". Dai un'occhiata (nessun gioco di parole previsto):

Su Windows, esegui 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"

Altrimenti:

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'

Utilizzo :

# 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

I git configcomandi sono "minimizzati" per praticità e memorizzazione, ma qui è espanso l'alias:

# 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

Perché funziona L=${1##*/} L=${L%.git}:? Lo spazio è un operatore?
Gulzt,

2

Usando Linux? E vuoi solo accedere facilmente e pulire l'albero di lavoro? senza disturbare il resto del codice sulla tua macchina. prova i symlink !

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

Test

cd ~/Desktop/my-subfolder
git status

1

Solo per chiarire alcune delle grandi risposte qui, i passaggi descritti in molte delle risposte presuppongono che tu abbia già un repository remoto da qualche parte.

Dato: un repository git esistente, ad esempio git@github.com:some-user/full-repo.git, con una o più directory che si desidera estrarre indipendentemente dal resto del repository, ad esempio directory denominate app1eapp2

Supponendo di avere un repository git come sopra ...

Quindi: è possibile eseguire passaggi come i seguenti per estrarre solo directory specifiche da quel repository più grande:

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

Ho erroneamente pensato che le opzioni di check-sparse dovessero essere impostate sul repository originale: non è così. Definisci le directory che desideri localmente, prima di estrarre dal telecomando. Spero che questo chiarimento aiuti qualcun altro.


0

Mentre odio dover usare svn quando ho a che fare con i repository git: / lo uso sempre;

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

Ciò consente di copiare dall'URL di Github senza modifiche. Uso;

--- /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

Se sei davvero interessato agli ultimi file di revisione di una directory, Github ti consente di scaricare un repository come file Zip, che non contiene cronologia. Quindi il download è molto più veloce.


0

Quindi ho provato di tutto in questo battistrada e niente ha funzionato per me ... Risulta che sulla versione 2.24 di Git (quella che viene fornita con cpanel al momento di questa risposta), non è necessario farlo

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

tutto ciò che serve è il nome della cartella

wpm/*

Quindi in breve lo fai

git config core.sparsecheckout true

quindi modifica il file .git / info / sparse-checkout e aggiungi i nomi delle cartelle (uno per riga) con / * alla fine per ottenere sottocartelle e file

wpm/*

Salvare ed eseguire il comando di pagamento

git checkout master

Il risultato è stato la cartella prevista dal mio repository e nient'altro Upvote se questo ha funzionato per te

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.