Verificación de subdirectorios en Git?

160

¿Es posible consultar subdirectorios de un repositorio en Git?

Imagina que estoy configurando una nueva instalación de WordPress. Crearé dos nuevos directorios para mi plugin y personalización del tema:

  • wordpress/wp-content/plugins/myplugins/
  • wordpress/wp-content/themes/mytheme/

Quiero mantener estos directorios a través de Git. En Subversion, me gustaría lograr esto por tener trunk/myplugins/y trunk/mytheme/directorios y subdirectorios a cabo la comprobación. ¿Git tiene una manera de lograr la misma tarea usando un único repositorio?

Podría perderme el barco en algún paradigma de Git, como un usuario de SVN desde hace mucho tiempo con poca exposición a Git.

Editar: varias ramas que almacenan contenido diferente es una forma interesante de manejar esto.

Annika Backstrom
fuente
2
¿Por qué no revisa todo el repositorio y hace un enlace simbólico a los subdirectorios con los que desea trabajar?
randomness2077
Respuesta simple aquí .
Peter Krauss el
¿Es posible hacer un pago escaso y hacer referencia al repositorio de Git?
luka5z

Respuestas:

121

Los pagos escasos ahora están en Git 1.7 .

También vea la pregunta “ ¿Es posible hacer un pago escaso sin consultar primero todo el repositorio? ".

Tenga en cuenta que los pagos escasos aún requieren que descargue todo el repositorio, a pesar de que algunos de los archivos que descarga Git no terminarán en su árbol de trabajo.

Collin Anderson
fuente
1
Donde de git clonesimple comando ?? Bueno, estoy usando esta respuesta , ¡está funcionando!
Peter Krauss el
44
¿Y hay alguna forma de cambiar el nombre de esas carpetas? Si escaso pago /foo/bar/foobar, ¿es posible verlo solo como /foobaren mi repositorio local?
graywolf
17

No hay una forma real de hacerlo en git. Y si no va a realizar cambios que afecten a ambos árboles a la vez como una sola unidad de trabajo, no hay una buena razón para usar un único repositorio para ambos. Pensé que echaría de menos esta función de Subversion, pero descubrí que crear repositorios tiene tan poca sobrecarga mental administrativa (simplemente debido al hecho de que los repositorios se almacenan justo al lado de su copia de trabajo, en lugar de obligarme a elegir explícitamente algún lugar fuera del copia de trabajo) que me acostumbré a hacer muchos repositorios pequeños de un solo propósito.

Sin embargo, si insiste (o realmente lo necesita), podría hacer un repositorio git con just mythemey mypluginsdirectorios y vincularlos desde la instalación de WordPress.


MDCore escribió:

hacer un compromiso, por ejemplo, mytheme incrementará el número de revisión para myplugin

Tenga en cuenta que esto no es una preocupación para git, si decide colocar ambos directorios en un único repositorio, porque git elimina por completo el concepto de números de revisión monotónicamente crecientes de cualquier forma.

El único criterio para saber qué cosas reunir en un único repositorio en git es si constituye una sola unidad, es decir. en su caso, si hay cambios en los que no tiene sentido mirar las ediciones en cada directorio de forma aislada. Si tiene cambios en los que necesita editar archivos en ambos directorios a la vez y las ediciones pertenecen juntas, deben ser un repositorio. Si no, entonces no los juntes.

Git realmente quiere que uses repositorios separados para entidades separadas.

submódulos

Los submódulos no abordan el deseo de mantener ambos directorios en un repositorio, porque en realidad impondrían tener un repositorio separado para cada directorio, que luego se unen en otro repositorio utilizando submódulos. Peor aún, dado que los directorios dentro de la instalación de WordPress no son subdirectorios directos del mismo directorio y también son parte de una jerarquía con muchos otros archivos, usar los repositorios por directorio como submódulos en un repositorio unificado no ofrecería ningún beneficio, ya que el unificado el repositorio no reflejaría ningún caso de uso / necesidad.

Aristóteles Pagaltzis
fuente
Donde de git clonesecuencia de comando simple ?? Bueno, estoy usando esta respuesta , ¡está funcionando!
Peter Krauss el
16

Una cosa que no me gusta de los pagos escasos, es que si desea pagar un subdirectorio que tiene unos pocos directorios de profundidad, la estructura de su directorio debe contener todos los directorios que lo conducen.

La forma de solucionar esto es clonar el repositorio en un lugar que no sea mi espacio de trabajo y luego crear un enlace simbólico en el directorio de mi espacio de trabajo al subdirectorio del repositorio. Git funciona así bastante bien porque cosas como el estado de git mostrarán los archivos de cambio en relación con su directorio de trabajo actual.

Travis Stevens
fuente
Esto solo funciona en un sistema operativo que admite enlaces simbólicos. Necesitan cambiar la forma en que funcionan los pagos escasos.
Anders Lindén
1
+1 para la idea con un enlace simbólico en el directorio desprotegido. Sin embargo, un pago escaso y un enlace simbólico no son mutuamente excluyentes: no necesita un clon completo.
Apitsch
10

En realidad, los pagos "estrechos" o "parciales" o "escasos" se encuentran en desarrollo actual y pesado para Git. Tenga en cuenta que todavía tendrá el repositorio completo debajo .git. Por lo tanto, las otras dos publicaciones son actuales para el estado actual de Git, pero parece que finalmente podremos realizar pagos escasos. Consulte las listas de correo si le interesan más detalles: están cambiando rápidamente.

Pat Notz
fuente
¡Bueno saber! Me gusta tener directorios tan relacionados en un solo repositorio, y lo haría si fuera posible.
Annika Backstrom
5

git clone --filter de Git 2.19

Esta opción realmente omitirá la búsqueda de objetos innecesarios del servidor:

git clone --depth 1 --no-checkout --filter=blob:none \
  "file://$(pwd)/server_repo" local_repo
cd local_repo
git checkout master -- mdir/

El servidor debe configurarse con:

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

No hay soporte de servidor a partir de v2.19.0, pero ya se puede probar localmente.

file://$(path)se requiere para superar las git clonetravesuras de protocolo: ¿Cómo clonar superficialmente un repositorio git local con una ruta relativa?

Recuerde que eso --depth 1ya implica --single-branch, vea también: ¿Cómo clono una sola rama en Git?

TODO: --filter=blob:noneomite todos los blobs, pero aún recupera todos los objetos del árbol. Pero en un repositorio normal, esto debería ser pequeño en comparación con los archivos en sí, por lo que esto ya es lo suficientemente bueno. Preguntado en: https://www.spinics.net/lists/git/msg342006.html Devs respondió un--filter=tree:0 está trabajando para hacerlo.

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

Se realizó una extensión al protocolo remoto Git para admitir esta función.

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:

# 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: todos los blobs desde fuera de d1/ faltan .

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.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fuente
1

Como señala su edición, puede usar dos ramas separadas para almacenar los dos directorios separados. Esto los mantiene a ambos en el mismo repositorio, pero aún no puede tener confirmaciones que abarquen ambos árboles de directorios. Si tiene un cambio en uno que requiere un cambio en el otro, tendrá que hacerlos como dos confirmaciones separadas, y abre la posibilidad de que un par de pagos de los dos directorios puedan estar fuera de sincronización.

Si desea tratar el par de directorios como una unidad, puede usar 'wordpress / wp-content' como la raíz de su repositorio y usar el archivo .gitignore en el nivel superior para ignorar todo menos los dos subdirectorios de interés. Esta es probablemente la solución más razonable en este momento.

Supuestamente, los pagos escasos han estado llegando durante dos años, pero todavía no hay señales de ellos en el repositorio de desarrollo de git, ni ninguna indicación de que los cambios necesarios llegarán allí. No contaría con ellos.

cjs
fuente
1

No puede pagar un solo directorio de un repositorio porque todo el repositorio es manejado por la única carpeta .git en la raíz del proyecto en lugar de la miríada de directorios .svn de subversion.

El problema con trabajar en complementos en un único repositorio es que hacer un compromiso, por ejemplo, mytheme incrementará el número de revisión para myplugin , por lo que incluso en subversión es mejor usar repositorios separados.

El paradigma de subversión para subproyectos es svn: externals, que se traduce de alguna manera en submódulos en git (pero no exactamente en el caso de que haya usado svn: externals antes).

MDCore
fuente
0

Hay una inspiración aquí. Solo utiliza shell regexo git regex.

git checkout commit_id */*.bat  # *.bat in 1-depth subdir exclude current dir, shell regex  
git checkout commit_id '*.bat'  # *.bat in all subdir include current dir, git regex

Use la cita para escapar de la interpretación de expresiones regulares de shell y pase comodines a git.

El primero no es recursivo, solo archivos en 1 profundidad subdir. Pero el segundo es recursivo.

En cuanto a su situación, lo siguiente puede ser suficiente.

git checkout master */*/wp-content/*/*
git checkout master '*/wp-content/*'

Simplemente piratea las líneas según sea necesario.

W.Perrin
fuente
0

Puede revertir los cambios no confirmados solo a un archivo o directorio en particular:

git checkout [some_dir|file.txt]
Yuliia Ashomok
fuente