Annuler les sous-répertoires des répertoires ignorés dans Git

99

Disons que j'ai ignoré un répertoire, mais je veux annuler l'ignorer des sous-répertoires spécifiques qu'il contient. J'ai donc la configuration:

/uploads/
/uploads/rubbish/
/uploads/rubbish/stuff/KEEP_ME/
/uploads/foo/
/uploads/foo/bar/lose/

Et je veux tout ignorer sauf le KEEP_MErépertoire. J'espère que l'ignorer ressemblerait à quelque chose comme:

/uploads/*
!/uploads/rubbish/stuff/KEEP_ME/

Mais cela ne fonctionne pas, pas plus que plusieurs permutations sur le même thème.

Celui qui fonctionne est

/uploads/**/**/**/
!/uploads/rubbish/stuff/KEEP_ME/

Mais cela semble un peu restrictif et verbeux?

Wil
la source
1
Le code que vous avez fourni ne fonctionnait pas pour moi (en utilisant la version 1.9.1 de git). Celui qui a fonctionné est / uploads / *! / Uploads / rubbish / / uploads / rubbish / *! / Uploads / rubbish / stuff / uploads / rubbish / stuff / *! / Uploads / rubbish / stuff / keep (qui est similaire à l'exemple dans git-scm.com/docs/gitignore ). Mon dossier struct; └ README.md └ uploads / foo / bar / lost / lost.txt └ uploads / rubbish / stuff / keep / keep.txt
gihanchanuka

Réponses:

119

Selon la section format de modèle de la documentation de gitignore :

Un préfixe facultatif "!" ce qui annule le modèle; tout fichier correspondant exclu par un modèle précédent sera de nouveau inclus. Il n'est pas possible de ré-inclure un fichier si un répertoire parent de ce fichier est exclu. Git ne répertorie pas les répertoires exclus pour des raisons de performances, donc tous les modèles sur les fichiers contenus n'ont aucun effet, peu importe où ils sont définis. Mettez une barre oblique inverse ("\") devant le premier "!" pour les modèles commençant par un littéral "!", par exemple, "! important! .txt".

Par conséquent, le /uploads/rubbish/stuff/keep/modèle de répertoire parent précédemment exclu doit être exclusivement annulé avant d'annuler son contenu:

#ignore everything within /uploads/ 
/uploads/*

#include everything within /uploads/rubbish/stuff/keep
!/uploads/rubbish/stuff/keep/  
!/uploads/rubbish/stuff/keep/*

Pour inclure des sous-répertoires à l'intérieur, /uploads/rubbish/stuff/keep/ajoutez la troisième ligne:

!/uploads/rubbish/stuff/keep/**/*
Art Shayderov
la source
1
Quelle version de git utilisiez-vous? Peut-être que c'est quelque chose de disponible uniquement dans certaines versions.
Embarrassé. J'ai oublié d'avoir posté ce commentaire. Je l'ai fait fonctionner, cependant. FWIW, je n'utilise pas les barres obliques principales. Je ne me souviens pas si c'était le problème. J'utilise 1.7.2.5.
J'ai un fichier global gitignore où j'ai ignoré tous les fichiers * .zip. Pourtant, pour un projet particulier, je souhaite inclure des fichiers zip. J'ai ajouté cette ligne à ce projet .gitignoreet cela fonctionne très bien !:!*.zip
Jinghao Shi
J'ai trouvé nécessaire de spécifier explicitement des répertoires arbitraires avant et après le dossier donné à la fois en excluant le dossier et en incluant le sous-dossier . ( Réponse complète ).
Josiah Yoder le
Cette méthode ne fonctionne pas (à partir de git 2.25 - peut-être que quelque chose a changé dans git). J'ai posté stackoverflow.com/a/60288435/295691 ci-dessous comme correction.
user295691
34

Même si vous ajoutez quelque chose à .gitignore, vous pouvez forcer git à l'ajouter à l'index

git add --force uploads/rubbish/stuff/KEEP_ME/

Cependant, "KEEP_ME" semble être un répertoire et git n'aime généralement pas les dossiers vides, vous devriez donc pouvoir ajouter un fichier "placeholder" à la place, si le dossier est vide

git add --force uploads/rubbish/stuff/KEEP_ME/.keep_me
KingCrunch
la source
Le seul problème avec cela est que cet exemple spécifique fait référence à un gitignore global que j'aurais dû mentionner. Je sais que je peux forcer l'ajout d'éléments, mais je devrai le faire si de nouveaux éléments sont ajoutés, ainsi qu'au départ pour chaque nouveau référentiel. Le .keep garantit-il que le contenu n'est pas ignoré?
Wil
1
J'ai fait un petit test. Oui, vous devez utiliser git add --forcepour chaque nouvel élément ou dossier dans KEEP_ME. mais après cela, les mises à jour sont simplement ajoutées (lors de l'exécution d'un git add -upar exemple) comme si les fichiers n'étaient pas ignorés. Le .keep_mene fait rien, c'est juste un fichier pour que git opère sur le dossier.
commonpike
1
git add --forceest la mauvaise solution pour cela. Si vous déplacez un répertoire ou déplacez le fichier vers un autre répertoire, le suivi de git supprimera le fichier mais ne l'ajoutera pas au nouvel emplacement et vous devrez git add --forcerecommencer. en annulant l'ignorance d'un motif générique, git suivra le mouvement d'un fichier dans le dépôt.
Merlin
C'est la seule solution qui a fonctionné pour moi. Mon dossier n'a PAS été ignoré, mais je ne pouvais en aucun cas l'ajouter. Cette façon a résolu le problème pour moi.
Akito
6

J'essayais de comprendre comment inclure un dossier spécifique lors de l'exclusion de tous les dossiers avec l'exclusion générique

**/build

si vous ajoutez le /*à la fin de votre exclusion générique, vous continuez d'exclure tous les fichiers de construction**/build/*

Ensuite, vous ajoutez une autre ligne pour corriger le chemin que vous souhaitez inclure pour ressembler à

!**/folder/build/* 

nous laissant un gitignore qui lit

**/build/* 
!**/folder/build/* 
John
la source
2

Buo-Ren Lin et JohnLes réponses de sont très utiles, mais je devais combiner les deux.

Lorsque je voulais exclure d'autres sous-dossiers ainsi que des fichiers dans les téléchargements, j'ai trouvé nécessaire de spécifier explicitement des répertoires arbitraires avant le dossier donné à la fois en excluant le dossier et en incluant le sous-dossier

**/uploads/*
!**/uploads/rubbish/
!**/uploads/rubbish/*

J'ai également trouvé qu'il était nécessaire de ré-inclure explicitement le sous-dossier et son contenu pour afficher les deux éléments dans le dossier et les sous-dossiers.

Josiah Yoder
la source
Soupir. Aucune chance ici. À cela depuis des heures maintenant. Git 2.20.1
RichieHH
@ HörmannHH Désolé d'entendre ça. Il est peut-être temps de poser une nouvelle question?
Josiah Yoder le
2

La solution présentée comme la réponse la plus votée est incorrecte et facilement démontrable en tant que telle.

Commencez par ignorer tout dans les téléchargements / *:

mkdir -p uploads/rubbish/stuff/KEEP_ME
touch uploads/a uploads/rubbish/a uploads/rubbish/stuff/a uploads/rubbish/stuff/KEEP_ME/a
echo '/uploads/*' >> .gitignore
git init
git add .
git commit -m "Initial commit"

Désignorez maintenant le répertoire parent des éléments ignorés comme ci-dessus:

echo 'uploads/rubbish/stuff/KEEP_ME/' >> .gitignore
echo 'uploads/rubbish/stuff/KEEP_ME/*' >> .gitignore
git status -u

N'affiche aucun fichier non suivi.

Pour que cela fonctionne, vous devez ignorer tous les fichiers sous l' uploads/arborescence ( uploads/**/*et pas seulement le niveau supérieur uploads/*), puis ajouter tous les répertoires parents de l'arborescence que vous souhaitez conserver

echo '/uploads/**/*' > .gitignore
echo '!/uploads/rubbish/' >> .gitignore
echo '!/uploads/rubbish/stuff' >> .gitignore
echo '!/uploads/rubbish/stuff/KEEP_ME' >> .gitignore
echo '!/uploads/rubbish/stuff/KEEP_ME/*' >> .gitignore
git status -u

Qui donne:

On branch master
...
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        uploads/rubbish/stuff/KEEP_ME/a

Si nous avions utilisé uploads/*ce qui .gitignoreprécède, tous les fichiers intermédiaires auraient également été inclus, donc par exemple uploads/rubbish/aapparaîtraient dans la commande d'état ci-dessus.

user295691
la source