.gitignore Syntax: bin vs bin / vs. bin / * vs. bin / **

88

Was ist der Unterschied zwischen dem Hinzufügen bin, bin/, bin/*und bin/**in meiner .gitignore - Datei? Ich habe andere .gitignore-Dateien verwendet bin/, aber in der Eclipse-Datei werden Doppel- und Einzelstern sogar so zusammen verwendet: Was ist damit los?) Ich sehe, dass die ersten beiden Muster ebenfalls weit verbreitet sind. Kann jemand bitte die Unterschiede zwischen den drei erklären? tmp/**/*

chandsie
quelle
4
@unutbu: Die akzeptierte Antwort auf diese Frage ist offenbar umstritten. Einer der Top-Kommentare behauptet, die Antwort sei tatsächlich ein vollständiger Mythos.
Chandsie
Das Verhalten ist vollständig in der Manpage angegeben, und ich bin sicher, dass es hier (oder zehn) eine Frage / Antwort gibt, die all diese Informationen enthält.
Cascabel
3
In Bezug auf **: stackoverflow.com/questions/1470572/…
Cascabel

Antworten:

85

binstimmt mit allen Dateien oder Verzeichnissen mit dem Namen 'bin' überein .

bin/stimmt mit allen Verzeichnissen mit dem Namen 'bin' überein , was praktisch den gesamten Inhalt bedeutet, da Git Verzeichnisse nicht alleine verfolgt.

bin/*stimmt mit allen Dateien und Verzeichnissen direkt in einem überein bin/. Dies verhindert, dass Git automatisch Dateien in seinen Unterverzeichnissen findet. Wenn jedoch beispielsweise ein bin/fooUnterverzeichnis erstellt wird, stimmt diese Regel nicht mit foodem Inhalt überein .

bin/**Entspricht allen Dateien und Verzeichnissen in einem beliebigen bin/Verzeichnis und allen Unterverzeichnissen.

Das Wort "any" ist hier kritisch, da Regeln nicht relativ zum Repository-Stamm sind und an einer beliebigen Stelle im Dateisystembaum gelten. Sie müssen Regeln mit einem /(oder nicht !/zu ignorierenden) Zeichen beginnen, dh dem Stammverzeichnis des Repositorys, nicht dem Stammverzeichnis des Systems, um nur dem zu entsprechen, was beabsichtigt war.

WARNUNG: Sie sollten niemals Regeln verwenden , wie dir/*, /dir/**etc. allein , wenn Sie auch etwas un-ignorieren , die in diesem Verzeichnis existiert . Auslassen das Sternchen oder Sie könnten dauerhaft eine Menge Daten verlieren aus bestimmten Anrufungen git gc, git stashund vieles mehr.

Ich weiß nicht wirklich, was ich tmp/**/*tun soll. Ich dachte anfangs, es könnte verwendet werden, um Dateien in den Unterverzeichnissen von, tmp/aber nicht Dateien, die direkt in sich tmp/selbst vorhanden sind, abzugleichen. Ein einfacher Test scheint jedoch darauf hinzudeuten, dass alle darin enthaltenen Dateien ignoriert werden tmp/.

Siddhartha Reddy
quelle
10
Nur um zu verdeutlichen, was ist der Unterschied zwischen bin/und bin/**?
Chandsie
1
Ich vermute bin/, dass das bin-Verzeichnis ignoriert wird, während bin/**das bin-Verzeichnis, aber keiner seiner Inhalte enthalten wird
Robin Winslow
1
Das scheint mit Siddharthas Antwort unvereinbar zu sein. Wenn Sie aus der Antwort ziehen, bin/wird das Verzeichnis selbst (einschließlich aller Unterverzeichnisse und Dateien) bin/**ignoriert , während alle Dateien im bin-Verzeichnis und seinen Unterverzeichnissen ignoriert werden, nicht jedoch das bin-Verzeichnis selbst. Ob das stimmt oder nicht, weiß ich nicht.
Christopher Berman
3
Beachten Sie, dass Sie (in nachfolgenden Zeilen) bin/** \n !bin/*(da ich nicht sehen kann, wie ein Zeilenumbruch in Mini-Markdown
erzwungen wird
9
Diese Antwort ist in vielerlei Hinsicht falsch. Erstens verfolgt git keine Verzeichnisse, sodass ein .gitignore-Eintrag immer nur mit Verzeichnisinhalten übereinstimmen kann, niemals mit einem Verzeichnis als solchem. Zweitens binstimmt sowohl eine Datei mit dem Namen bin als auch der Inhalt des binOrdners überein . Drittens bin/* stimmt mit allen Dateien in seinen Unterverzeichnissen überein . Habt ihr das überhaupt getestet?
ThomasR
45

binund bin/unterscheiden sich nur darin, dass letztere nur mit einem Verzeichnis übereinstimmen.

bin/**/*ist das gleiche wie bin/**(anscheinend seit 1.8.2, gemäß der Antwort von @ VonC).

Das Knifflige, dass ich gerade eine Stunde damit verbracht habe, mir die Haare auszureißen, ist das bin/und bin/**ist nicht ganz dasselbe! Da der frühere das Verzeichnis als Ganzes ignoriert und der letztere jede der darin enthaltenen Dateien ignoriert und git in fast allen Fällen keine Verzeichnisse interessiert, gibt es normalerweise keinen Unterschied. Wenn Sie jedoch versuchen !, einen Unterpfad zu ignorieren, werden Sie feststellen, dass git (ahem) ihn ignoriert , wenn Sie das übergeordnete Verzeichnis ignoriert haben! (wieder eher als der Verzeichnisinhalt)

Dies wird am Beispiel am deutlichsten. Für ein neu initiiertes Repository, das wie folgt eingerichtet ist:

$ cat .gitignore
ignored-file
or-dir
dir-only/
!dir-only/cant-reinclude
dir-contents/**
!dir-contents/can-reinclude

$ mkdir or-dir dir-only dir-contents

$ touch file ignored-file or-dir/ignored-file dir-only/cant-reinclude dir-contents/can-reinclude

Die folgenden nicht verfolgten Dateien existieren:

$ git ls-files --other
.gitignore
dir-contents/can-reinclude
dir-only/cant-reinclude
file
ignored-file
or-dir/ignored-file

Sie können jedoch sehen, dass die folgenden Dateien nicht ignoriert werden:

$ git ls-files --other --exclude-standard
.gitignore
dir-contents/can-reinclude
file

Und wenn Sie versuchen hinzuzufügen, erhalten Sie:

$ git add dir-only/cant-reinclude
The following paths are ignored by one of your .gitignore files:
dir-only/cant-reinclude
Use -f if you really want to add them.
fatal: no files added

Ich halte dieses Verhalten für einen Fehler. (Das ist alles an git version 1.8.4.msysgit.0)

Simon Buchan
quelle
1
+1 in der Tat. Sie sollten in Betracht ziehen, einen tatsächlichen Fehlerbericht zu diesem Thema einzureichen, da das Verhalten unerwartet erscheint.
Chandsie
1
Genau mein Anwendungsfall. Vielen Dank!
Sebastian Graf
3
Das unterschiedliche Verhalten von dir/und dir/**re. Das !Nicht -Ignorieren mit geschieht, weil "Es ist nicht möglich, eine Datei erneut einzuschließen, wenn ein übergeordnetes Verzeichnis dieser Datei ausgeschlossen ist" [Quelle ]. Verwirrend, aber aus Leistungsgründen gemacht. Siehe eine verwandte SO-Frage .
Tanius
23

Beachten Sie, dass git streng genommen keine Verzeichnisse verfolgt, sondern nur Dateien. Es ist daher nicht möglich, ein Verzeichnis hinzuzufügen, sondern nur dessen Inhalt .

Im Zusammenhang mit .gitignore gibt git jedoch vor, Verzeichnisse nur aus dem Grund zu verstehen, dass

Es ist nicht möglich, eine Datei erneut einzuschließen, wenn ein übergeordnetes Verzeichnis dieser Datei ausgeschlossen ist.
https://git-scm.com/docs/gitignore#_pattern_format

Was bedeutet das für die Ausschlussmuster? Lassen Sie uns sie im Detail durchgehen:

bin

Dies wird ignoriert

  • Dateien benannt bin .
  • den Inhalt der genannten Ordner bin

Sie können ignorierte binDateien und Ordner auf die Whitelist setzen, indem Sie nachfolgende !Einträge hinzufügen. Sie können jedoch den Inhalt der genannten Ordner nicht auf die Whitelist setzenbin

bin

!bin/file_in_bin # has no effect, since bin/ is blacklisted!
!bin/* # has no effect, since bin/ is blacklisted!
!file_in_bin # has no effect, since bin/ is blacklisted!

!bin # this works

bin/

Wie oben, außer dass die genannten Dateien nicht übereinstimmen bin. Durch Hinzufügen eines Trailing /wird git angewiesen, nur mit Verzeichnissen übereinzustimmen.

bin/*

Dies wird ignoriert

  • Dateien in einem Ordner mit dem Namenbin
  • Inhalt der direkten Unterordner der genannten Ordner bin
bin/*  # blacklists bin/file_in_bin and bin/subfolder/

!bin/subfolder/file_in_sub # has no effect, since bin/subfolder is blacklisted!
!bin # whitelists files named bin/bin, since bin/ itself is not blacklisted
!bin/ # has no effect, since bin/ itself is not blacklisted


!bin/file_in_bin # works since bin/ itself is not blacklisted
!file_in_bin # works too
!bin/subfolder # works (so implicitly whitelists bin/subfolder/file_in_sub)
!bin/subfolder/ # works just as well
!bin/* # works for file_in_bin and subfolder/

bin/**

Dies wird ignoriert

  • Inhalt von bin
  • Inhalt von Unterordnern (beliebige Verschachtelungsebene) innerhalb bin
bin/**  # blacklists bin/file_in_bin and
        # bin/subfolder/ and bin/subfolder/file_in_sub and
        # bin/subfolder/2/ and bin/subfolder/2/file_in_sub_2

!bin/subfolder/file_in_sub # has no effect, since bin/subfolder is blacklisted
!bin/subfolder/2/ # has no effect, since bin/subfolder is blacklisted
!bin/subfolder/2/file_in_sub_2 # has no effect, since bin/subfolder is blacklisted

!bin/subfolder # works only in combinations with other whitelist entries,
               # since all contents of subfolder are blacklisted (1)

!bin/file_in_bin # works since bin itself is not blacklisted
!bin/* # works for file_in_bin and subfolder; see (1)
ThomasR
quelle
9

Ich habe gerade ein neues Repo gemacht und einige Dinge ausprobiert. Hier sind meine Ergebnisse:

NEUE ERGEBNISSE

Git Version 2.10.1.windows.1

  1. Initialisieren Sie ein fast leeres Repo. Nur die README-Datei
  2. Füllen Sie das binVerzeichnis mehrere Ebenen tief
    • bin.txt
    • Test.txt
    • bin/a/b/bin.txt
    • bin/a/b/Test.txt
    • bin/a/bin/bin.txt
    • bin/a/bin/Test.txt
    • bin/a/bin.txt
    • bin/a/Test.txt
    • bin/bin.txt
    • bin/Test.txt
  3. In binzu gitignore: Ergebnisse
    • Alles unter dem binVerzeichnis (und tiefer) wird jetzt ignoriert
    • Die Root-Ebene wird nicht ignoriert (/bin.txt und /Test.txt werden weiterhin angezeigt).
  4. Bearbeiten binzu bin/in der gitignore: Ergebnisse
    • Keine Änderung
  5. Bearbeiten bin/zubin/*
    • Keine Änderung
  6. Bearbeiten bin/*zubin/**
    • Keine Änderung
  7. Bearbeiten bin/**zubin/**/
    • bin/bin.txtund bin/Test.txtwerden nicht länger ignoriert
  8. Bearbeiten bin/**/zubin/**/*
    • bin/bin.txtund bin/Test.txtwerden wieder ignoriert

ALTE ERGEBNISSE

Git-Version: 2.7.0.windows.1

  1. Initialisieren Sie ein fast leeres Repo. Nur die README-Datei
  2. Füllen Sie das binVerzeichnis mehrere Ebenen tief
    • bin/a/b/Test.txt
    • bin/a/bin/Test.txt
    • bin/a/Test.txt
    • bin/Test.txt
  3. In binzu gitignore: Ergebnisse
    • Alles unter dem binVerzeichnis (und tiefer) wird jetzt ignoriert
  4. Bearbeiten binzu bin/in der gitignore: Ergebnisse
    • Alles unter dem binVerzeichnis (und tiefer) wird immer noch ignoriert (keine Änderung)
  5. Bearbeiten bin/zubin/*
    • Alles unter dem binVerzeichnis (und tiefer) wird immer noch ignoriert (keine Änderung)
  6. Bearbeiten bin/*zubin/**
    • Alles unter dem binVerzeichnis (und tiefer) wird immer noch ignoriert (keine Änderung)
  7. Bearbeiten bin/**zubin/**/
    • bin/Test.txt wird nicht mehr ignoriert
  8. Bearbeiten bin/**/zubin/**/*
    • Alles unter dem binVerzeichnis (und tiefer) wird wieder ignoriert
Joe Phillips
quelle
1
Dies ist ein guter Test. Ich denke, dass das Umbenennen von text.txt in bin.txt einige wichtige Unterschiede besser zeigen würde. Wenn Sie dies tun würden, würde ich für diese Antwort stimmen.
Matt Johnson
@ MattJohnson True ... leider bin ich im Moment auf einer neueren Git-Version
Joe Phillips
@ MattJohnson Ich bin endlich dazu gekommen
Joe Phillips
8

Beachten Sie, dass sich das ' **' in Kombination mit einem Unterverzeichnis ( **/bar) von seinem Standardverhalten geändert haben muss, da in der Versionshinweis für git1.8.2 jetzt Folgendes erwähnt wird:

Die Muster in .gitignoreund .gitattributesDateien können **/ein Muster haben , das 0 oder mehr Ebenen des Unterverzeichnisses entspricht.

ZB " foo/**/bar" entspricht " bar" in " foo" selbst oder in einem Unterverzeichnis von " foo".


Die Regel, an die Sie sich erinnern sollten (und die hilft, den Unterschied der Absichten hinter dieser Syntax zu verstehen), lautet:

Es ist nicht möglich, eine Datei erneut einzuschließen, wenn ein übergeordnetes Verzeichnis dieser Datei ausgeschlossen ist.


Wenn Sie Dateien aus einem Unterordner eines Ignorierordners f ausschließen möchten, gehen Sie normalerweise wie folgt vor:

f/**
!f/**/
!f/a/sub/folder/someFile.txt

Das ist:

  • Wenn die erste Regel wäre, würde f/der Ordner f/ignoriert und die folgenden Regeln spielen fkeine Rolle.
  • f/**Erzielen Sie dasselbe wie f/, ignorieren Sie jedoch alle Unterelemente (Dateien und Unterordner).
    Dies gibt Ihnen die Möglichkeit, die Unterordner auf die Whitelist zu setzen (vom Gitignore auszuschließen) : !f/**/.
  • Da alle fUnterordner werden nicht ignoriert, können Sie eine Regel hinzufügen , eine Datei ausschließen ( !f/a/sub/folder/someFile.txt)
VonC
quelle
Wie beantwortet dies die Frage?
ThomasR
0

Es gibt noch einen weiteren Unterschied zwischen bin/*und bin/.

bin/stimmt überein foo/bin/test.txt(wie erwartet), aber bin/*nicht, was seltsam erscheint, aber es ist dokumentiert: https://git-scm.com/docs/gitignore

"Documentation / *. Html" entspricht "Documentation / git.html", jedoch nicht "Documentation / ppc / ppc.html" oder "tools / perf / Documentation / perf.html".

Der Grund dafür scheinen folgende Regeln zu sein:

  • Wenn das Muster mit einem Schrägstrich endet, wird es zum Zweck der folgenden Beschreibung entfernt…

  • Wenn das Muster keinen Schrägstrich / enthält, behandelt Git es als Shell-Glob-Muster und prüft, ob eine Übereinstimmung mit dem Pfadnamen in Bezug auf den Speicherort der .gitignore-Datei vorliegt.

  • Andernfalls behandelt Git das Muster als Shell-Glob, der für den Verbrauch durch fnmatch (3) mit dem Flag FNM_PATHNAME geeignet ist.

Wenn das Muster mit einem Schrägstrich endet, wird der Schrägstrich entfernt und als Shell-Glob-Muster behandelt. In diesem Fall binstimmt er überein foo/bin/test.txt. Wenn es mit endet /*, wird der Schrägstrich nicht entfernt und an fnmatch übergeben, das in Unterverzeichnissen nicht übereinstimmt.

Dies gilt jedoch nicht für foo/bin/und foo/bin/*, da der nachfolgende Schrägstrich auch nach dem Entfernen foo/bin/noch einen Schrägstrich enthält, sodass er als fnmatch-Muster und nicht als Glob behandelt wird. Dh es wird nicht passenbar/foo/bin/test.txt

user1431317
quelle