¿Cómo clono un subdirectorio solo de un repositorio Git?

1410

Tengo mi repositorio Git que, en la raíz, tiene dos subdirectorios:

/finisht
/static

Cuando esto estaba en SVN , /finishtse desprotegió en un lugar, mientras /staticse desprotegió en otro lugar, así:

svn co svn+ssh://[email protected]/home/admin/repos/finisht/static static

¿Hay alguna manera de hacer esto con Git?

Nick Sergeant
fuente
14
posible duplicado de subdirectorios
Joachim Breitner
1
Para un usuario de 2014, ¿cuál es el git clonecomando más simple? Usé esta respuesta simple . Si hay algo más simple, por favor comente
Peter Krauss
Para aquellos que intentan clonar el contenido del repositorio (sin crear la carpeta raíz), esta es una solución muy fácil: stackoverflow.com/questions/6224626/…
Marc
@JoachimBreitner: Esa pregunta se trata de verificar subdirectorios en Git (que es fácil), mientras que esta pregunta se trata de clonar subdirectorios en Git (que es imposible).
Jörg W Mittag el
@NickSergeant: a partir de Git 2.19, lanzado hace 3 semanas, esto finalmente es posible, como se puede ver en esta respuesta: stackoverflow.com/a/52269934/2988 Considere aceptar esa ahora. Nota: en Git 2.19, solo se implementa el soporte del lado del cliente, todavía falta el soporte del lado del servidor, por lo que solo funciona al clonar repositorios locales. También tenga en cuenta que los grandes servidores Git, por ejemplo, GitHub en realidad no usan el servidor Git, sino que usan su propia implementación, por lo que incluso si el soporte aparece en el servidor Git, no significa automáticamente que funcione en los servidores Git. (OTOH, podrían implementarlo más rápido.)
Jörg W Mittag el

Respuestas:

612

EDITAR : a partir de Git 2.19, esto finalmente es posible, como se puede ver en esta respuesta .

Considere votar esa respuesta.

Nota: en Git 2.19, solo se implementa el soporte del lado del cliente, todavía falta el soporte del lado del servidor, por lo que solo funciona al clonar repositorios locales. También tenga en cuenta que los servidores Git grandes, por ejemplo, GitHub, en realidad no usan el servidor Git, sino que usan su propia implementación, por lo que incluso si el soporte aparece en el servidor Git, no significa automáticamente que funcione en los servidores Git. (OTOH, dado que no usan el servidor Git, podrían implementarlo más rápido en sus propias implementaciones antes de que aparezca en el servidor Git).


No, eso no es posible en Git.

Implementar algo como esto en Git sería un esfuerzo sustancial y significaría que la integridad del repositorio del cliente ya no podría garantizarse. Si está interesado, busque discusiones sobre "clon disperso" y "búsqueda dispersa" en la lista de correo de git.

En general, el consenso en la comunidad Git es que si tiene varios directorios que siempre se verifican de forma independiente, entonces estos son realmente dos proyectos diferentes y deberían vivir en dos repositorios diferentes. Puedes volver a pegarlos usando Git Submodules .

Jörg W Mittag
fuente
66
Dependiendo del escenario, es posible que desee usar git subtree en lugar de git submodule. Ver alumnit.ca/~apenwarr/log/?m=200904#30
C Pirate
99
@StijndeWitt: Durante el proceso de pago escaso git-read-tree, mucho después get-fetch. La pregunta no era solo verificar un subdirectorio, sino clonar solo un subdirectorio. No veo cómo los pagos escasos podrían hacer eso, ya que se git-read-treeejecuta después de que el clon ya se haya completado.
Jörg W Mittag
99
En lugar de este "trozo", ¿desea que elimine esta respuesta para que Chronial pueda flotar hasta la cima? No puede eliminarlo usted mismo, porque es aceptado, pero un moderador sí puede. Mantendrás la reputación que te has ganado, ya que es muy viejo. (Encontré esto porque alguien lo marcó como "solo enlace". :-)
Cody Gray
1
@CodyGray: la respuesta crónica todavía clona todo el repositorio, y no solo un subdirectorio. (El último párrafo incluso lo dice explícitamente). Clonar solo un subdirectorio es no posible en Git. El protocolo de red no lo admite, el formato de almacenamiento no lo admite. Cada respuesta a esta pregunta siempre clona todo el repositorio. La pregunta es simple Sí / No, y la respuesta tiene dos caracteres: No. Si es así, mi respuesta es innecesariamente larga , no corta.
Jörg W Mittag
1
@ JörgWMittag: la respuesta de Ciro Santili parece contradecirlo.
Dan Dascalescu el
1525

Lo que está tratando de hacer se llama un pago escaso , y esa característica se agregó en git 1.7.0 (febrero de 2012). Los pasos para hacer un clon escaso son los siguientes:

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

Esto crea un repositorio vacío con su control remoto y recupera todos los objetos, pero no los extrae. Entonces hazlo:

git config core.sparseCheckout true

Ahora debe definir qué archivos / carpetas desea verificar realmente. Esto se hace enumerándolos en .git/info/sparse-checkout, por ejemplo:

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

Por último, pero no menos importante, actualice su repositorio vacío con el estado del control remoto:

git pull origin master

Ahora tendrá archivos "desprotegidos" para some/diryanother/sub/tree en su sistema de archivos (con esas rutas aún), y no hay otras rutas presentes.

Es posible que desee echar un vistazo al tutorial extendido y probablemente debería leer la documentación oficial para un pago escaso .

Como una función:

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"

Tenga en cuenta que esto seguirá descargando todo el repositorio del servidor, solo que el pago se reduce en tamaño. Por el momento no es posible clonar un solo directorio. Pero si no necesita el historial del repositorio, al menos puede ahorrar en ancho de banda creando un clon superficial. Ver la respuesta de udondan a continuación para obtener información sobre cómo combinar clones poco profundos y pago escaso.


A partir de git 2.25.0 (enero de 2020), se agrega un comando experimental de comprobación escasa en 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
Crónica
fuente
14
en Apple el perímetro '-f' no funciona. solo haga git remote add origin <url> sin -f
Anno2001
135
Es una mejora, pero aún necesita descargar y almacenar una copia completa del repositorio remoto en origen, lo que a uno le gustaría evitar si está interesado solo en partes de la base de código (o si hay subcarpetas de documentación como en mi caso )
a1an
56
¿Hay alguna manera de clonar el contenido deseado del directorio (no el directorio en sí) directamente en mi repositorio? Por ejemplo, quiero clonar el contenido de la https://github.com/Umkus/nginx-boilerplate/tree/master/srcderecha en/etc/nginx
mac
25
@Chronial, @ErikE: ambos tienen razón / están equivocados: P El git remote addcomando no implica una búsqueda, pero git remote add -f, como se usa aquí, ¡sí! Eso es lo que -fsignifica.
ntc2
21
Usando esto y --depth=1cloné Chromium Devtools en 338 MB en lugar de 4.9 GB de Blink source + history. Excelente.
Rudie
444

git clone --filter de Git 2.19

Esta opción realmente omitirá la búsqueda de objetos innecesarios del servidor. También incluido --filter=tree:0desde Git 2.20 y el --filter=combinefiltro compuesto agregado en Git 2.24, terminamos 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/

El servidor debe configurarse con:

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

Se realizó una extensión al protocolo remoto Git para admitir esta función en v2.19.0 y omitir la búsqueda de objetos innecesarios, pero no hay soporte de servidor en ese momento. Pero ya se puede probar localmente.

Desglose de comandos:

El formato de --filterestá documentado en man git-rev-list.

Documentos en el árbol de Git:

Pruébalo

#!/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 aguas arriba .

Salida en 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

Conclusiones: d1/faltan todos los blobs externos . Por ejemplo 0975df9b39e23c15f63db194df7f45c76528bccb, que d2/bno está allí después de la salida d1/a.

Tenga en cuenta que root/rooty mybranch/mybranchtambién faltan, pero lo --depth 1oculta de la lista de archivos faltantes. Si elimina --depth 1, se muestran en la lista de archivos faltantes.

Tengo un sueño

Esta característica podría revolucionar a Git.

Imagine tener todo el código base de su empresa en un único repositorio sin herramientas desagradables de terceros comorepo .

Imagine almacenar grandes blobs directamente en el repositorio sin ninguna extensión fea de terceros .

Imagínese si GitHub permitiría metadatos por archivo / directorio como estrellas y permisos, para que pueda almacenar todas sus cosas personales en un solo repositorio.

Imagine si los submódulos se trataran exactamente como directorios normales : solo solicite un SHA en árbol y un mecanismo similar a DNS resuelve su solicitud , primero buscando en su servidor local~/.git , luego primero en servidores más cercanos (espejo / caché de su empresa) y terminando en GitHub.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fuente
Curiosamente, en macOS con git versión 2.20.1 (Apple Git-117), se queja de que "no se pueden combinar múltiples especificaciones de filtro"
muru
1
Lamentablemente, no hubo suerte con la versión macOS git. fatal: invalid filter-spec 'combine:blob:none+tree:0'¡Gracias de cualquier manera! Tal vez funcione con versiones más nuevas.
muru
1
Esto falla al intentarlo en Windows 10 usando GIT 2.24.1 (arroja toneladas de "no se puede leer el archivo sha1 de ..." + "Error al desvincular el archivo xxx"). Funcionó como un encanto con la misma versión en Linux.
Oyvind
1
@Ciro Santilli Esto todavía falla con "no se puede leer el archivo sha1 de ..." en git versión 2.26.1.windows.1. Abrí un informe de error: github.com/git-for-windows/git/issues/2590
nharrer
1
@nharrer gracias por la información!
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
405

Puede combinar el pago escaso y el características de clon superficial . El clon superficial corta el historial y el escaso pago solo extrae los archivos que coinciden con sus patrones.

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

Necesitará un mínimo de 1.9 git para que esto funcione. Lo probé solo con 2.2.0 y 2.2.2.

De esta manera, todavía podrás empujar , lo que no es posible con git archive.

udondan
fuente
21
Esto es útil y puede ser la mejor respuesta disponible, pero aún clona el contenido que no le interesa (si está en la rama que extrae), aunque no aparezca en el proceso de pago.
nobar
1
¿Cuál es tu versión de git? Según git help, ¿está disponible la opción de profundidad?
udondan
2
no funciona para mí cuando el último comando no es git pull --depth=1 origin masterpero git pull --depth=1 origin <any-other-branch>. esto es tan extraño, mira mi pregunta aquí: stackoverflow.com/questions/35820630/…
Shuman
55
En Windows, la penúltima línea debe omitir las comillas, o la extracción falla.
nateirvin
44
¡Esto todavía descarga todos los datos! Encontré esta solución, usando svn: stackoverflow.com/a/18324458/2302437
electronix384128
157

Para otros usuarios que solo desean descargar un archivo / carpeta de github, simplemente use:

svn export <repo>/trunk/<folder>

p.ej

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

(sí, eso es svn aquí. aparentemente en 2016 todavía necesita svn para simplemente descargar algunos archivos github)

Cortesía: descargue una sola carpeta o directorio de un repositorio de GitHub

Importante : asegúrese de actualizar la URL de Github y reemplazar/tree/master/ con '/ trunk /'.

Como script bash:

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

Nota: Este método descarga una carpeta, no la clona / desprotege. No puede enviar los cambios nuevamente al repositorio. Por otro lado, esto da como resultado una descarga más pequeña en comparación con el pago escaso o el pago superficial.

Anona112
fuente
99
única versión que funcionó para mí con github. Los comandos git extrajeron> 10k archivos, el svn exportó solo los 700 que quería. ¡Gracias!
Christopher Lörken
44
Intenté hacer esto https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/trunk/udacitypero obtuve un svn: E170000: URL 'https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/trunk/udacity' doesn't existerror :(
zthomas.nc
99
@ zthomas.nc Debe eliminar el 'tronco' que precede a udacity y reemplazar / tree / master / con / trunk / en su lugar.
Speedy
2
¡Este comando fue el que funcionó para mí! Solo quería obtener una copia de un archivo de un repositorio para poder modificarlo localmente. Buena vieja SVN al rescate!
Michael J
3
funciona, pero parece lento. tarda un poco en comenzar y luego los archivos pasan relativamente lento
Aryeh Beitz
73

Si nunca planea interactuar con el repositorio desde el que clonó, puede hacer un clon git completo y reescribir su repositorio usando git filter-branch --subdirectory-filter . De esta manera, al menos se preservará la historia.

hillu
fuente
11
Para las personas que no conocen el comando, lo esgit filter-branch --subdirectory-filter <subdirectory>
Jaime Hablutzel
99
Este método tiene la ventaja de que el subdirectorio que elija se convierte en la raíz del nuevo repositorio, que es exactamente lo que quiero.
Andrew Schulman
Ese es definitivamente el mejor y más fácil enfoque para usar. Aquí hay un comando de un paso que usa el filtro de subdirectoriogit clone https://github.com/your/repo_xx.git && cd repo_xx && git filter-branch --subdirectory-filter repo_xx_subdir
Alex
66

Esto parece mucho más simple:

git archive --remote=<repo_url> <branch> <path> | tar xvf -
ErichBSchulz
fuente
17
Cuando hago esto en github me sale fatal: la operación no es compatible con el protocolo. Final inesperado de la secuencia de comandos
Michael Fox
1
El error de protocolo podría deberse a HTTPS o: en la url del repositorio. También podría deberse a la falta de clave ssh.
Umair A.
2
Si está usando github, puede usarlo svn exporten su lugar
Milo Wielondek
2
No funcionará con Github -> Comando no válido: 'git-upload-archive' xxx / aaa.git '' Parece que estás usando ssh para clonar un git: // URL. Asegúrese de que su opción de configuración core.gitProxy y la variable de entorno GIT_PROXY_COMMAND NO estén establecidas. fatal: el extremo remoto colgó inesperadamente
Nianliang
3
La razón por la cual esto no funciona con GitHub: "No admitimos el uso de git-archive para extraer un archivo directamente desde GitHub. Puede clonar el repositorio localmente y ejecutar git-archive, o hacer clic en el botón Descargar ZIP en la página de repositorio ". github.com/xuwupeng2000/capistrano-scm-gitcopy/issues/16
Donn Lee
63

Git 1.7.0 tiene "pagos escasos". Ver “core.sparseCheckout” en el git config página de manual , “checkout escasa” en el GIT lectura árbol página de manual , y “poco Skip-worktree” en el git-actualización de índice de página de manual .

La interfaz no es tan conveniente como la SVN (por ejemplo, no hay forma de hacer un pago escaso en el momento de un clon inicial), pero la funcionalidad básica sobre la cual se podrían construir interfaces más simples ahora está disponible.

Chris Johnsen
fuente
37

No es posible clonar el subdirectorio solo con Git, pero a continuación hay algunas soluciones alternativas.

Filtrar rama

Es posible que desee volver a escribir el repositorio para que se vea como si trunk/public_html/hubiera sido la raíz del proyecto, y descartar el resto del historial (usando filter-branch), intente ya en la rama de pago:

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

Notas: El --que separa las opciones de rama de filtro de las opciones de revisión, y el --allpara reescribir todas las ramas y etiquetas. Toda la información incluida originales cometer veces o información de combinación será preservada . Este comando honra el .git/info/graftsarchivo y las referencias en el refs/replace/espacio de nombres, por lo que si tiene algún injerto o reemplazo refsdefinido, ejecutar este comando los hará permanentes.

¡Advertencia! El historial reescrito tendrá diferentes nombres de objeto para todos los objetos y no convergerá con la rama original. No podrá empujar y distribuir fácilmente la rama reescrita encima de la rama original. No use este comando si no conoce todas las implicaciones, y evite usarlo de todos modos, si una simple confirmación sería suficiente para solucionar su problema.


Pago escaso

Aquí hay pasos simples con un enfoque de pago escaso que llenará el directorio de trabajo de manera dispersa, por lo que puede decirle a Git qué carpeta (s) o archivo (s) en el directorio de trabajo vale la pena revisar.

  1. Clonar el repositorio como de costumbre ( --no-checkoutes opcional):

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

    Puede omitir este paso, si ya tiene su repositorio clonado.

    Sugerencia: Para repositorios grandes, considere clonar superficial ( --depth 1) para pagar solo la última revisión o / y --single-branchsolo.

  2. Habilitar sparseCheckoutopción:

    git config core.sparseCheckout true
    
  3. Especifique la (s) carpeta (s) para el pago escaso ( sin espacio al final):

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

    o editar .git/info/sparse-checkout.

  4. Verifique la sucursal (por ejemplo master):

    git checkout master
    

Ahora debería haber seleccionado carpetas en su directorio actual.

Puede considerar enlaces simbólicos si tiene demasiados niveles de directorios o rama de filtrado.


kenorb
fuente
¿La rama Filter todavía te lo permite pull?
sam
2
@sam: no. filter-branchvolvería a escribir las confirmaciones principales para que tengan diferentes ID SHA1 y, por lo tanto, su árbol filtrado no tendría confirmaciones en común con el árbol remoto. git pullno sabría de dónde tratar de fusionarnos.
Peter Cordes
Este enfoque es sobre todo una respuesta satisfactoria a mi caso.
Abbas
10

Acabo de escribir un guión para GitHub .

Uso:

python get_git_sub_dir.py path/to/sub/dir <RECURSIVE>
david_adler
fuente
11
FYI, eso es solo para GitHub .
Sz.
99
Y aparentemente esto es para descargar un directorio, no para clonar una pieza de un repositorio con todos sus metadatos ... ¿verdad?
LarsH
55
Debe incluir su código aquí y no en otro lugar.
jww
urllib2.HTTPError: Error HTTP 403: límite de velocidad excedido
diyism
9

Esto clonará una carpeta específica y eliminará todo el historial que no esté relacionado con ella.

git clone --single-branch -b {branch} [email protected]:{user}/{repo}.git
git filter-branch --subdirectory-filter {path/to/folder} HEAD
git remote remove origin
git remote add origin [email protected]:{user}/{new-repo}.git
git push -u origin master
BARJ
fuente
Aquí hay dragones. Uno se saludado por ADVERTENCIA: git-filter-branch tiene un exceso de trampas de generación reescribe la historia .. destrozados . Entonces los documentos de git-filter-branch tienen una lista de advertencia bastante larga.
Oyvind
6

Aquí hay una secuencia de comandos de shell que escribí para el caso de uso de un único subdirectorio

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
jxramos
fuente
2
Buena secuencia de comandos, solo algo que debería arreglarse es el enlace simbólico, debería ser en ln -s ./.$localRepo/$subDir $localRepolugar deln -s ./.$localRepo$subDir $localRepo
valentin_nasta
2

Escribí un .gitconfig [alias]para realizar un "pago escaso". Compruébalo (sin juego de palabras):

En Windows ejecuta en 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"

De otra manera:

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'

Uso :

# 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

Los git configcomandos se 'minifican' para mayor comodidad y almacenamiento, pero aquí está el alias expandido:

# 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
YenForYang
fuente
¿Por qué funciona esto L=${1##*/} L=${L%.git}? ¿Es el espacio un operador?
Gulzt
2

¿Usando Linux? ¿Y solo quiere un árbol de trabajo de fácil acceso y limpieza? sin molestar el resto del código en su máquina. prueba los enlaces simbólicos !

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

Prueba

cd ~/Desktop/my-subfolder
git status
Nasir Iqbal
fuente
1

Solo para aclarar algunas de las excelentes respuestas aquí, los pasos descritos en muchas de las respuestas suponen que ya tiene un repositorio remoto en alguna parte.

Dado: un repositorio git existente, por ejemplo [email protected]:some-user/full-repo.git, con uno o más directorios que desea extraer independientemente del resto del repositorio, por ejemplo, los directorios nombrados app1yapp2

Suponiendo que tiene un repositorio git como el anterior ...

Luego: puede ejecutar pasos como los siguientes para extraer solo directorios específicos de ese repositorio más grande:

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

Pensé erróneamente que las opciones de pago escaso tenían que establecerse en el repositorio original: este no es el caso. Usted define qué directorios desea localmente, antes de extraerlos del control remoto. Espero que esta aclaración ayude a alguien más.

Everett
fuente
0

Si bien odio tener que usar svn cuando trato con repositorios git: / Lo uso todo el tiempo;

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

Esto le permite copiar desde la url de github sin modificación. 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/
chico expulsado
fuente
0

Si realmente está interesado en los últimos archivos de revisión de un directorio, Github le permite descargar un repositorio como archivo Zip, que no contiene historial. Entonces la descarga es mucho más rápida.

weberjn
fuente
0

Así que intenté todo en esta banda y nada funcionó para mí ... Resulta que en la versión 2.24 de Git (la que viene con cpanel en el momento de esta respuesta), no es necesario que hagas esto

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

todo lo que necesitas es el nombre de la carpeta

wpm/*

En resumen, haces esto

git config core.sparsecheckout true

luego edita .git / info / sparse-checkout y agrega los nombres de carpeta (uno por línea) con / * al final para obtener subcarpetas y archivos

wpm/*

Guarde y ejecute el comando de pago

git checkout master

El resultado fue la carpeta esperada de mi repositorio y nada más Upvote si esto funcionó para usted

Patrick Simard
fuente