rsync esclude secondo .gitignore & .hgignore & svn: ignora come --filter =: C


113

Rsync include un'elegante opzione --cvs-excludeper "ignorare i file nello stesso modo in cui lo fa CVS", ma CVS è obsoleto da anni. C'è un modo per escludere anche file che sarebbero ignorati dai moderni sistemi di controllo delle versioni (Git, Mercurial, Subversion)?

Ad esempio, ho molti progetti Maven controllati da GitHub. In genere includono .gitignorealmeno un elenco target, la directory di compilazione Maven predefinita (che può essere presente al livello superiore o nei sottomoduli). Poiché il contenuto di queste directory è interamente usa e getta e può essere molto più grande del codice sorgente, vorrei escluderle quando si utilizza rsync per i backup.

Ovviamente posso --exclude=target/farlo in modo esplicito, ma questo sopprimerà accidentalmente le directory non correlate che per caso hanno un nome targete non dovrebbero essere ignorate.

E potrei fornire un elenco completo di percorsi assoluti per tutti i nomi di file e modelli menzionati in qualsiasi .gitignore, .hgignoreo svn:ignoreproprietà sul mio disco, ma questo sarebbe un elenco enorme che dovrebbe essere prodotto da una sorta di script.

Dato che rsync non ha alcun supporto integrato per i checkout VCS oltre a CVS, c'è qualche buon trucco per alimentare i propri schemi di ignoranza? O qualche tipo di sistema di callback in base al quale è possibile chiedere a uno script utente se un determinato file / directory debba essere incluso o meno?

Aggiornamento : --filter=':- .gitignore'come suggerito da LordJavac sembra funzionare anche per Git come --filter=:Cfa per CVS, almeno sugli esempi che ho trovato, anche se non è chiaro se la sintassi sia una corrispondenza esatta. --filter=':- .hgignore'non funziona molto bene per Mercurial; ad esempio un .hgignorecontenente una riga come ^target$(l'equivalente Mercurial di Git /target/) non è riconosciuto da rsync come espressione regolare. E niente sembra funzionare per Subversion, per il quale dovresti analizzare .svn/dir-prop-baseper una copia di lavoro 1.6 o precedente, e alzare le mani in sgomento per una copia di lavoro 1.7 o successiva.


11
Sembra un po 'come sarebbe una buona idea inviare una patch per rsync che aggiunge il supporto per .gitignore, .hgignore, ecc.
ThiefMaster

3
@ThiefMaster: ho archiviato bugzilla.samba.org/show_bug.cgi?id=9744 come punto di partenza.
Jesse Glick

2
solo una nota per gli altri, il .gitignore deve essere nella gerarchia delle cartelle da rysnc, non nella directory in cui viene eseguito il comando
myol

Cosa :-significa esattamente? Cosa significa il colon? Che cos'è il trattino?
David

Git ora ha un check-ignoresottocomando che può gestire il duro lavoro di analizzare i vari file "ignorati", se si desidera utilizzare l'opzione "genera un elenco di tutti i file non ignorati". La mia risposta qui fornisce dettagli su come farlo.
cjs

Risposte:


120

Come accennato da luksan, puoi farlo con il --filterpassaggio a rsync. Ho ottenuto questo risultato con --filter=':- .gitignore'(c'è uno spazio prima di ".gitignore") che dice rsyncdi fare una fusione di directory con i .gitignorefile e di escluderli secondo le regole di git. Potresti anche voler aggiungere il tuo file ignora globale, se ne hai uno. Per renderlo più facile da usare, ho creato un alias rsyncche includeva il filtro.


Un buon inizio, anche se esito ad "accettare" questa risposta in quanto copre solo Git.
Jesse Glick

23
Una versione più dettagliata che esclude anche i file .git:--exclude='/.git' --filter="dir-merge,- .gitignore"
VasiliNovikov

2
Ho qualcosa del genere ora: rsync -rvv --exclude='.git*' --exclude='/rsync-to-dev.sh' --filter='dir-merge,-n /.gitignore' $DIR/ development.foobar.com:~/test/.. ma anche se dice [sender] hiding file .gitignore because of pattern .git*, il file viene comunque inviato alla destinazione
rolandow,

2
Se anche voi volete utilizzare --deletel'opzione, qui è la linea di comando di lavoro: rsync --delete-after --filter=":e- .gitignore" --filter "- .git/" -v -a .... Mi ci è voluto un po '... enel filtro e --delete-aftersono entrambi importanti. Suggerisco di leggere il capitolo "REGOLE PER DIRECTORY E CANCELLAZIONE" della rsyncpagina man.
dbolotin

1
Per sincronizzare le eliminazioni e le aggiunte e gli aggiornamenti, puoi semplicemente aggiungere --delete-afteralla versione del comando di @ VasiliNovikov. (Questo sembra equivalente alla versione del comando di @ dboliton, tranne che @db usa: e che penso escluda la copia dei file .gitignore, che non è quello che volevo.)
Bampfer

10

È possibile utilizzare git ls-filesper creare l'elenco dei file esclusi dai file del repository .gitignore. https://git-scm.com/docs/git-ls-files

Opzioni:

  • --exclude-standardConsidera tutti i .gitignorefile.
  • -o Non ignorare le modifiche non programmate.
  • -i Visualizza solo i file ignorati.
  • --directory Visualizza il percorso della directory solo se l'intera directory viene ignorata.

L'unica cosa che mi restava da ignorare era .git.

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

4
questo non funziona. esclude il primo file dal sottocomando git e quindi considera il resto come parte dell'elenco SRC. funziona: rsync -azP --exclude-from="$(git -C SRC ls-files --exclude-standard -oi --directory > /tmp/excludes; echo /tmp/excludes)" SRC DEST
maratona

2
Questo è l'unico metodo che funziona se hai sia escludi che includi righe nel tuo .gitignore(cioè righe che iniziano con !). Inoltre esegue nuovamente la sincronizzazione dei file --forceaggiunti al repository, il che di solito è una buona cosa.
ostrokach

1
In effetti questa risposta NON FUNZIONA, quindi ho finito per scriverne una che funziona: stackoverflow.com/a/50059607/99834
sorin

6

che ne dici rsync --exclude-from='path/.gitignore' --exclude-from='path/myignore.txt' source destination?
Ha funzionato per me.
Credo che tu possa avere anche più --exclude-fromparametri.


3
Questo funzionerà nella misura in cui i tuoi .gitignorefile utilizzeranno una sintassi compatibile con rsync.
Jesse Glick

@JesseGlick è giusto, rsync non è in grado di analizzare .gitignore file, vedere stackoverflow.com/a/50059607/99834 workround.
sorin

6

Soluzione 2018 confermata

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 

Dettagli: --exclude-from è obbligatorio al posto di --exclude perché probabilmente il caso in cui l'elenco di eccezioni non verrà analizzato come argomento. Escludi da richiede un file e non può funzionare con le pipe.

La soluzione corrente salva il file di esclusione all'interno della cartella .git per garantire che non influirà git statusmantenendolo autonomo. Se vuoi puoi usare / tmp.


3
Sembra che funzionerà se si dispone di un particolare repository Git che si desidera sincronizzare, il SRCqui, ma non per il problema originale che ho affermato, che è una directory tentacolare con migliaia di repository Git come sottodirectory a varie profondità, molti dei quali hanno idiosincratico .gitignores.
Jesse Glick,

1
Se stai usando una shell con supporto per la sostituzione del processo (bash, zsh, ecc.) Puoi usare--exclude-from=<(git -C SRC ls-files --exclude-standard -oi --directory)
Roland W

3

Per mercurial potresti usare

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

per raccogliere l'elenco dei file che NON sono sotto il controllo di Mercurial a causa delle restrizioni .hgignore e quindi eseguire

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

per sincronizzare nuovamente tutti i file tranne quelli ignorati. Notare il flag -m in rsync che escluderà le directory vuote dalla sincronizzazione perché hg status -i elencherebbe solo i file esclusi, non le directory


2

Prova questo:

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

Può copiare tutti i file nella directory remota escludendo i file in ".gitignore" ed eliminare i file non presenti nella directory corrente.


1

Per la rsyncpagina man, oltre all'elenco standard di modelli di file:

i file elencati in $ HOME / .cvsignore vengono aggiunti all'elenco e tutti i file elencati nella variabile d'ambiente CVSIGNORE

Quindi, il mio file $ HOME / .cvsignore ha questo aspetto:

.git/
.sass-cache/

per escludere .git e i file generati da Sass .


2
Al contrario, voglio assolutamente includere le .git/directory, forse anche più fortemente della copia di lavoro. Quello che voglio escludere sono i prodotti build.
Jesse Glick

Inoltre, questa impostazione non è portatile. È per utente, non per progetto.
VasiliNovikov

@ JesseGlick Ti ho chiesto di mantenere .git / dirs incluso. Essendo Git un SCM distribuito, è importante eseguire il backup dell'intero repository locale.
Johan Boulé

1 / La frase dalla rsyncpagina man citata in questa risposta descrive l' --cvs-excludeopzione, quindi devi usarla esplicitamente. 2 / È possibile creare .cvsignorefile in qualsiasi directory per ignorare specifici del progetto, anche quelli vengono letti. 3 / .gitè già ignorato quando lo usi --cvs-exclude, secondo il manuale, quindi averlo in $HOME/.cvsignoresembra ridondante.
Niavlys

1

Avevo un numero di .gitignorefile molto grandi e nessuna delle soluzioni "pure rsync" ha funzionato per me. Ho scritto questo script wrapper rsync , rispetta pienamente le .gitignoreregole (includi !eccezioni in stile e .gitignorefile nelle sottodirectory) e ha funzionato alla grande per me.


Provando questo tramite locate -0e .gitignore | (while read -d '' x; do process_git_ignore "$x"; done), ma ha molti problemi. File nella stessa directory .gitignorenon separati correttamente dal nome della directory con /. Righe vuote e commenti interpretati male. Soffoca i .gitignorefile in percorsi con spazi (non importa il diabolico /opt/vagrant/embedded/gems/gems/rb-fsevent-0.9.4/spec/fixtures/custom 'path/.gitignoredal vagrantpacchetto per Ubuntu). Forse fatto meglio come script Perl.
Jesse Glick

@JesseGlick Non sono sicuro del motivo per cui stai chiamando la funzione all'interno dello script. è inteso per essere utilizzato come sostituto immediato di rsync, per la ragione specifica che la gestione di citazioni / spazi bianchi è un tale dolore. Se hai un esempio di una gsyncriga di comando che non funziona e i .gitignorefile ad essa associati, sarei felice di dare un'occhiata più da vicino.
cobbzilla

Ho bisogno di rsyncun intero filesystem, con vari repository Git sparsi intorno ad esso. Forse il tuo script funziona bene per la sincronizzazione di un singolo repository.
Jesse Glick,

1
Sì, sicuramente. scusa non l'ho chiarito. Con questo script, dovresti invocarlo una volta per repository git, dall'interno della directory repository.
cobbzilla

0

Controlla la sezione REGOLE FILTRO FILE MERGE in rsync (1).

Sembra che sia possibile creare una regola rsync --filter che includerà i file .gitignore mentre attraversa la struttura della directory.


0

Invece di creare filtri di esclusione, puoi utilizzare git ls-filesper selezionare ogni file da 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

Funziona anche se git ls-filesrestituisce percorsi separati da nuova riga. Probabilmente non funzionerà se hai file con versione con spazi nei nomi dei file.


0

alternative:

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

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

(rsync comprende solo in parte .gitignore)


0

Risposta breve

rsync -r --info=progress2 --filter=':- .gitignore' SOURCE DEST/

Significato dei parametri:

-r: ricorsivo

--info=...: mostra i progressi

--filter=...: esclude secondo le regole elencate nel file .gitignore

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.