.gitignore Ordner ausschließen, aber bestimmten Unterordner einschließen


964

Ich habe den Ordner, application/den ich dem hinzufüge .gitignore. Innerhalb des application/Ordners befindet sich der Ordner application/language/gr. Wie kann ich diesen Ordner einschließen?

Ich habe es versucht

application/
!application/language/gr/

ohne Glück ...


1
Hoffentlich wurde die .gitignoreDokumentation zum " Musterformat" gerade klarer (Dezember 2013). Siehe meine Antwort unten
VonC

Meine Lieblingsfrage und -antwort, die sowohl zu Favoriten als auch zu Browser-Lesezeichen hinzugefügt wurde.
Codekiddy

Antworten:


1613

Wenn Sie ausschließen application/, wird immer alles darunter ausgeschlossen (auch wenn ein späteres negatives Ausschlussmuster („unignore“) möglicherweise mit etwas unter übereinstimmt application/).

Um das zu tun, was Sie wollen, müssen Sie jedes übergeordnete Verzeichnis von allem, was Sie "abmelden" möchten, "abmelden". Normalerweise schreiben Sie Regeln für diese Situation paarweise: Ignorieren Sie alles in einem Verzeichnis, aber nicht ein bestimmtes Unterverzeichnis.

# you can skip this first one if it is not already excluded by prior patterns
!application/

application/*
!application/language/

application/language/*
!application/language/gr/

Hinweis
Das Nachlaufen /*ist signifikant:

  • Das Muster dir/schließt ein Verzeichnis mit dem Namen dirund (implizit) alles darunter aus.
    Mit dir/wird Git niemals etwas unter betrachten dirund daher niemals eines der "Ausschluss" -Muster auf etwas unter anwenden dir.
  • Das Muster dir/*sagt nichts über sich dirselbst aus; es schließt einfach alles unter aus dir. Mit verarbeitet dir/*Git den direkten Inhalt von dirund gibt anderen Mustern die Möglichkeit, einen Teil des Inhalts ( !dir/sub/) auszuschließen .

12
Sind die nachgestellten Sternchen signifikant? Wenn ja, was ist der Unterschied in der Bedeutung? Gemäß dem in der gitignore- Dokumentation beschriebenen Algorithmus entspricht das Ende mit einem abschließenden Schrägstrich einem Verzeichnis und Pfaden unter diesem Verzeichnis. Das Beenden mit einem Sternchen würde dann als Glob-Muster behandelt. Das Experimentieren zeigt, dass die Sternchenvariante funktioniert, aber nicht die, die nur mit einem abschließenden Schrägstrich endet. Ich würde gerne verstehen, warum das so ist.
seh

123
@seh: Ja, das Trailing /*ist signifikant. Wenn ein Verzeichnis ausgeschlossen ist, wird Git niemals den Inhalt dieses Verzeichnisses anzeigen. Das Muster dir/schließt ein Verzeichnis mit dem Namen dirund (implizit) alles darunter aus. Das Muster dir/*sagt nichts über sich dirselbst aus; es schließt einfach alles unter aus dir. Mit dir/wird Git niemals etwas unter betrachten dirund daher niemals eines der "Ausschluss" -Muster auf etwas unter anwenden dir. Mit verarbeitet dir/*Git den direkten Inhalt von dirund gibt anderen Mustern die Möglichkeit, einen Teil des Inhalts ( !dir/sub/) auszuschließen .
Chris Johnsen

7
Ah, das erklärt es. Egal wie oft ich die Gitignore- Dokumentation gelesen habe , ich habe nie verstanden, wann die zurückgesetzten Muster nicht funktionieren. Mit Ihrer Erklärung ist es jetzt klar. Die gitignore- Dokumentation benötigt einen Abschnitt "Rezept", um zu erklären, wie dies gemacht wird.
seh

8
Ich konnte das nicht ganz zum Laufen bringen (verrückte .gitignore-Datei!), Also habe ich die Dateien stattdessen zwangsweise hinzugefügt, nachdem ich sie in das gewünschte Verzeichnis verschoben hatte. git add -f .
K0D4

2
Beachten Sie, dass Sie sich nicht auf die Ausgabe von verlassen können. Dies git statussagt Ihnen nur, dass das Verzeichnis der obersten Ebene hinzugefügt wird. Führen Sie stattdessen ein git addVerzeichnis der obersten Ebene aus und git statuslisten Sie dann (hoffentlich) die Teilmenge der Dateien auf, die mit dem Muster übereinstimmen.
Matthew Strawbridge

136

Commit 59856de von Karsten Blees (kblees) für Git 1.9 / 2.0 (Q1 2014) verdeutlicht diesen Fall:

gitignore.txt: Klären Sie den rekursiven Charakter ausgeschlossener Verzeichnisse

Ein optionales Präfix " !", das das Muster negiert; Alle übereinstimmenden Dateien, die von einem vorherigen Muster ausgeschlossen wurden, werden wieder aufgenommen.

Es ist nicht möglich, eine Datei erneut einzuschließen, wenn ein übergeordnetes Verzeichnis dieser Datei ausgeschlossen ist. ( *)
( *: Sofern bestimmte Bedingungen in Git 2.8+ nicht erfüllt sind, siehe unten)
Git listet aus Leistungsgründen keine ausgeschlossenen Verzeichnisse auf, sodass Muster für enthaltene Dateien keine Auswirkungen haben, unabhängig davon, wo sie definiert sind.

Setzen Sie einen Backslash (" \") vor das erste " !" für Muster, die mit einem Literal " !" beginnen, z. B. " \!important!.txt".

Beispiel zum Ausschließen von allem außer einem bestimmten Verzeichnis foo/bar(beachten Sie /*, dass der Platzhalter ohne Schrägstrich auch alles darin ausschließt foo/bar):

 --------------------------------------------------------------
     $ cat .gitignore
     # exclude everything except directory foo/bar
     /*
     !/foo
     /foo/*
     !/foo/bar
 --------------------------------------------------------------

In Ihrem Fall:

application/*
!application/**/
application/language/*
!application/language/**/
!application/language/gr/**

Sie müssen zuerst Ordner auf die weiße Liste setzen, bevor Sie Dateien in einem bestimmten Ordner auf die weiße Liste setzen können.


Update Februar / März 2016:

Beachten Sie, dass es mit git 2.9.x / 2.10 (Mitte 2016?) Möglicherweise möglich ist, eine Datei erneut einzuschließen, wenn ein übergeordnetes Verzeichnis dieser Datei ausgeschlossen wird, wenn der wieder aufgenommene Pfad keinen Platzhalter enthält .

Nguyễn Thái Ngọc Duy ( pclouds) versucht, diese Funktion hinzuzufügen:

Mit Git 2.9+ hätte dies tatsächlich funktionieren können, wurde aber letztendlich rückgängig gemacht:

application/
!application/language/gr/

Ich habe versucht, die aktualisierte Wiedereinschlusssyntax zu verwenden, die am Ende Ihrer Antwort auf git für Windows veröffentlicht wurde, v2.8.1.windows.1aber es scheint nicht zu funktionieren :(
David Hancock

1
@ DavidHancock Entschuldigung, ich habe die Antwort bearbeitet: Dies ist noch nicht verfügbar.
VonC

1
@ DavidHancock mich auch: das sind mehr als 13 Stack Overflow-Antworten, die ich mehrmals bearbeiten musste!
VonC

5
Git 2.9 wurde gestern veröffentlicht. Das Bestätigen des in der Antwort erwähnten application/+ -Musters !application/language/gr/funktioniert wie erwartet.
Ray Shan

1
@RayShan Seltsam: Ich habe gesehen, dass das Revert-Commit diese Funktion abbricht, aber ich habe es nicht gesehen (und der Versionshinweis github.com/git/git/blob/master/Documentation/RelNotes/2.9.0.txt erwähnt dies nicht). jedes Commit zur Verbesserung der .gitignore-Regeln.
VonC

52

Die Antwort von @Chris Johnsen ist großartig, aber mit einer neueren Version von Git (1.8.2 oder höher) gibt es ein doppeltes Sternchenmuster, das Sie für eine etwas kürzere Lösung nutzen können:

# assuming the root folder you want to ignore is 'application'
application/**/*

# the subfolder(s) you want to track:
!application/language/gr/

Auf diese Weise müssen Sie das übergeordnete Verzeichnis des Unterordners, den Sie verfolgen möchten, nicht "aufheben".


Mit Git 2.17.0 (nicht sicher, wie früh vor dieser Version. Möglicherweise zurück zu 1.8.2) funktioniert die Verwendung des **Musters in Kombination mit Ausschlüssen für jedes Unterverzeichnis, das zu Ihren Dateien führt. Zum Beispiel:

# assuming the root folder you want to ignore is 'application'
application/**

# Explicitly track certain content nested in the 'application' folder:
!application/language/
!application/language/gr/
!application/language/gr/** # Example adding all files & folder in the 'gr' folder
!application/language/gr/SomeFile.txt # Example adding specific file in the 'gr' folder

9
Leider schlägt dies fehl (Git 1.8.4.msysgit.0), da das Muster **mit null Unterordnern *übereinstimmen kann languageund es übereinstimmt und ausschließt, wodurch die Aufnahme von verhindert wird gr. Die gesamte Kette der Eltern, die @Chris Johnson empfiehlt, scheint immer noch notwendig zu sein.
Sean Gugler

3
Klingt perfekt, funktioniert aber bei Git 2.3.7 nicht ... /www/**/* !/www/config.xml !/www/resconfig.xml und das res-Verzeichnis werden immer noch ignoriert.
Rob

@Rob müssen Sie auch hinzufügen !/www/res/. Sie können das folder/**/*Muster verwenden, müssen jedoch weiterhin Ausschlüsse für jedes Unterverzeichnis hinzufügen, das Sie hinzufügen möchten. Es ist immer noch kürzer und lesbarer als die Ignorier- / Ausschluss-Kombination.
Ben Kane

Ich weiß, dass das ein alter Kommentar ist, aber falls Sie neugierig sind. Ich habe der Antwort eine Bearbeitung hinzugefügt, die diesen Ansatz dokumentiert.
Ben Kane

21

Es gibt eine Reihe ähnlicher Fragen dazu, daher werde ich das posten, was ich zuvor geschrieben habe:

Die einzige Möglichkeit, dies auf meiner Maschine zum Laufen zu bringen, bestand darin, es folgendermaßen zu tun:

# Ignore all directories, and all sub-directories, and it's contents:
*/*

#Now ignore all files in the current directory 
#(This fails to ignore files without a ".", for example 
#'file.txt' works, but 
#'file' doesn't):
*.*

#Only Include these specific directories and subdirectories:
!wordpress/
!wordpress/*/
!wordpress/*/wp-content/
!wordpress/*/wp-content/themes/
!wordpress/*/wp-content/themes/*
!wordpress/*/wp-content/themes/*/*
!wordpress/*/wp-content/themes/*/*/*
!wordpress/*/wp-content/themes/*/*/*/*
!wordpress/*/wp-content/themes/*/*/*/*/*

Beachten Sie, wie Sie Inhalte für jede Ebene, die Sie einschließen möchten, explizit zulassen müssen. Wenn ich also Unterverzeichnisse 5 tief unter Themen habe, muss ich das noch formulieren.

Dies stammt aus @ Yarins Kommentar hier: https://stackoverflow.com/a/5250314/1696153

Dies waren nützliche Themen:

Ich habe es auch versucht

*
*/*
**/**

und **/wp-content/themes/**

oder /wp-content/themes/**/*

Nichts davon hat auch für mich funktioniert. Viel Versuch und Irrtum!


1
Hinweis: Denken Sie daran, dass die Reihenfolge auch in einer Gitignore-Datei von Bedeutung ist. Stellen Sie daher sicher, dass Sie Ihre !Regeln unten einfügen .
Starbeamrainbowlabs


8

Der einfachste und wahrscheinlich beste Weg ist, die Dateien manuell hinzuzufügen (im Allgemeinen hat dies Vorrang vor .gitignoreRegeln im Stil):

git add /path/to/module

Möglicherweise möchten Sie sogar die -N Absicht, ein Flag hinzuzufügen , um vorzuschlagen, dass Sie sie hinzufügen, jedoch nicht sofort. Ich mache das oft für neue Dateien, für die ich noch nicht bereit bin.


Dies ist eine Kopie einer Antwort, die auf einer möglicherweise doppelten Qualitätssicherung veröffentlicht wurde. Ich reposte es hier, um die Sichtbarkeit zu verbessern. Ich finde es einfacher, keine Gitignore-Regeln durcheinander zu bringen.


2
Danke für diese Antwort. Ich musste -f hinzufügen, da es in meinem .gitignore so ist: git add -f Pfad / zu / Datei
jasonflaherty

6

Also, da viele Programmierer Knoten verwenden. Der Anwendungsfall, der diese Frage erfüllt, besteht darin, node_modulesaußer einem Modul auszuschließen, module-azum Beispiel:

!node_modules/

node_modules/*
!node_modules/module-a/

2
Funktioniert nicht für die Git-Version 2.10.2.windows.1.
Sebastian

1
Für Git Version 2.10.2 folgen Sie dieser Antwort
Nalexn

👌 großartig 👋 👋.
Abdennour TOUMI

6

Fügen Sie eine zusätzliche Antwort hinzu:

!/.vs/              <== include this folder to source control, folder only, nothing else
/.vs/*              <== but ignore all files and sub-folder inside this folder
!/.vs/ProjectSettings.json <== but include this file to source control
!/.vs/config/       <== then include this folder to source control, folder only, nothing else
!/.vs/config/*      <== then include all files inside the folder

Hier ist das Ergebnis:

Geben Sie hier die Bildbeschreibung ein


2
Dies war die nützlichste Antwort für mich, da die Grafik half. Vielen Dank!
Joel Murphy

4

Insbesondere für die älteren Git-Versionen funktionieren die meisten Vorschläge nicht so gut. In diesem Fall würde ich einen separaten .gitignore in das Verzeichnis einfügen, in das der Inhalt unabhängig von anderen Einstellungen aufgenommen werden soll, und dort zulassen, was benötigt wird.

Zum Beispiel: /.gitignore

# ignore all .dll files
*.dll

/dependency_files/.gitignore

# include everything
!*

Alles in / dependency_files (sogar DLL-Dateien) ist also in Ordnung.


4

Ich habe hier einen ähnlichen Fall gefunden, in dem in Laravel standardmäßig .gitignorealle mit Asterix verwendeten ignoriert werden und dann das öffentliche Verzeichnis überschrieben wird.

*
!public
!.gitignore

Dies ist nicht ausreichend, wenn Sie auf das OP-Szenario stoßen.

Wenn Sie eine bestimmte Unterordner begehen wollen public, sagen für zB in Ihrem public/productsVerzeichnis möchten Sie Dateien enthalten , die einen Unterordner tief zB enthalten sind public/products/a/b.jpgwerden sie nicht richtig erkannt werden, auch wenn Sie sie hinzufügen speziell wie diese !/public/products, !public/products/*etc ..

Die Lösung besteht darin, sicherzustellen, dass Sie für jede Pfadebene einen Eintrag hinzufügen, um alle zu überschreiben.

*
!.gitignore
!public/
!public/*/
!public/products/
!public/products/*
!public/products/*/
!public/products/*/
!public/products/*/*

3

Nur ein weiteres Beispiel für das Durchlaufen der Verzeichnisstruktur, um genau das zu erhalten, was Sie möchten. Hinweis: Ich habe nicht ausschließen , Library/aberLibrary/**/*

# .gitignore file
Library/**/*
!Library/Application Support/
!Library/Application Support/Sublime Text 3/
!Library/Application Support/Sublime Text 3/Packages/
!Library/Application Support/Sublime Text 3/Packages/User/
!Library/Application Support/Sublime Text 3/Packages/User/*macro
!Library/Application Support/Sublime Text 3/Packages/User/*snippet
!Library/Application Support/Sublime Text 3/Packages/User/*settings
!Library/Application Support/Sublime Text 3/Packages/User/*keymap
!Library/Application Support/Sublime Text 3/Packages/User/*theme
!Library/Application Support/Sublime Text 3/Packages/User/**/
!Library/Application Support/Sublime Text 3/Packages/User/**/*macro
!Library/Application Support/Sublime Text 3/Packages/User/**/*snippet
!Library/Application Support/Sublime Text 3/Packages/User/**/*settings
!Library/Application Support/Sublime Text 3/Packages/User/**/*keymap
!Library/Application Support/Sublime Text 3/Packages/User/**/*theme

> git add Library

> git status

On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   Library/Application Support/Sublime Text 3/Packages/User/Default (OSX).sublime-keymap
    new file:   Library/Application Support/Sublime Text 3/Packages/User/ElixirSublime.sublime-settings
    new file:   Library/Application Support/Sublime Text 3/Packages/User/Package Control.sublime-settings
    new file:   Library/Application Support/Sublime Text 3/Packages/User/Preferences.sublime-settings
    new file:   Library/Application Support/Sublime Text 3/Packages/User/RESTer.sublime-settings
    new file:   Library/Application Support/Sublime Text 3/Packages/User/SublimeLinter/Monokai (SL).tmTheme
    new file:   Library/Application Support/Sublime Text 3/Packages/User/TextPastryHistory.sublime-settings
    new file:   Library/Application Support/Sublime Text 3/Packages/User/ZenTabs.sublime-settings
    new file:   Library/Application Support/Sublime Text 3/Packages/User/adrian-comment.sublime-macro
    new file:   Library/Application Support/Sublime Text 3/Packages/User/json-pretty-generate.sublime-snippet
    new file:   Library/Application Support/Sublime Text 3/Packages/User/raise-exception.sublime-snippet
    new file:   Library/Application Support/Sublime Text 3/Packages/User/trailing_spaces.sublime-settings

Genau das, was ich auch machen wollte ;-)
Kitze

3

In WordPress hat mir das geholfen:

wp-admin/
wp-includes/
/wp-content/*
!wp-content/plugins/
/wp-content/plugins/*
!/wp-content/plugins/plugin-name/
!/wp-content/plugins/plugin-name/*.*
!/wp-content/plugins/plugin-name/**

3

gitignore - Gibt absichtlich nicht verfolgte Dateien an, die ignoriert werden sollen.

Beispiel zum Ausschließen von allem außer einem bestimmten Verzeichnis foo / bar (beachten Sie das / * - ohne den Schrägstrich würde der Platzhalter auch alles in foo / bar ausschließen ):

$ cat .gitignore
# exclude everything except directory foo/bar
/*
!/foo
/foo/*
!/foo/bar

Ein weiteres Beispiel für WordPress :

!/wp-content
wp-content/*
!/wp-content/plugins
wp-content/plugins/*
!wp-content/plugins/my-awesome-plugin

Weitere Informationen finden Sie hier: https://git-scm.com/docs/gitignore


2

Ich verwende diese Problemumgehung häufig in der CLI, wo .gitignoreich anstelle der Konfiguration meiner eine separate .includeDatei erstelle, in der ich die (Unter-) Verzeichnisse definiere, die trotz Verzeichnissen direkt oder rekursiv ignoriert werden sollen .gitignore.

Somit benutze ich zusätzlich

git add `cat .include`

während der Inszenierung vor dem Festschreiben.

Für das OP schlage ich vor, ein zu verwenden, .includedas folgende Zeilen enthält:

<parent_folder_path>/application/language/gr/*

HINWEIS: Die Verwendung caterlaubt nicht die Verwendung von Aliasen (innerhalb .include) zur Angabe von $ HOME (oder eines anderen spezifischen Verzeichnisses). Dies liegt daran, dass die Zeile homedir/app1/* bei Übergabe an git addden obigen Befehl wie folgt angezeigt git add 'homedir/app1/*'wird und das Einschließen von Zeichen in einfache Anführungszeichen ('') den Literalwert jedes Zeichens in den Anführungszeichen beibehält , wodurch verhindert wird, dass Aliase (z. B. homedir ) funktionieren (siehe Bash Single) Zitate ).

Hier ist ein Beispiel für eine .includeDatei , die ich in meinem Repo verwende hier .

/home/abhirup/token.txt
/home/abhirup/.include
/home/abhirup/.vim/*
/home/abhirup/.viminfo
/home/abhirup/.bashrc
/home/abhirup/.vimrc
/home/abhirup/.condarc

1

Ich wollte jquery-Produktion js-Dateien verfolgen und das funktionierte:

node_modules/*
!node_modules/jquery
node_modules/jquery/*
!node_modules/jquery/dist/*

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.