rsync ausschließen gemäß .gitignore & .hgignore & svn: ignorieren wie --filter =: C.


112

Rsync enthält eine raffinierte Option --cvs-excludezum "Ignorieren von Dateien auf die gleiche Weise wie CVS", aber CVS ist seit Jahren veraltet. Gibt es eine Möglichkeit, Dateien auszuschließen, die von modernen Versionskontrollsystemen (Git, Mercurial, Subversion) ignoriert werden?

Zum Beispiel habe ich viele Maven-Projekte von GitHub ausgecheckt. In der Regel enthalten sie .gitignoremindestens eine Auflistung target, das Standard-Maven-Build-Verzeichnis (das möglicherweise auf oberster Ebene oder in Submodulen vorhanden ist). Da der Inhalt dieser Verzeichnisse vollständig verfügbar ist und weitaus größer als der Quellcode sein kann, möchte ich sie bei der Verwendung von rsync für Sicherungen ausschließen.

Natürlich kann ich das explizit, --exclude=target/aber das wird versehentlich nicht verwandte Verzeichnisse unterdrücken, die zufällig benannt werden targetund nicht ignoriert werden sollen.

Und ich konnte eine vollständige Liste der absoluten Pfade für alle Dateinamen und Muster erwähnten in jedem liefern .gitignore, .hgignoreoder svn:ignoreEigentum auf meiner Festplatte, aber das wäre eine riesige Liste, die durch irgendeine Art von Skript erzeugt werden müßte.

Gibt es einen guten Trick, um rsync ihre Ignoriermuster zuzuweisen, da es keine integrierte Unterstützung für VCS-Checkouts außer CVS gibt? Oder eine Art Rückrufsystem, bei dem ein Benutzerskript gefragt werden kann, ob eine bestimmte Datei / ein bestimmtes Verzeichnis enthalten sein soll oder nicht?

Update : --filter=':- .gitignore'Wie von LordJavac vorgeschlagen, scheint es für Git genauso gut zu funktionieren wie --filter=:Cfür CVS, zumindest bei den Beispielen, die ich gefunden habe, obwohl unklar ist, ob die Syntax genau übereinstimmt. --filter=':- .hgignore'funktioniert nicht sehr gut für Mercurial; zB wird .hgignoreeine Zeile wie ^target$(das Mercurial-Äquivalent von Git /target/) von rsync nicht als regulärer Ausdruck erkannt. Und für Subversion scheint nichts zu funktionieren, für das Sie .svn/dir-prop-baseeine Arbeitskopie von 1.6 oder früher analysieren und für eine Arbeitskopie von 1.7 oder später bestürzt die Hände hochwerfen müssten .


11
Klingt ein bisschen so, als wäre es eine gute Idee, einen Patch für rsync einzureichen, der Unterstützung für .gitignore, .hgignore usw.
hinzufügt

3
@ThiefMaster: Ich habe bugzilla.samba.org/show_bug.cgi?id=9744 als Ausgangspunkt abgelegt .
Jesse Glick

2
Nur ein Hinweis für andere, der .gitignore muss sich in der Ordnerhierarchie befinden, die rysnc'd wird, nicht in dem Verzeichnis, in dem der Befehl ausgeführt wird
myol

Was :-bedeutet genau? Was bedeutet der Doppelpunkt? Was zum Teufel?
David

Git hat jetzt einen check-ignoreUnterbefehl, der die harte Arbeit des Parsens der verschiedenen "Ignorieren" -Dateien bewältigen kann, wenn Sie die Option "Liste aller nicht ignorierten Dateien erstellen" verwenden möchten. Meine Antwort hier gibt Einzelheiten dazu.
cjs

Antworten:


120

Wie von Luksan erwähnt, können Sie dies mit dem --filterWechsel zu tun rsync. Ich habe dies erreicht mit --filter=':- .gitignore'(es gibt ein Leerzeichen vor ".gitignore"), das angibt rsync, eine Verzeichniszusammenführung mit .gitignoreDateien durchzuführen und diese gemäß den Regeln von git auszuschließen. Möglicherweise möchten Sie auch Ihre globale Ignorierdatei hinzufügen, falls Sie eine haben. Um die Verwendung zu vereinfachen, habe ich einen Alias ​​erstellt, zu rsyncdem der Filter gehört.


Ein guter Anfang, obwohl ich zögere, diese Antwort zu „akzeptieren“, da sie nur Git abdeckt.
Jesse Glick

23
Eine ausführlichere Version, die auch --exclude='/.git' --filter="dir-merge,- .gitignore"
.git-

2
Ich habe jetzt so etwas: rsync -rvv --exclude='.git*' --exclude='/rsync-to-dev.sh' --filter='dir-merge,-n /.gitignore' $DIR/ development.foobar.com:~/test/.. aber obwohl es heißt [sender] hiding file .gitignore because of pattern .git*, wird die Datei immer noch an die Desintation gesendet
Rolandow

2
Wenn Sie auch die --deleteOption verwenden möchten , finden Sie hier die Arbeitsbefehlszeile : rsync --delete-after --filter=":e- .gitignore" --filter "- .git/" -v -a .... Das hat eine Weile gedauert ... eim Filter und --delete-afterbeide sind wichtig. Ich schlage vor, das Kapitel "PER-DIRECTORY RULES AND DELETE" der rsyncManpage zu lesen .
Dbolotin

1
Um Löschvorgänge sowie das Hinzufügen und Aktualisieren zu synchronisieren, können Sie einfach --delete-afterdie Version des Befehls von @ VasiliNovikov hinzufügen . (Dies scheint äquivalent zu @ dbolitons Version des Befehls zu sein, außer dass @db Folgendes verwendet: e, was meiner Meinung nach die .gitignore-Dateien vom Kopieren ausschließt, was nicht das ist, was ich wollte.)
Bampfer

10

Sie können git ls-filesdamit die Liste der Dateien erstellen, die von den Dateien des Repositorys ausgeschlossen sind .gitignore. https://git-scm.com/docs/git-ls-files

Optionen:

  • --exclude-standardBetrachten Sie alle .gitignoreDateien.
  • -o Ignorieren Sie nicht bereitgestellte Änderungen nicht.
  • -i Nur ignorierte Dateien ausgeben.
  • --directory Geben Sie den Verzeichnispfad nur aus, wenn das gesamte Verzeichnis ignoriert wird.

Das einzige, was ich ignorieren musste, war .git.

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

4
das funktioniert nicht Es schließt die erste Datei aus dem Unterbefehl git aus und behandelt den Rest als Teil der SRC-Liste. das funktioniert: rsync -azP --exclude-from="$(git -C SRC ls-files --exclude-standard -oi --directory > /tmp/excludes; echo /tmp/excludes)" SRC DEST
Marathon

2
Dies ist die einzige Methode, die funktioniert, wenn Sie sowohl Ausschluss- als auch Einschlusszeilen in Ihrer .gitignore(dh Zeilen, die mit beginnen !) haben. Es werden auch Dateien synchronisiert, die Sie --forceIhrem Repo hinzugefügt haben, was normalerweise eine gute Sache ist.
Ostrokach

1
In der Tat funktioniert diese Antwort NICHT, also schrieb ich eine, die funktioniert: stackoverflow.com/a/50059607/99834
sorin

6

wie wäre es rsync --exclude-from='path/.gitignore' --exclude-from='path/myignore.txt' source destination?
Es hat bei mir funktioniert.
Ich glaube, Sie können auch mehr --exclude-fromParameter haben.


3
Dies funktioniert insofern, als Ihre .gitignoreDateien zufällig eine mit kompatible Syntax verwenden rsync.
Jesse Glick

@JesseGlick ist richtig, rsync kann keine .gitignore-Dateien analysieren, siehe Workover stackoverflow.com/a/50059607/99834.
Sorin

6

2018 Lösung bestätigt

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 

Details: --exclude-fromist obligatorisch anstelle von --exclude, da der wahrscheinliche Fall, dass die Ausschlussliste nicht als Argument analysiert wird. Ausschließen von erfordert eine Datei und kann nicht mit Pipes arbeiten.

Die aktuelle Lösung speichert die Ausschlussdatei im Ordner .git, um sicherzustellen, dass sie keine Auswirkungen hat, git statuswährend sie in sich geschlossen bleibt . Wenn Sie möchten, können Sie gerne / tmp verwenden.


3
Dies scheint zu funktionieren, wenn Sie ein bestimmtes Git-Repository haben, das Sie synchronisieren möchten - das SRChier -, aber nicht für das ursprüngliche Problem, das ich angegeben habe. Hierbei handelt es sich um ein weitläufiges Verzeichnis mit Tausenden von Git-Repositorys als Unterverzeichnisse in verschiedenen Tiefen, von denen viele vorhanden sind eigenwillig .gitignores.
Jesse Glick

1
Wenn Sie eine Shell mit Unterstützung für die Prozessersetzung (bash, zsh usw.) verwenden, können Sie--exclude-from=<(git -C SRC ls-files --exclude-standard -oi --directory)
Roland W

3

Für Quecksilber könnten Sie verwenden

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

um die Liste der Dateien zu sammeln, die aufgrund von .hgignore- Einschränkungen NICHT unter Quecksilberkontrolle stehen , und dann auszuführen

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

um alle Dateien außer den ignorierten zu synchronisieren. Beachten Sie das Flag -m in rsync, das leere Verzeichnisse von der Synchronisierung ausschließt, da der hg-Status -i nur ausgeschlossene Dateien auflistet, keine Verzeichnisse


2

Versuche dies:

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

Es kann alle Dateien in das Remote-Verzeichnis kopieren, mit Ausnahme der Dateien in '.gitignore', und Dateien löschen, die sich nicht in Ihrem aktuellen Verzeichnis befinden.


1

Auf der rsyncManpage zusätzlich zur Standardliste der Dateimuster:

Dateien, die in einem $ HOME / .cvsignore aufgeführt sind, werden der Liste hinzugefügt, und alle Dateien, die in der Umgebungsvariablen CVSIGNORE aufgeführt sind

Meine $ HOME / .cvsignore-Datei sieht also folgendermaßen aus:

.git/
.sass-cache/

um .git und die von Sass generierten Dateien auszuschließen .


2
Im Gegenteil, ich möchte definitiv .git/Verzeichnisse einbinden, vielleicht sogar stärker als die Arbeitskopie. Was ich ausschließen möchte, sind Build-Produkte.
Jesse Glick

Diese Einstellung ist auch nicht portierbar. Es ist pro Benutzer, nicht pro Projekt.
VasiliNovikov

@ JesseGlick Ich stimme dir zu, dass .git / dirs enthalten bleiben. Da Git ein verteilter SCM ist, ist es wichtig, das gesamte lokale Repository zu sichern.
Johan Boulé

1 / Der rsyncin dieser Antwort angegebene Satz aus der Manpage beschreibt die --cvs-excludeOption, daher müssen Sie sie explizit verwenden. 2 / Sie können .cvsignoreDateien in jedem Verzeichnis erstellen , die projektspezifisch ignoriert werden. Diese werden ebenfalls gelesen. 3 / .gitwird --cvs-excludelaut Handbuch bereits ignoriert, wenn Sie es verwenden , sodass es $HOME/.cvsignoreüberflüssig erscheint , es zu verwenden .
Niavlys

1

Ich hatte eine Reihe sehr großer .gitignoreDateien und keine der "reinen Rsync" -Lösungen funktionierte für mich. Ich habe dieses rsync-Wrapper-Skript geschrieben , es respektiert die .gitignoreRegeln (einschließlich !Ausnahmen .gitignoreim Stile- Stil und Dateien in Unterverzeichnissen) vollständig und hat für mich wie ein Zauber funktioniert.


Ich versuche dies über locate -0e .gitignore | (while read -d '' x; do process_git_ignore "$x"; done), habe aber viele Probleme. Dateien im selben Verzeichnis wie .gitignorenicht korrekt vom Verzeichnisnamen mit getrennt /. Leerzeilen und Kommentare falsch interpretiert. Drosselt .gitignoreDateien in Pfaden mit Leerzeichen (egal, was /opt/vagrant/embedded/gems/gems/rb-fsevent-0.9.4/spec/fixtures/custom 'path/.gitignoreaus dem vagrantPaket für Ubuntu hervorgeht). Vielleicht besser als Perl-Skript.
Jesse Glick

@ JesseGlick Ich bin mir nicht sicher, warum Sie die Funktion innerhalb des Skripts aufrufen. Es ist als Ersatz für Drop-In gedacht rsync, aus dem speziellen Grund, dass der Umgang mit Anführungszeichen / Leerzeichen so schmerzhaft ist. Wenn Sie ein Beispiel für eine gsyncfehlerhafte Befehlszeile und die damit verbundenen .gitignoreDateien haben, würde ich gerne einen genaueren Blick darauf werfen.
Cobbzilla

Ich brauche rsyncein ganzes Dateisystem mit verschiedenen Git-Repositorys. Möglicherweise funktioniert Ihr Skript gut für den Fall der Synchronisierung eines einzelnen Repositorys.
Jesse Glick

1
ja definitiv. Entschuldigung, das habe ich nicht klargestellt. Mit diesem Skript müssten Sie es einmal pro Git-Repo aus dem Repo-Verzeichnis aufrufen.
Cobbzilla

0

Lesen Sie den Abschnitt MERGE-FILES FILTER RULES in rsync (1).

Es scheint möglich zu sein, eine rsync --filter-Regel zu erstellen, die .gitignore-Dateien enthält, wenn die Verzeichnisstruktur durchlaufen wird.


0

Anstatt Ausschlussfilter zu erstellen, können git ls-filesSie jede Datei für rsync auswählen:

#!/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

Dies funktioniert auch dann, wenn durch git ls-filesZeilenumbrüche getrennte Pfade zurückgegeben werden. Funktioniert wahrscheinlich nicht, wenn Sie versionierte Dateien mit Leerzeichen in den Dateinamen haben.


0

Alternativen:

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

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

(rsync versteht .gitignore nur teilweise)


0

Kurze Antwort

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

Parameter Bedeutung:

-r: rekursiv

--info=...: Fortschritt anzeigen

--filter=...: Ausschließen durch die in der .gitignore-Datei aufgeführten Regeln

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.