1453 votes

.gitignore exclure un dossier mais inclure un sous-dossier spécifique

J'ai le dossier application/ que j'ajoute à la .gitignore . A l'intérieur de la application/ le dossier est le dossier application/language/gr . Comment puis-je inclure ce dossier ?

J'ai essayé ceci

application/
!application/language/gr/

sans succès...

1 votes

Espérons que le " .gitignore La documentation sur le "format de motif" vient d'être clarifiée (décembre 2013). Voir ma réponse ci-dessous

1 votes

Ma question et réponse préférée, ajoutée aux favoris ainsi qu'aux signets du navigateur.

2 votes

2309voto

Chris Johnsen Points 50064

Si vous excluez application/ alors tout ce qui se trouve en dessous sera toujours exclu (même si un motif d'exclusion négatif ("unignore") ultérieur peut correspondre à quelque chose se trouvant sous application/ ).

Pour faire ce que vous voulez, vous devez "désignoriser" chaque répertoire parent de ce que vous voulez "désignoriser". En général, on finit par écrire des règles pour cette situation par paires : ignorer tout dans un répertoire, mais pas un certain sous-répertoire.

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

application/*
!application/language/

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

Note
La queue /* est significatif :

  • Le motif dir/ exclut un répertoire nommé dir et (implicitement) tout ce qui s'y trouve.
    Avec dir/ Git ne regardera jamais rien en dessous de dir et n'appliquera donc jamais l'un des modèles de "désexclusion" à tout ce qui se trouve sous le seuil d'exclusion. dir .
  • Le motif dir/* ne dit rien sur dir elle-même ; elle exclut simplement tout ce qui est sous dir . Avec dir/* Git traitera le contenu direct de dir en donnant aux autres modèles une chance de "désexclure" une partie du contenu ( !dir/sub/ ).

18 votes

Les astérisques de queue sont-ils significatifs ? Si oui, quelle est la différence de signification ? Selon l'algorithme décrit dans le gitignore se terminant par une barre oblique correspond à un répertoire et aux chemins sous ce répertoire. La terminaison par un astérisque peut alors être traitée comme un motif global. L'expérimentation montre que la variante avec astérisque fonctionne, mais pas celle qui se termine par une simple barre oblique. J'aimerais comprendre pourquoi il en est ainsi.

154 votes

@seh : Oui, la queue /* est significatif. Si un répertoire est exclu, Git ne regardera jamais le contenu de ce répertoire. Le motif dir/ exclut un répertoire nommé dir et (implicitement) tout ce qui s'y trouve. Le modèle dir/* ne dit rien sur dir elle-même ; elle exclut simplement tout ce qui est sous dir . Avec dir/ Git ne regardera jamais rien en dessous de dir et n'appliquera donc jamais l'un des modèles de "désexclusion" à tout ce qui se trouve sous le seuil d'exclusion. dir . Avec dir/* Git traitera le contenu direct de dir en donnant aux autres modèles une chance de "désexclure" une partie du contenu ( !dir/sub/ ).

13 votes

Ah, ça explique tout. Peu importe le nombre de fois que j'ai lu la gitignore documentation, je n'ai jamais compris quand les modèles inversés ne fonctionnent pas. Avec votre explication, c'est maintenant clair. Le site gitignore La documentation doit comporter une section "recettes" expliquant comment procéder.

185voto

VonC Points 414372

Commit 59856de de Karsten Blees (kblees) pour Git 1.9/2.0 (Q1 2014) clarifie ce cas :

gitignore.txt : clarifier la nature récursive des répertoires exclus

Un préfixe facultatif " ! "qui annule le motif ; tout fichier correspondant exclu par un motif précédent sera à nouveau inclus.

Il n'est pas possible de réinclure un fichier si un répertoire parent de ce fichier est exclu. ( * )
( * : sauf si certaines conditions sont remplies dans git 2.8+, voir ci-dessous)
Git ne liste pas les répertoires exclus pour des raisons de performance, donc les motifs sur les fichiers contenus n'ont aucun effet, peu importe où ils sont définis.

Mettez un backslash (" \ ") devant le premier " ! "pour les modèles qui commencent par un " ! ", par exemple, " \!important!.txt ".

Exemple pour exclure tout sauf un répertoire spécifique foo/bar (notez le /* - sans la barre oblique, le caractère générique exclurait également tout ce qui se trouve à l'intérieur de foo/bar ):

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

Dans votre cas :

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

Vous devez mettre sur liste blanche dossiers avant de pouvoir mettre sur liste blanche les fichiers d'un dossier donné.


Mise à jour février/mars 2016 :

Notez qu'avec git 2.9.x/2.10 (mi 2016 ?), il pourrait être possible de réinclure un fichier si un répertoire parent de ce fichier est exclu. s'il n'y a pas de joker dans le chemin réinclus .

Nguyen Thái Ngoc Duy ( pclouds ) essaie d'ajouter cette fonctionnalité :

Ainsi, avec git 2.9+, cela aurait pu fonctionner, mais a finalement été annulé :

application/
!application/language/gr/

0 votes

J'ai essayé d'utiliser la mise à jour de la syntaxe re-include postée à la fin de votre réponse sur git pour Windows v2.8.1.windows.1 mais cela ne semble pas fonctionner :(

1 votes

@DavidHancock Désolé, j'ai modifié la réponse : ce n'est pas encore disponible.

0 votes

Merci d'avoir éclairci ce point. J'ai un monstrueux .gitignore en ce moment. J'espère que cela sera intégré à la 2.9.

79voto

rpyzh Points 191

La réponse de @Chris Johnsen est excellente, mais avec les versions plus récentes de Git (1.8.2 ou plus), il existe un modèle de double astérisque que vous pouvez utiliser pour une solution un peu plus concise :

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

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

De cette façon, vous n'avez pas besoin de "désignoriser" le répertoire parent du sous-dossier que vous voulez suivre.


Avec Git 2.17.0 (je ne suis pas sûr de l'antériorité de cette version, peut-être jusqu'à 1.8.2), en utilisant la commande ** combiné à des exclusions pour chaque sous-répertoire menant au(x) fichier(s) fonctionne. Par exemple :

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

Hélas, cela échoue (Git 1.8.4.msysgit.0) car le motif ** peut correspondre à zéro sous-dossier, et * correspondra à language et l'exclure, empêchant ainsi l'inclusion de gr . La chaîne complète des parents recommandée par @Chris Johnson semble encore nécessaire.

3 votes

Cela semble parfait mais cela ne fonctionne pas pour moi sur git 2.3.7 ... /www/**/* !/www/config.xml !/www/res config.xml et le répertoire res sont toujours ignorés.

0 votes

@Rob vous devez également ajouter !/www/res/ . Vous pouvez utiliser le folder/**/* mais vous devez encore ajouter des exclusions pour chaque sous-répertoire que vous voulez ajouter. C'est tout de même plus court et plus lisible que le combo ignorer/exclure.

54voto

Steve Kling Points 291

Je n'ai trouvé que ceci en fait travaux.

**/node_modules/*
!**/node_modules/keep-dir

0 votes

Génial, sauve ma journée)

0 votes

A sauvé le mien aussi

0 votes

C'est le moyen le plus simple et le plus rapide.

31voto

Kayvar Points 4239

Il y a un tas de questions similaires à ce sujet, donc je vais poster ce que j'ai écrit auparavant :

La seule façon d'obtenir ce résultat sur ma machine a été de procéder de cette manière :

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

Remarquez que vous devez autoriser explicitement le contenu pour chaque niveau que vous souhaitez inclure. Ainsi, si j'ai des sous-répertoires de 5 niveaux sous les thèmes, je dois encore le préciser.

Ceci est tiré du commentaire de @Yarin ici : https://stackoverflow.com/a/5250314/1696153

Ces sujets étaient utiles :

J'ai aussi essayé

*
*/*
**/**

y **/wp-content/themes/**

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

Rien de tout ça n'a marché pour moi non plus. Beaucoup d'essais et d'erreurs !

3 votes

Note : Rappelez-vous que l'ordre a aussi de l'importance dans un fichier .gitignore, donc assurez-vous de mettre votre fichier .gitignore dans la liste des fichiers. ! règles en bas de page.

3 votes

C'est plus embarrassant que le javascript en tant que langage lui-même. pourquoi diable y a-t-il autant de réponses différentes et absurdes pour un problème aussi simple ? (Je suis critique envers git, pas envers votre solution). Et non, git n'est pas mauvais, mais il a quelques mauvais côtés.

1 votes

La façon dont tu l'as fait est la seule qui ait fonctionné pour moi.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X