web-dev-qa-db-fra.com

rsync exclut selon .gitignore & .hgignore & svn: ignorer comme --filter =: C

Rsync inclut une option astucieuse --cvs-exclude pour "ignorer les fichiers de la même manière que CVS", mais CVS est obsolète depuis des années. Existe-t-il un moyen d'exclure également les fichiers qui seraient ignorés par les systèmes de contrôle de version modernes (Git, Mercurial, Subversion)?

Par exemple, j'ai beaucoup de projets Maven extraits de GitHub. Ils incluent généralement un .gitignore listant au moins target, le répertoire de construction par défaut de Maven (qui peut être présent au niveau supérieur ou dans des sous-modules). Étant donné que le contenu de ces répertoires est entièrement jetable et qu'il peut être bien plus volumineux que le code source, je voudrais les exclure lors de l'utilisation de rsync pour les sauvegardes.

Bien sûr, je peux explicitement --exclude=target/ mais cela supprimera accidentellement les répertoires non liés qui se trouvent être nommés target et ne sont pas censés être ignorés.

Et je pourrais fournir une liste complète des chemins absolus pour tous les noms de fichiers et modèles mentionnés dans n'importe quel .gitignore, .hgignore, ou svn:ignore propriété sur mon disque, mais ce serait une énorme liste qui devrait être produite par une sorte de script.

Étant donné que rsync n'a pas de prise en charge intégrée pour les extractions VCS autres que CVS, existe-t-il une bonne astuce pour l'alimenter en modèles ignorés? Ou une sorte de système de rappel permettant de demander à un script utilisateur si un fichier/répertoire donné doit être inclus ou non?

Mise à jour: --filter=':- .gitignore' comme l'a suggéré LordJavac semble fonctionner aussi bien pour Git que --filter=:C fait pour CVS, au moins sur les exemples que j'ai trouvés, bien qu'il ne soit pas clair si la syntaxe est une correspondance exacte. --filter=':- .hgignore' ne fonctionne pas très bien pour Mercurial; par exemple. un .hgignore contenant une ligne comme ^target$ (l'équivalent Mercurial de Git /target/) n'est pas reconnu par rsync comme une expression régulière. Et rien ne semble fonctionner pour Subversion, pour lequel il faudrait analyser .svn/dir-prop-base pour une copie de travail 1.6 ou antérieure, et jetez un œil consterné pour une copie de travail 1.7 ou ultérieure.

97
Jesse Glick

Comme mentionné par luksan, vous pouvez le faire avec le --filter basculez sur rsync. J'ai réussi avec --filter=':- .gitignore' (il y a un espace avant ".gitignore") qui indique à rsync de fusionner un répertoire avec .gitignore fichiers et les faire exclure selon les règles de git. Vous pouvez également ajouter votre fichier d'ignorance global, si vous en avez un. Pour le rendre plus facile à utiliser, j'ai créé un alias pour rsync qui incluait le filtre.

102
LordJavac

Vous pouvez utiliser git ls-files pour construire la liste des fichiers exclus par le référentiel .gitignore des dossiers. https://git-scm.com/docs/git-ls-files

Options:

  • --exclude-standard Considérez tout .gitignore des dossiers.
  • -o N'ignorez pas les modifications non programmées.
  • -i Uniquement les fichiers ignorés en sortie.
  • --directory N'afficher le chemin du répertoire que si le répertoire entier est ignoré.

La seule chose que j'ai laissé ignorer était .git.

rsync -azP --exclude=.git --exclude=`git -C <SRC> ls-files --exclude-standard -oi --directory` <SRC> <DEST>
9
Jared Deckard

Solution 2018 confirmé

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 

Détails: --exclude-from est obligatoire au lieu de --exclude car le cas probable où cette liste d'exclusion ne serait pas analysée comme argument. Exclure de requiert un fichier et ne peut pas fonctionner avec les canaux.

La solution actuelle enregistre le fichier d'exclusion dans le dossier .git afin de garantir qu'il n'affectera pas git status tout en restant autonome. Si vous le souhaitez, vous pouvez utiliser/tmp.

5
sorin

que diriez-vous rsync --exclude-from='path/.gitignore' --exclude-from='path/myignore.txt' source destination?
Cela a fonctionné pour moi.
Je pense que vous pouvez en avoir plus --exclude-from paramètres aussi.

5
ericn

Pour Mercurial vous pouvez utiliser

hg status -i | sed 's/^I //' > /tmp/tmpfile.txt

pour collecter la liste des fichiers qui ne sont PAS sous contrôle Mercurial en raison des restrictions . hgignore , puis exécutez

rsync -avm --exclude-from=/tmp/tmpfile.txt --delete source_dir/ target_dir/

pour rsync tous les fichiers sauf ceux ignorés. Remarque - m indicateur dans rsync qui exclura les répertoires vides de la synchronisation car hg status -i ne listerait que les fichiers exclus, pas dirs

3
ffeast

Essaye ça:

rsync -azP --delete --filter=":- .gitignore" <SRC> <DEST>

Il peut copier tous les fichiers dans un répertoire distant, à l'exception des fichiers dans '.gitignore', et supprimer des fichiers qui ne se trouvent pas dans votre répertoire actuel.

2
Shawn Wang

J'ai eu un certain nombre de très gros .gitignore fichiers et aucune des solutions "pure rsync" n'a fonctionné pour moi. J'ai écrit ceci script wrapper rsync , il respecte pleinement .gitignore règles (inclure !- exceptions de style et .gitignore fichiers dans les sous-répertoires) et a fonctionné comme un charme pour moi.

1
cobbzilla

Par la page de manuel rsync, en plus de la liste standard des modèles de fichiers:

les fichiers répertoriés dans un $ HOME/.cvsignore sont ajoutés à la liste et tous les fichiers répertoriés dans la variable d'environnement CVSIGNORE

Ainsi, mon fichier $ HOME/.cvsignore ressemble à ceci:

.git/
.sass-cache/

pour exclure .git et les fichiers générés par Sass .

0
Doug Harris

Consultez la section RÈGLES DE FILTRE MERGE-FILES dans rsync (1).

Il semble qu'il soit possible de créer une règle rsync --filter qui inclura les fichiers .gitignore lors de la traversée de la structure du répertoire.

0
luksan

Au lieu de créer des filtres d'exclusion, vous pouvez utiliser git ls-files pour sélectionner chaque fichier à 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

Cela fonctionne même si git ls-files renvoie des chemins séparés par des sauts de ligne. Ne fonctionnera probablement pas si vous avez des fichiers versionnés avec des espaces dans les noms de fichiers.

0
user7033996

Alternatives:

git ls-files -zi --exclude-standard |rsync -0 --exclude-from=- ...

git ls-files -zi --exclude-per-directory=".gitignore" |...

(rsync ne comprend que partiellement .gitignore)

0
druid62