.gitignore esclude la cartella ma include una sottocartella specifica


965

Ho la cartella application/che aggiungo a .gitignore. All'interno della application/cartella c'è la cartella application/language/gr. Come posso includere questa cartella?

Ci ho provato

application/
!application/language/gr/

senza fortuna ...


1
Si spera che la .gitignoredocumentazione sul "formato del modello" sia diventata più chiara (dicembre 2013). Vedi la mia risposta qui sotto
VonC

La mia domanda e risposta preferita, aggiunta ai preferiti e ai segnalibri del browser.
codekiddy,

Risposte:


1614

Se si esclude application/, allora tutto ciò che sarà sotto sarà sempre escluso (anche se qualche modello di esclusione negativa successivo ("unignore") potrebbe corrispondere a qualcosa sotto application/).

Per fare quello che vuoi, devi "unignore" ogni directory padre di tutto ciò che vuoi "unignore". Di solito finisci per scrivere le regole per questa situazione in coppia: ignora tutto in una directory, ma non una certa sottodirectory.

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

application/*
!application/language/

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

Nota
Il trailing /*è significativo:

  • Il modello dir/esclude una directory denominata dire (implicitamente) tutto sotto di essa.
    Con dir/, Git non guarderà mai nulla sotto dir, e quindi non applicherà mai nessuno dei modelli di "non-esclusione" a qualsiasi cosa sotto dir.
  • Lo schema dir/*non dice nulla di dirse stesso; esclude semplicemente tutto ciò che è sotto dir. Con dir/*, Git elaborerà i contenuti diretti di dir, dando ad altri pattern la possibilità di "non-escludere" parte del contenuto ( !dir/sub/).

12
Gli asterischi finali sono significativi? In tal caso, qual è la differenza di significato? Secondo l'algoritmo descritto nella documentazione di gitignore , la fine con una barra finale corrisponde a una directory e ai percorsi sottostanti quella directory. Terminare con un asterisco cadrebbe quindi in trattamento come un modello glob. La sperimentazione mostra che la variante dell'asterisco funziona, ma non quella che termina in una barra finale. Mi piacerebbe capire perché è così.
seh,

123
@seh: Sì, il trailing /*è significativo. Se una directory viene esclusa, Git non guarderà mai il contenuto di quella directory. Il modello dir/esclude una directory denominata dire (implicitamente) tutto sotto di essa. Lo schema dir/*non dice nulla di dirse stesso; esclude semplicemente tutto ciò che è sotto dir. Con dir/, Git non guarderà mai nulla sotto dir, e quindi non applicherà mai nessuno dei modelli di "non-esclusione" a qualsiasi cosa sotto dir. Con dir/*, Git elaborerà i contenuti diretti di dir, dando ad altri pattern la possibilità di "non-escludere" parte del contenuto ( !dir/sub/).
Chris Johnsen,

7
Ah, questo lo spiega. Non importa quante volte ho letto la documentazione di gitignore , non ho mai capito quando i modelli ripristinati non funzionano. Con la tua spiegazione, ora è chiaro. La documentazione di gitignore necessita di una sezione "ricetta" per spiegare come farlo.
seh,

8
Non riuscivo proprio a farlo funzionare (file .gitignore pazzo!), Quindi invece ho aggiunto forzatamente i file dopo aver inserito il cd nella directory che volevo. git add -f .
K0D4,

2
Nota che non puoi fare affidamento sull'output di git status, che ti dirà semplicemente che la directory di livello superiore verrà aggiunta. Invece, esegui una git adddelle directory di livello superiore e quindi git status(si spera) elencherà il sottoinsieme di file che sono stati abbinati dal modello.
Matthew Strawbridge,

136

Commit 59856de di Karsten Blees (kblees) per Git 1.9 / 2.0 (Q1 2014) chiarisce questo caso:

gitignore.txt: chiarire la natura ricorsiva delle directory escluse

Un prefisso opzionale " !" che nega il modello; qualsiasi file corrispondente escluso da un modello precedente verrà nuovamente incluso.

Non è possibile includere nuovamente un file se viene esclusa una directory padre di quel file. ( *)
( *: A meno che non siano rispettate determinate condizioni in git 2.8 o successiva, vedi sotto)
Git non elenco directory per motivi di prestazioni escluso, in modo che qualsiasi modelli su file contenuti non hanno alcun effetto, non importa dove essi sono definiti.

Metti una barra rovesciata (" \") davanti al primo " !" per i modelli che iniziano con un " !" letterale , ad esempio " \!important!.txt".

Esempio per escludere tutto tranne una directory specifica foo/bar(notare il /*- senza la barra, il carattere jolly escluderebbe anche tutto all'interno foo/bar):

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

Nel tuo caso:

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

È necessario prima elencare le cartelle nella white list , prima di poter elencare i file nella white list in una determinata cartella.


Aggiornamento febbraio / marzo 2016:

Si noti che con git 2.9.x / 2.10 (metà 2016?), Potrebbe essere possibile includere nuovamente un file se una directory padre di quel file viene esclusa se non sono presenti caratteri jolly nel percorso .

Nguyễn Thái Ngọc Duy ( pclouds) sta cercando di aggiungere questa funzione:

Quindi con git 2.9+, questo avrebbe potuto effettivamente funzionare, ma alla fine è stato ripristinato:

application/
!application/language/gr/

Ho provato a usare la sintassi re-include aggiornata pubblicata alla fine della tua risposta su git per Windows v2.8.1.windows.1ma non sembra funzionare :(
David Hancock,

1
@DavidHancock Siamo spiacenti, ho modificato la risposta: questo non è ancora disponibile.
VonC,

1
@DavidHancock anche a me: sono più di 13 le risposte Stack Overflow che ho dovuto modificare più volte!
VonC,

5
Git 2.9 è stato rilasciato ieri. La conferma del modello application/+ !application/language/gr/menzionato nella risposta funziona come previsto.
Ray Shan,

1
@RayShan Strano: ho visto il commit di ripristino che annulla quella funzione, ma non ho visto (e la nota di rilascio github.com/git/git/blob/master/Documentation/RelNotes/2.9.0.txt non menziona) qualsiasi commit che migliora le regole .gitignore.
VonC,

52

La risposta di @Chris Johnsen è ottima, ma con una versione più recente di Git (1.8.2 o successive), esiste un doppio modello di asterisco che puoi sfruttare per una soluzione un po 'più abbreviata:

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

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

In questo modo non è necessario "annullare il riconoscimento" della directory principale della sottocartella che si desidera tracciare.


Con Git 2.17.0 (Non sono sicuro di quanto prima di questa versione. Forse indietro a 1.8.2), usando il **modello combinato con exclude per ogni sottodirectory che porta ai tuoi file funziona. Per esempio:

# 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
Purtroppo, questo fallisce (Git 1.8.4.msysgit.0) perché il modello **può abbinare zero sottocartelle e *lo abbinerà languageed escluderà, impedendo l'inclusione di gr. L'intera catena di genitori raccomandata da Chris Johnson sembra ancora necessaria.
Sean Gugler,

3
Sembra perfetto ma per me non funziona su git 2.3.7 ... /www/**/* !/www/config.xml !/www/resconfig.xml e la directory res è ancora ignorata.
Rob,

@Rob devi anche aggiungere !/www/res/. È possibile utilizzare il folder/**/*modello, ma è comunque necessario aggiungere esclusioni per ogni sottodirectory che si desidera aggiungere. È ancora più breve e più leggibile della combinazione ignore / exclude.
Ben Kane,

So che è un vecchio commento, ma nel caso tu sia curioso. Ho aggiunto una modifica alla risposta che documenta questo approccio.
Ben Kane,

21

Ci sono un sacco di domande simili su questo, quindi posterò quello che ho scritto prima:

L'unico modo per farlo funzionare sulla mia macchina era farlo in questo modo:

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

Nota come devi consentire esplicitamente il contenuto per ogni livello che desideri includere. Quindi, se ho sottodirectory 5 temi profondi, devo ancora precisarlo.

Questo è dal commento di @ Yarin qui: https://stackoverflow.com/a/5250314/1696153

Questi erano argomenti utili:

Ho anche provato

*
*/*
**/**

e **/wp-content/themes/**

o /wp-content/themes/**/*

Niente di tutto ciò ha funzionato neanche per me. Un sacco di tentativi ed errori!


1
Nota: ricorda che l'ordine è importante anche in un file .gitignore, quindi assicurati di mettere le tue !regole in fondo.
Starbeamrainbowlabs


8

Il modo più semplice e probabilmente migliore è provare ad aggiungere i file manualmente (in genere ciò ha la precedenza sulle .gitignoreregole di stile):

git add /path/to/module

Si potrebbe anche voler l' -N intento di aggiungere la bandiera, a suggerire che si sarà aggiungerli, ma non subito. Lo faccio spesso per i nuovi file che non sono ancora pronto a mettere in scena.


Questa è una copia di una risposta postata su quello che potrebbe facilmente essere un QA duplicato. Lo sto ripubblicando qui per una maggiore visibilità: trovo più facile non avere un pasticcio di regole gitignore.


2
Grazie per questa risposta Ho dovuto aggiungere -f dato che è nel mio .gitignore in questo modo: git add -f path / to / file
jasonflaherty

6

Quindi, poiché molti programmatori usano il nodo. il caso d'uso che risponde a questa domanda è di escludere node_modulesad module-aesempio un modulo :

!node_modules/

node_modules/*
!node_modules/module-a/

2
Non funziona con la versione git 2.10.2.windows.1.
Sebastian,

1
Per la versione 2.10.2 di git segui questa risposta
nalexn,

👌 fantastico 👋 👋.
Abdennour TOUMI

6

Aggiungi una risposta aggiuntiva:

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

ecco il risultato:

inserisci qui la descrizione dell'immagine


2
Questa è stata la risposta più utile per me dato che la grafica mi ha aiutato. Grazie!
Joel Murphy,

4

Soprattutto per le versioni precedenti di Git, la maggior parte dei suggerimenti non funzionerà così bene. In tal caso, inserirò un .gitignore separato nella directory in cui desidero includere il contenuto indipendentemente dalle altre impostazioni e consentirei ciò che è necessario.

Ad esempio: /.gitignore

# ignore all .dll files
*.dll

/dependency_files/.gitignore

# include everything
!*

Quindi tutto in / dependency_files (anche file .dll) è incluso bene.


4

Ho trovato un caso simile qui, dove in laravel per impostazione predefinita, .gitignoreignora tutto usando asterix, quindi sovrascrive la directory pubblica.

*
!public
!.gitignore

Ciò non è sufficiente se si esegue lo scenario OP.

Se si desidera eseguire il commit di una sottocartella specifica di public, ad esempio nella propria public/productsdirectory si desidera includere file con una sottocartella profonda ad esempio per includere public/products/a/b.jpgche non verranno rilevati correttamente, anche se li si aggiunge in modo specifico !/public/products,!public/products/* ecc ..

La soluzione è assicurarsi di aggiungere una voce per ogni livello di percorso come questo per sovrascriverli tutti.

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

3

Solo un altro esempio di come si cammina lungo la struttura delle directory per ottenere esattamente ciò che si desidera. Nota: non ho escluso Library/maLibrary/**/*

# .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

Esattamente quello che volevo fare anch'io ;-)
Kitze,

3

In WordPress, questo mi ha aiutato:

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 - Specifica i file non tracciati intenzionalmente da ignorare.

Esempio per escludere tutto tranne una specifica directory foo / bar (notare / / - senza la barra, il carattere jolly escluderebbe anche tutto all'interno di foo / bar ):

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

Un altro esempio per WordPress :

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

Maggiori informazioni qui: https://git-scm.com/docs/gitignore


2

Uso spesso questa soluzione alternativa nella CLI dove invece di configurare my .gitignore, creo un .includefile separato in cui definisco le (sotto) directory che voglio includere nonostante le directory ignorate direttamente o ricorsivamente da.gitignore .

Quindi, uso anche

git add `cat .include`

durante la messa in scena, prima di impegnarsi.

All'OP, suggerisco di usare un .includeche ha queste righe:

<parent_folder_path>/application/language/gr/*

NOTA: L'uso catnon consente l'uso di alias (all'interno .include) per specificare $ HOME (o qualsiasi altra directory specifica). Questo perché la riga homedir/app1/* quando viene passata git addall'utilizzo del comando precedente appare come git add 'homedir/app1/*', e racchiudere i caratteri tra virgolette singole ('') preserva il valore letterale di ciascun carattere all'interno delle virgolette, impedendo così il funzionamento di alias (come homedir ) (vedi Bash Single Citazioni ).

Ecco un esempio di un .includefile che uso nel mio repository qui .

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

1

Volevo tenere traccia dei file js di produzione jquery e questo ha funzionato:

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

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.