Non ignorare le sottodirectory delle directory ignorate in Git


99

Diciamo che ho ignorato una directory, ma desidero non ignorare specifiche sottodirectory al suo interno. Quindi ho la configurazione:

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

E voglio ignorare tutto tranne la KEEP_MEdirectory. Spero che l'ignore assomigli a qualcosa del tipo:

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

Ma questo non funziona, e nemmeno molte permutazioni sullo stesso tema.

Uno che funziona è

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

Ma sembra un po 'restrittivo e prolisso?


1
Il codice che hai fornito non ha funzionato per me (utilizzando la versione 1.9.1 di git). Uno che ha funzionato è / uploads / *! / Uploads / rubbish / / uploads / rubbish / *! / Uploads / rubbish / stuff / uploads / rubbish / stuff / *! / Uploads / rubbish / stuff / keep (che è simile all'esempio in git-scm.com/docs/gitignore ). La mia struttura della cartella; └ README.md └ uploads / foo / bar / lose / lose.txt └ uploads / rubbish / stuff / keep / keep.txt
gihanchanuka

Risposte:


119

Secondo la sezione del formato del modello della documentazione di gitignore :

Un prefisso opzionale "!" che nega il pattern; qualsiasi file corrispondente escluso da un modello precedente verrà nuovamente incluso. Non è possibile includere nuovamente un file se una directory principale di quel file è esclusa. Git non elenca le directory escluse per motivi di prestazioni, quindi qualsiasi modello sui file contenuti non ha effetto, indipendentemente da dove sono definiti. Metti una barra rovesciata ("\") davanti al primo "!" per i modelli che iniziano con un letterale "!", ad esempio, "! important! .txt".

Pertanto il /uploads/rubbish/stuff/keep/modello di directory padre precedentemente escluso deve essere esclusivamente negato prima di negare il suo contenuto:

#ignore everything within /uploads/ 
/uploads/*

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

Per includere sottodirectory all'interno /uploads/rubbish/stuff/keep/aggiungi la terza riga:

!/uploads/rubbish/stuff/keep/**/*

1
Quale versione di git stavi usando? Forse è qualcosa disponibile solo in alcune versioni.

Imbarazzato. Dimenticavo di aver pubblicato questo commento. Ho funzionato, però. FWIW, non uso le barre iniziali. Non ricordo se questo fosse il problema. Sto usando 1.7.2.5.

Ho un file gitignore globale in cui ho ignorato tutti i file * .zip. Tuttavia, per un progetto particolare, voglio includere file zip. Ho aggiunto questa riga a quel progetto .gitignoree funziona benissimo !:!*.zip
Jinghao Shi

Ho trovato necessario specificare esplicitamente directory arbitrarie sia prima che dopo la cartella data sia escludendo la cartella sia includendo la sottocartella . ( Risposta completa ).
Josiah Yoder,

Questo metodo non funziona (a partire da git 2.25 - forse qualcosa in git è cambiato). Ho pubblicato stackoverflow.com/a/60288435/295691 di seguito come correzione.
user295691

34

Anche se aggiungi qualcosa a .gitignore, puoi forzare git ad aggiungerlo all'indice

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

Tuttavia, "KEEP_ME" sembra essere una directory ea git di solito non piace la cartella vuota, quindi dovresti aggiungere un file "segnaposto" -holder, se la cartella è vuota

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

L'unico problema è che questo esempio specifico si riferisce a un gitignore globale che avrei dovuto menzionare. So di poter forzare l'aggiunta di elementi, ma dovrò farlo se vengono aggiunti nuovi elementi, nonché inizialmente per ogni nuovo repository. Il .keep garantisce che i contenuti non vengano ignorati?
Wil

1
Ho fatto un piccolo test. Sì, devi usare git add --forceper ogni nuovo elemento o cartella in KEEP_ME. ma dopo ciò, gli aggiornamenti vengono semplicemente aggiunti (quando si esegue un filegit add -u ad esempio ) come se i file fossero "non ignorati". Non .keep_mefa nulla, è solo un file in modo che git operi sulla cartella.
commonpike

1
git add --forceè la soluzione sbagliata per questo. Se sposti una directory o sposti il ​​file in un'altra directory, il monitoraggio di git eliminerà il file ma non lo aggiungerà nella nuova posizione e dovrai farlo di git add --forcenuovo. ignorando un pattern generico, git terrà traccia del movimento di un file all'interno del repository.
Merlin

Questa è l'unica soluzione che ha funzionato per me. La mia cartella NON è stata ignorata, ma non ho potuto aggiungerla in alcun modo. In questo modo l'ho risolto per me.
Akito

6

Stavo cercando di capire come includere una cartella specifica escludendo tutte le cartelle con l'esclusione generica

**/build

se aggiungi il /*alla fine della tua esclusione generica, continui ad escludere tutti i file di build**/build/*

Quindi aggiungi un'altra riga per correggere il percorso che desideri includere

!**/folder/build/* 

lasciandoci un gitignore che legge

**/build/* 
!**/folder/build/* 

2

Buo-Ren Lin e John sono molto utili, ma dovevo combinare entrambe le cose.

Quando si desidera escludere altre sottocartelle e file all'interno dei caricamenti, ho ritenuto necessario specificare esplicitamente directory arbitrarie prima della cartella data sia escludendo la cartella sia includendo la sottocartella

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

Ho anche trovato necessario reincludere esplicitamente sia la sottocartella che il suo contenuto per mostrare entrambi gli elementi all'interno della cartella e delle sottocartelle.


Sospiro. Zero fortuna qui. A questo da ore ormai. Git 2.20.1
RichieHH

@ HörmannHH Mi dispiace sentirlo. Forse è il momento di fare una nuova domanda?
Josiah Yoder il

2

La soluzione presentata come la risposta più votata è sbagliata e facilmente dimostrabile come tale.

Inizia ignorando tutto nei caricamenti / *:

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"

Ora annulla la directory principale delle cose ignorate come sopra:

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

Non mostra file non tracciati.

Affinché funzioni, è necessario ignorare tutti i file sotto l' uploads/albero ( uploads/**/*, non solo il livello superiore uploads/*) e quindi aggiungere tutte le directory padre dell'albero che si desidera mantenere

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

Che dà:

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

Se avessimo usato uploads/*quanto .gitignoresopra, allora sarebbero stati inclusi anche tutti i file intermedi, quindi ad esempio uploads/rubbish/averrebbero visualizzati nel comando di stato sopra.

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.