¿Cómo excluyo archivos del archivo git?

6 minutos de lectura

Dado un repositorio de prueba simple con una sola confirmación con dos archivos, a y bpuedo obtener una lista de archivos específicos:

$ git ls-files a
a

O una lista de todos los archivos excluyendo archivos específicos:

$ git ls-files . ':!b'
a

Puedo crear un archivo de archivos específicos:

$ git archive HEAD a | tar tf -
a

Pero no puedo crear un archivo de todos los archivos excluyendo archivos específicos:

$ git archive HEAD . ':!b' | tar tf -
a
b

La opción de usar un archivo de archivos específicos no es una opción para mí en mi repositorio real, ya que excede la longitud máxima del argumento de la línea de comando.

Sé que puedo almacenar la lista de archivos para excluir en .gitattributes mediante el export-ignore atributo, pero la lista se genera dinámicamente. Puedo cambiar automáticamente el archivo, pero los cambios no se recogen hasta después de otra confirmación.

¿Hay alguna otra invocación que funcione sin requerir otro compromiso?

Creo que casi lo lograste: los atributos se pueden leer desde varios lugares, con .gitattributes siendo sólo los más comunes de ellos. La segunda, considerada una configuración por repositorio, es $GIT_DIR/info/attributes.

Para citar el manual:

Tenga en cuenta que los atributos se toman por defecto del .gitattributes archivos en el árbol que se está archivando. Si desea modificar la forma en que se genera la salida después del hecho (por ejemplo, se comprometió sin agregar un
export-ignore en su .gitattributes), ajustar el desprotegido .gitattributes archivar según sea necesario y utilizar --worktree-attributes opción. Alternativamente, puede mantener los atributos necesarios que deberían aplicarse al archivar cualquier árbol en su
$GIT_DIR/info/attributes expediente.

Entonces, si es posible, pegue su lista a ese archivo y luego haga git archive.

Otro enfoque es no usar git archive pero en cambio simplemente tar el árbol de trabajo pasando tar la --exclude-from opción de línea de comandos que acepta un archivo. Esto no funcionaría para un repositorio simple, pero si está de acuerdo con verificar cosas antes de archivarlas, esto se puede hacer haciendo git read-tree y git checkout-index suministrado con la correcta $GIT_INDEX_FILE y $GIT_WORK_TREE env. variables

Otra posible solución es invertir el enfoque: tar (al menos GNU tar) admite una opción menos conocida de poder Eliminar cosas de un archivo en una canalización.

Básicamente, puedes hacer

 $ tar -C a_path -c -f - . \
   | tar -f - --wildcards --delete '*.pdf' >result.tar

para que el primero tar en la canalización archiva todo mientras que el segundo pasa todo excepto los archivos que coinciden con el *.pdf patrón de globo de concha.

Entonces, si la especificación de archivos para eliminar usando globos de shell se puede ajustar al límite de la línea de comandos, simplemente canalice la salida de git archive a un tar proceso que elimina las cosas que no se necesitan.

  • Gracias por la respuesta detallada. pienso por mi .git/info/attributes no es necesariamente el enfoque más lógico, pero se adapta mejor a lo que ya tengo, y si necesito algo más en el futuro, puedo cambiarlo a tar --delete.

    usuario743382

    3 de agosto de 2016 a las 9:05

  • Esta respuesta es innecesariamente complicada. Consulte la respuesta de zett42 a continuación para excluir archivos a través del argumento de ruta de git archive y la funcionalidad de exclusión de git pathspecs.

    – Leezu

    5 de febrero a las 15:06


avatar de usuario
zett42

Con la versión 2.20 de Git (Windows) y el servidor Gitolite (versión desconocida), esto me funciona para excluir archivos y carpetas llamados “b”:

git archive HEAD . ":!b" | tar tf -

Esto también funciona:

git archive HEAD . ":(exclude)b" | tar tf -

Tenga en cuenta que tengo que usar comillas dobles en la plataforma Windows, no estoy seguro acerca de otras plataformas.

Esta característica es parte de especificación de ruta (patrón utilizado para limitar las rutas en los comandos de Git). También vea esta respuesta.

  • Gracias. Ejemplo práctico basado en esto: git archive -v -o eb-bundle.zip –format=zip HEAD . “:(excluir)datos/local.js”

    – Tom Boutell

    13 de junio a las 13:18

  • ¡Muy agradable! ¿Hay alguna documentación sobre esa sintaxis “: (excluir)”? En git archive docs no hay nada al respecto.

    – Lorenzo Donati apoya a Ucrania

    18 de junio a las 15:06

  • @LorenzoDonatisupportUkraine He agregado enlaces.

    – zett42

    18 de junio a las 15:40

  • @zett42 Gracias!!! ¡Esta información está “particularmente bien oculta” en la documentación enviada con GitForWindows! Esperaría que cualquier opción/comando que requiera una especificación de ruta se vincule a la documentación relevante, ¡pero no!

    – Lorenzo Donati apoya a Ucrania

    19 de junio a las 8:29

Puede crear un archivo tar y luego eliminar carpetas y archivos que no es necesario que estén dentro

git archive HEAD -o archive.tar
tar -f archive.tar --delete listoffiles1
tar -f archive.tar --delete listoffiles2
tar -f archive.tar --delete listoffiles..
tar -f archive.tar --delete listoffilesN

de esta manera, puede dividir su línea de comando para permanecer por debajo de la longitud máxima del argumento cli

en lugar de poner export-ignore en un (comprometido) .gitattributestambién puede ponerlo en un (no comprometido) $GIT_DIR/info/attributes expediente. O alternativamente dejar el .gitattributes no comprometido y usar el --worktree-attributes opción, también probablemente no sea tan agradable ya que deja su árbol de trabajo sucio.

Una posible solución radica en el hecho de que git archive quiere un árbol-ish para archivar.

lo estas pasando HEAD (la opción más común, probablemente). Para hacer que esto haga lo que quiere decir, esta referencia se resuelve automáticamente en el objeto al que apunta, lo que obviamente será una confirmación. Y un objeto de compromiso se resuelve en el objeto de árbol adjunto. Entonces obtienes el contenido de la confirmación actual. Hasta ahora, tan obvio.

¡Pero puedes pasar cualquier objeto de árbol que quieras! ¿Y cómo ayuda eso? Bueno, siempre puedes crear un objeto de árbol a partir del estado actual del índice usando git write-tree – que devuelve el SHA1 del objeto de árbol que acaba de crear en stdout. No tienes que crear un compromiso ni nada por el estilo.

Así que puedes simplemente git rm --cached todo lo que no desea en el tarball y luego cree un objeto de árbol para pasar a git archive. Y dado que de lo contrario no le importa el objeto de árbol, puede combinarlo en el git archive dominio:

git archive $( git write-tree )

Después de eso puedes git reset --hard y sigue tu camino.

Todos juntos:

git rm --cached foo bar baz
git archive $( git write-tree )
git reset --all

¿Ha sido útil esta solución?