rsync excluye según.gitignore &.hgignore & svn: ignore como--filter=: C
mercurial (9)
Rsync incluye una opción ingeniosa --cvs-exclude
para "ignorar archivos de la misma manera que CVS", pero CVS ha quedado obsoleto durante años. ¿Hay alguna manera de hacer que también excluya archivos que serían ignorados por los modernos sistemas de control de versiones (Git, Mercurial, Subversion)?
Por ejemplo, tengo muchos proyectos de Maven sacados de GitHub. Por lo general, incluyen un listado .gitignore
al menos target
, el directorio de compilación Maven predeterminado (que puede estar presente en el nivel superior o en submódulos). Dado que el contenido de estos directorios es totalmente desechable, y pueden ser mucho más grandes que el código fuente, me gustaría excluirlos cuando uso rsync para copias de seguridad.
Por supuesto, puedo explícitamente --exclude=target/
pero eso suprimirá accidentalmente directorios no relacionados que simplemente se denominan target
y no se deben ignorar.
Y podría proporcionar una lista completa de rutas absolutas para todos los nombres de archivos y patrones mencionados en cualquier .gitignore
, .hgignore
o svn:ignore
en mi disco, pero esta sería una gran lista que tendría que ser producida por algún tipo de secuencia de comandos
Dado que rsync no tiene soporte integrado para las comprobaciones de VCS que no sean CVS, ¿hay algún truco para alimentar sus patrones de ignorar? ¿O algún tipo de sistema de devolución de llamada mediante el cual se puede preguntar al usuario si se debe incluir o no un archivo / directorio determinado?
Actualización : --filter='':- .gitignore''
como lo sugiere LordJavac parece funcionar también para Git como --filter=:C
hace para CVS, al menos en los ejemplos que he encontrado, aunque no está claro si la sintaxis es una coincidencia exacta. --filter='':- .hgignore''
no funciona muy bien para Mercurial; por ejemplo, un .hgignore
contiene una línea como ^target$
(el equivalente de Mercurial de Git /target/
) no es reconocido por rsync como una expresión regular. Y nada parece funcionar para Subversion, para lo cual tendría que analizar .svn/dir-prop-base
para una copia de trabajo 1.6 o anterior, y levantar sus manos en señal de consternación por una copia de trabajo 1.7 o posterior.
2018 solución confirmed
rsync -ah --delete
--include .git --exclude-from="$(git -C SRC ls-files /
--exclude-standard -oi --directory >.git/ignores.tmp && /
echo .git/ignores.tmp'')" /
SRC DST
Detalles: --exclude-from
es obligatorio en lugar de --exclude porque es probable que el caso que excluye la lista no se analice como un argumento. Excluir requiere un archivo y no puede trabajar con tuberías.
La solución actual guarda el archivo de exclusión dentro de la carpeta .git para asegurar que no afecte el git status
mientras se mantiene independiente. Si lo desea, puede utilizar / tmp.
¿ rsync --exclude-from=''path/.gitignore'' --exclude-from=''path/myignore.txt'' source destination
?
Funcionó para mí
Creo que también puedes tener más parámetros de --exclude-from
.
Como lo mencionó luksan, puede hacer esto con el interruptor --filter
a rsync
. Lo --filter='':- .gitignore''
con --filter='':- .gitignore''
(hay un espacio antes de ".gitignore") que le dice a rsync
que haga una fusión de directorio con archivos .gitignore
y que los excluya por las reglas de git. También es posible que desee agregar su archivo global de ignorar, si tiene uno. Para que sea más fácil de usar, creé un alias para rsync
que incluía el filtro.
Consulte la sección REGLAS DEL FILTRO DE FUSIÓN en rsync (1).
Parece que es posible crear una regla rsync --filter que incluirá archivos .gitignore a medida que atraviesa la estructura del directorio.
En lugar de crear filtros de exclusión, puede usar git ls-files
para seleccionar cada archivo para rsync:
#!/usr/bin/env bash
if [[ ! $# -eq 2 ]] ; then
echo "Usage: $(basename $0) <local source> <rsync destination>"
exit 1
fi
cd $1
versioned=$(git ls-files --exclude-standard)
rsync --verbose --links --times --relative --protect-args ${versioned} $2
Esto funciona a pesar de que git ls-files
devuelve rutas separadas por nueva línea. Probablemente no funcionará si tiene archivos versionados con espacios en los nombres de archivo.
Para Mercurial puedes usar
hg status -i | sed ''s/^I //'' > /tmp/tmpfile.txt
para recopilar la lista de archivos que NO están bajo control mercurial debido a restricciones de .hgignore y luego ejecutar
rsync -avm --exclude-from=/tmp/tmpfile.txt --delete source_dir/ target_dir/
para sincronizar todos los archivos, excepto los ignorados. Observe -m marca en rsync que excluirá la sincronización de directorios vacíos porque el estado hg -i solo mostrará los archivos excluidos, no los directorios
Puede usar git ls-files
para compilar la lista de archivos excluidos por los archivos .gitignore
del repositorio. https://git-scm.com/docs/git-ls-files
Opciones:
-
--exclude-standard
Considera todos los archivos.gitignore
. -
-o
No ignore los cambios sin grabar. -
-i
Solo salida de archivos ignorados. -
--directory
Solo--directory
la ruta del directorio si se ignora todo el directorio.
Lo único que dejé de ignorar fue .git
.
rsync -azP --exclude=.git --exclude=`git -C <SRC> ls-files --exclude-standard -oi --directory` <SRC> <DEST>
Según la página del manual de rsync
, además de la lista estándar de patrones de archivos:
los archivos que se enumeran en $ HOME / .cvsignore se agregan a la lista y a los archivos enumerados en la variable de entorno CVSIGNORE
Por lo tanto, mi archivo $ HOME / .cvsignore se ve así:
.git/
.sass-cache/
para excluir .git y los archivos generados por Sass .
Tenía varios archivos .gitignore
muy grandes y ninguna de las soluciones "rsync puras" funcionaba para mí. Escribí este guión rsync wrapper , respeta .gitignore
reglas .gitignore
(incluye excepciones de estilo !
.gitignore
archivos .gitignore
en subdirectorios) y funcionó como un encanto para mí.