Faça o .gitignore ignorar tudo, exceto alguns arquivos

1701

Entendo que um arquivo .gitignore oculta arquivos especificados do controle de versão do Git. Eu tenho um projeto (LaTeX) que gera muitos arquivos extras (.auth, .dvi, .pdf, logs, etc.) enquanto ele é executado, mas não quero que eles sejam rastreados.

Estou ciente de que eu poderia (talvez devesse) fazê-lo para que todos esses arquivos sejam colocados em uma subpasta separada no projeto, já que eu poderia simplesmente ignorar a pasta.

No entanto, existe alguma maneira viável de manter os arquivos de saída na raiz da árvore do projeto e usar .gitignore para ignorar tudo, exceto os arquivos que estou rastreando com o Git? Algo como

# Ignore everything
*

# But not these files...
script.pl
template.latex
# etc...
Andrew
fonte
12
Duplicado de stackoverflow.com/q/9162919/321973 (eu sei que é mais recente, mas a resposta é mais correta). Na verdade, esta resposta é provavelmente o melhor
Tobias KIENZLER

Respostas:

2442

Um prefixo opcional !que nega o padrão; qualquer arquivo correspondente excluído por um padrão anterior será incluído novamente. Se um padrão negado corresponder, isso substituirá as origens de padrões de precedência mais baixa.

# Ignore everything
*

# But not these files...
!.gitignore
!script.pl
!template.latex
# etc...

# ...even if they are in subdirectories
!*/

# if the files to be tracked are in subdirectories
!*/a/b/file1.txt
!*/a/b/c/*
Joakim Elofsson
fonte
14
Parece que isso também 'ignora' as subpastas, de forma que qualquer arquivo chamado 'script.pl' em algo que não seja o diretório raiz não será encontrado. Eu estou usando isso agora (com * .pl) e todos os arquivos * .pl estão sendo ignoradas, embora existam muitos nos subdiretórios abaixo o arquivo .gitignore
PandaWood
38
@PandaWood Essa questão foi apresentada aqui (stackoverflow.com). É causada pela primeira expressão que corresponde a tudo, incluindo diretórios, que você nunca nega. Para corrigir, adicione (! * /), Que corresponde a qualquer subdiretório (recursivamente) no diretório atual. Isso não ajudará a resposta principal, que está na lista de arquivos específicos (se estiverem em subdiretórios, você provavelmente desejará especificar manualmente o caminho completo ou usar arquivos .gitignore específicos do diretório).
simont
40
Não consegui fazer isso funcionar. Estou ignorando uma pasta (por exemplo wp/), mas quero NÃO ignorar alguns arquivos que estão no fundo dessa pasta (por exemplo wp/path/to/some/location/*). A única maneira que eu poderia fazê-lo trabalho foi fazendogit add -f wp/path/to/some/location/*
trusktr
13
@trusktr Use a !*/exceção de simont
Tobias Kienzler 9/10/12
7
Nossa essa última regra: !*/faz toda a diferença nas minhas tentativas fúteis de organizar um .gitignorearquivo para funcionar. Muito obrigado.
racl101
628

Se você deseja ignorar todo o conteúdo de um diretório, exceto um arquivo, pode escrever um par de regras para cada diretório no caminho do arquivo. Por exemplo, .gitignore para ignorar a pasta pippo, exceto pippo / pluto / paperino.xml

.gitignore

pippo/*
!pippo/pluto
pippo/pluto/*
!pippo/pluto/paperino.xml
Giuseppe Galano
fonte
58
Excelente resposta, mas vale a pena notar para quem se deparar com isso mais tarde que fooe nãofoo/* é o mesmo. Para que isso funcione, você precisa de usar para a pasta de basefoo/*
thislooksfun
20
@ Mayank Pippo é Pateta em italiano, enquanto Paperino é Pato Donald e Plutão é o mesmo que em inglês. Eles costumavam ser um trio de nomes de variáveis ​​muito comum para programar amostras nos dias de hoje. Foi bom para lê-los novamente .. :)
Ghidello
O que @thislooksfun diz é importante se você deseja "excluir uma pasta, exceto o arquivo x".
Czechnology
8
não funciona para mim: node_modules / *! node_modules / bootstrap
SuperUberDuper
1
@simple_human Isso seria verdade se ele estivesse ignorando tudo na raiz do repositório ou se tivesse o arquivo .gitignore para se preocupar, dentro dos diretórios mencionados.
XZero
245

Você deseja usar em /*vez de *ou */na maioria dos casos

O uso *é válido, mas funciona recursivamente. Ele não procurará diretórios a partir de então. As pessoas recomendam usar os !*/diretórios da lista de permissões novamente, mas é realmente melhor colocar na lista negra a pasta de nível mais alto com/*

# Blacklist files/folders in same directory as the .gitignore file
/*

# Whitelist some files
!.gitignore
!README.md

# Ignore all files named .DS_Store or ending with .log
**/.DS_Store
**.log

# Whitelist folder/a/b1/ and folder/a/b2/
# trailing "/" is optional for folders, may match file though.
# "/" is NOT optional when followed by a *
!folder/
folder/*
!folder/a/
folder/a/*
!folder/a/b1/
!folder/a/b2/
!folder/a/file.txt

# Adding to the above, this also works...
!/folder/a/deeply
/folder/a/deeply/*
!/folder/a/deeply/nested
/folder/a/deeply/nested/*
!/folder/a/deeply/nested/subfolder

O código acima iria ignorar todos os arquivos, exceto .gitignore, README.md, folder/a/file.txt, folder/a/b1/e folder/a/b2/e tudo contida nesses dois últimos pastas. (E os arquivos .DS_Storee *.logserão ignorados nessas pastas.)

Obviamente, eu poderia fazer, por exemplo, !/folderou !/.gitignoretambém.

Mais informações: http://git-scm.com/docs/gitignore

Ryan Taylor
fonte
3
Muito esperto, obrigado. Na IMO, essa é a melhor maneira de fazer isso em sites WordPress com o número mínimo de regras de inclusão. Além disso, novos plugins, temas ou atualizações do WP não são removidos ou adicionados sem a sua permissão expressa. Ao usar o GitHub Desktop, acho que os .DS_Storearquivos não são ignorados, mas via linha de comando isso não é um problema. Para contornar isso, eu tive que mudar as **/.DS_Storeregras abaixo.
Jibran 18/05
7
Meu marcador de sintaxe interna está tendo uma reação estranha ao título da sua postagem.
itsadok
3
Gracias! você também pode colocar na lista branca um arquivo em uma pasta ..! /some/folder/file.txt
PodTech.io
Impressionante, usar / * em vez de * corrigiu todos os meus problemas quando as respostas acima não. Minha única pergunta agora é qual é a diferença entre! / Folder e! / Folder / *? Se eu usar a pasta! / Sem o *, ele ainda capta as alterações em todos os arquivos da pasta, tanto quanto eu sei.
dallin
1
@ Dallas, não há diferença. Uma lista de permissões de uma pasta e a outra lista os filhos dessa pasta, o que faz a mesma coisa. O único problema é que a pasta ou o pai de um arquivo precisa ser incluído na lista de permissões antes que possa ser permitido, portanto você não pode fazê /*-lo !/nested/folder/*(ou o equivalente !/nested/folder) sem fazer !/nested/ou !/nestedprimeiro! (e provavelmente /nested/*no meio). Um truque para lembrar é se você está whitelisting uma subpasta profundamente aninhada você precisa preto as crianças em cada subpasta todo o caminho até, e essas listas negras vai acabar com a "estrela barra" ...
Ryan Taylor
75

Um pouco mais específico:

Exemplo: ignore tudo webroot/cache- mas mantenha webroot/cache/.htaccess.

Observe a barra (/) após a cachepasta:

FALHAS

webroot/cache*
!webroot/cache/.htaccess

TRABALHO

webroot/cache/*
!webroot/cache/.htaccess
Nik
fonte
Se você estiver usando o Código VS, tome cuidado para não interpretar mal a coloração do arquivo depois de aplicá-lo a uma pasta com .gitkeep, porque o nome da pasta ficará verde, mas o arquivo .gitkeep ficará cinza, como todos os outros arquivos ignorados; .gitkeep será parecido com a sua ignorado, mas você verá que há um 'U' no lado direito, indicando que ele foi detectado
OzzyTheGiant
55
# ignore these
*
# except foo
!foo
Suvesh Pratapa
fonte
28

Para ignorar alguns arquivos em um diretório, você deve fazer isso na ordem correta :

Por exemplo, ignore tudo na pasta "application", exceto index.php e a pasta "config", preste atenção ao pedido .

Você deve negar o que deseja primeiro.

FALHAS

application/*

!application/config/*

!application/index.php

TRABALHO

!application/config/*

!application/index.php

application/*

slatunje
fonte
38
Errado. Você nega após o "ignorar tudo".
Carlos Carlos
2
Não se deixe enganar por git statusverificar se as alterações ao .gitignoretrabalho como esperado
Philippe Rathe
10
Se git statusnão vai lhe dizer o que está vendo e o que é ignorado, como você pode saber se isso está funcionando?
kris
1
@kris Limpe o cache do git primeiro. Faça um "git rm --cached *" primeiro, então você pode fazer um "git add --all" e um "status do git" mostrará todas as novas alterações no gitignore.
Mark McCorkle
20

Você pode usar git config status.showUntrackedFiles noe todos os arquivos não rastreados serão ocultados. Veja man git-configpara detalhes.

Robert Munteanu
fonte
Isso é ótimo se você só deseja confirmar alguns arquivos dentre muitos!
Josh M.
16

Para excluir a pasta do .gitignore, o seguinte pode ser feito.

!app/

app/*
!app/bower_components/

app/bower_components/*
!app/bower_components/highcharts/

Isso ignorará todos os arquivos / subpastas dentro, bower_componentsexceto /highcharts.

Guy Baskin
fonte
14

Há várias perguntas semelhantes sobre isso, então vou postar o que escrevi antes:

A única maneira de fazer isso funcionar na minha máquina era fazê-lo desta maneira:

# 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 and files if you wish:
!wordpress/somefile.jpg
!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/*/*/*/*/*

Observe como você deve permitir explicitamente o conteúdo para cada nível que você deseja incluir. Portanto, se eu tiver subdiretórios 5 em temas, ainda preciso esclarecer isso.

Isto é do comentário de @ Yarin aqui: https://stackoverflow.com/a/5250314/1696153

Estes foram tópicos úteis:

Eu também tentei

*
*/*
**/**

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

ou /wp-content/themes/**/*

Nada disso funcionou para mim também. Muita trilha e erro!

Katie
fonte
2
Este é o único método que trabalha para incluir exclusivamente determinadas extensões de arquivo. Ainda melhor, faz a grande arte ASCII: gist.github.com/Wolfgange3311999/91c671f5e4d3c56cf5a1
Matthew D. Scholefield
10

Eu tive um problema com a subpasta.

Não funciona:

/custom/*
!/custom/config/foo.yml.dist

Trabalho:

/custom/config/*
!/custom/config/foo.yml.dist
Fabian Picone
fonte
9

Tentei todas as respostas, conforme indicado aqui acima, mas nenhuma funcionou para mim. Depois de ler a documentação do gitignore ( aqui ), descobri que, se você excluir uma pasta primeiro, os nomes de arquivos na subpasta não estão sendo indexados. Portanto, se você usar o ponto de exclamação posteriormente para incluir um arquivo, ele não será encontrado no índice e, portanto, não será incluído no seu cliente git.

Essa foi a maneira de encontrar a solução. Comecei adicionando exceções para todas as subpastas da árvore de pastas para fazê-lo funcionar, o que é um trabalho e tanto. Depois pude compactar a configuração detalhada para a configuração abaixo, o que é um pouco contrário à documentação.

Working .gitignore:

# Ignore the 'Pro' folder, except for the '3rdparty' subfolder 
/Pro/*
!Pro/3rdparty/

# Ignore the '3rdparty' folder, except for the 'domain' subfolder
/Pro/3rdparty/*
!Pro/3rdparty/domain/

# Ignore the 'domain' folder, except for the 'modulename' subfolder
Pro/3rdparty/domain/*
!Pro/3rdparty/domain/modulename/

Como resultado, vejo no meu cliente git que apenas os dois arquivos dentro da pasta Pro / 3rdparty / domain / modulename / estão sendo testados para a próxima confirmação, e era exatamente isso que eu estava procurando.

E se você precisar colocar várias subpastas da mesma pasta na lista de permissões, agrupe as linhas de ponto de exclamação abaixo da instrução de exclusão da seguinte maneira:

# Ignore the 'Pro' folder, except for the '3rdparty' subfolder 
/Pro/*
!Pro/3rdparty/

# Ignore the '3rdparty' folder, except for the 'domain' & 'hosting' subfolders
/Pro/3rdparty/*
!Pro/3rdparty/domain/
!Pro/3rdparty/hosting/

# Ignore the 'domain' folder, except for the 'modulename' subfolder
Pro/3rdparty/domain/*
!Pro/3rdparty/domain/modulename/

# Ignore the 'hosting' folder, except for the 'modulename' subfolder
Pro/3rdparty/hosting/*
!Pro/3rdparty/hosting/modulename/

Caso contrário, não funcionará como esperado.

Tim B.
fonte
Finalmente uma resposta que funcionou. Gostaria de saber quando vou entender como .gitignore realmente funciona
David
8

Foi o que funcionou para mim. Queria comprometer apenas um plug-in Cordova ao repositório:

...
plugins/*
!plugins/cordova-plugin-app-customization
Dmitry Sokurenko
fonte
8

Eu sei que estou atrasado para a festa, mas aqui está a minha resposta.

Como o @Joakim disse, para ignorar um arquivo, você pode usar algo como abaixo.

# Ignore everything
*

# But not these files...
!.gitignore
!someFile.txt

mas se o arquivo estiver em diretórios aninhados, será um pouco difícil escrever as regras manualmente.

Por exemplo, se queremos pular todos os arquivos em um gitprojeto, mas não o a.txtque está localizado aDir/anotherDir/someOtherDir/aDir/bDir/cDir. Então, nosso .gitignoreserá algo parecido com isto

# Skip all files
*

# But not `aDir/anotherDir/someOtherDir/aDir/bDir/cDir/a.txt`
!aDir/
aDir/*
!aDir/anotherDir/
aDir/anotherDir/*
!aDir/anotherDir/someOtherDir/
aDir/anotherDir/someOtherDir/*
!aDir/anotherDir/someOtherDir/aDir/
aDir/anotherDir/someOtherDir/aDir/*
!aDir/anotherDir/someOtherDir/aDir/bDir/
aDir/anotherDir/someOtherDir/aDir/bDir/*
!aDir/anotherDir/someOtherDir/aDir/bDir/cDir/
aDir/anotherDir/someOtherDir/aDir/bDir/cDir/*
!aDir/anotherDir/someOtherDir/aDir/bDir/cDir/a.txt

O .gitignorearquivo acima mencionado pulará todos os diretórios e arquivos, exceto!aDir/anotherDir/someOtherDir/aDir/bDir/cDir/a.txt

Como você deve ter notado, é difícil definir essas regras.

Para solucionar esse problema, criei um aplicativo de console simples chamado git-do-not-ignore, que gerará as regras para você. Eu hospedei o projeto no github com instruções detalhadas.

Exemplo de uso

java -jar git-do-not-ignore.jar "aDir/anotherDir/someOtherDir/aDir/bDir/cDir/a.txt"

Resultado

!aDir/
aDir/*
!aDir/anotherDir/
aDir/anotherDir/*
!aDir/anotherDir/someOtherDir/
aDir/anotherDir/someOtherDir/*
!aDir/anotherDir/someOtherDir/aDir/
aDir/anotherDir/someOtherDir/aDir/*
!aDir/anotherDir/someOtherDir/aDir/bDir/
aDir/anotherDir/someOtherDir/aDir/bDir/*
!aDir/anotherDir/someOtherDir/aDir/bDir/cDir/
aDir/anotherDir/someOtherDir/aDir/bDir/cDir/*
!aDir/anotherDir/someOtherDir/aDir/bDir/cDir/a.txt

Há também uma versão web simples disponível aqui

Obrigado.

theapache64
fonte
7

Eu tenho Jquery e Angular do caramanchão. Bower os instalou em

/public_html/bower_components/jquery/dist/bunch-of-jquery-files
/public_html/bower_components/jquery/src/bunch-of-jquery-source-files
/public_html/bower_components/angular/angular-files

O jquery minimizado está dentro do distdiretório e angular está dentro do angulardiretório. Eu só precisava que arquivos minimizados fossem enviados ao github. Alguma adulteração do .gitignore e foi isso que consegui conjurar ...

/public_html/bower_components/jquery/*
!public_html/bower_components/jquery/dist
/public_html/bower_components/jquery/dist/*
!public_html/bower_components/jquery/dist/jquery.min.js
/public_html/bower_components/angular/*
!public_html/bower_components/angular/angular.min.js

Espero que alguém possa achar isso útil.

Mario Legenda
fonte
7

Foi assim que eu fiz:

# Ignore everything
*

# Whitelist anything that's a directory
!*/

# Whitelist some files
!.gitignore

# Whitelist this folder and everything inside of it
!wordpress/wp-content/themes/my-theme/**

# Ignore this folder inside that folder
wordpress/wp-content/themes/my-theme/node_modules

# Ignore this file recursively
**/.DS_Store

Use gig status -upara exibir arquivos individuais em diretórios não git statusrastreados de forma recursiva - você só veria pastas, o que poderia fazer você pensar que tudo dentro deles era rastreado

zok
fonte
5

Solução simples se você precisar ignorar tudo, exceto alguns arquivos e poucas pastas raiz :

/*
!.gitignore
!showMe.txt
!my_visible_dir

A mágica está em /*(como descrito acima) e ignora tudo na pasta (raiz) MAS NÃO recursivamente.

d.raev
fonte
4

Eu também tive alguns problemas com a negação de arquivos únicos. Consegui confirmá-los, mas meu IDE (IntelliJ) sempre reclamava de arquivos ignorados, que são rastreados.

git ls-files -i --exclude-from .gitignore

Exibe os dois arquivos que eu excluí desta maneira:

public/
!public/typo3conf/LocalConfiguration.php
!public/typo3conf/PackageStates.php

No final, isso funcionou para mim:

public/*
!public/typo3conf/
public/typo3conf/*
!public/typo3conf/LocalConfiguration.php
!public/typo3conf/PackageStates.php

A chave foi a negação da pasta typo3conf/ primeiro.

Além disso, parece que a ordem das declarações não importa . Em vez disso, você precisa negar explicitamente todas as subpastas, antes de poder negar arquivos únicos nela.

A pasta !public/typo3conf/e o conteúdo da pasta public/typo3conf/*são duas coisas diferentes para .gitignore.

Great thread! Esse problema me incomodou por um tempo;)

Armin
fonte
3

Até agora, nada funcionou para mim porque eu estava tentando adicionar um jar da lib.

Isso não funcionou:

build/*
!build/libs/*
!build/libs/
!build/libs/myjarfile.jar 

Isso funcionou:

build/*
!build/libs
Manish Bansal
fonte
3

Eu tenho esse trabalho

# Vendor
/vendor/braintree/braintree_php/*
!/vendor/braintree/braintree_php/lib
raftaar1191
fonte
2

Teve o problema semelhante ao OP, mas nenhuma das 10 principais respostas votadas realmente funcionou .
Eu finalmente descobri o seguinte

Sintaxe incorreta:

*
!bin/script.sh

Sintaxe correta:

*
!bin
!bin/script.sh

Explicação da página do manual gitignore :

Um prefixo opcional "!" que nega o padrão; qualquer arquivo correspondente excluído por um padrão anterior será incluído novamente. Não é possível incluir novamente um arquivo se um diretório pai desse arquivo for excluído . O Git não lista os diretórios excluídos por motivos de desempenho; portanto, qualquer padrão nos arquivos contidos não tem efeito, não importa onde eles estejam definidos.

Exemplo estendido:

$ tree.

.
├── .gitignore
└── bin
    ├── ignore.txt
    └── sub
        └── folder
            └── path
                ├── other.sh
                └── script.sh

$ cat .gitignore

*
!.gitignore
!bin
!bin/sub
!bin/sub/folder
!bin/sub/folder/path
!bin/sub/folder/path/script.sh

$ git status --untracked-files --ignored

On branch master

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        .gitignore
        bin/sub/folder/path/script.sh

Ignored files:
  (use "git add -f <file>..." to include in what will be committed)
        bin/ignore.txt
        bin/sub/folder/path/other.sh

nothing added to commit but untracked files present (use "git add" to track)
frntn
fonte
1

Essência

# Ignore everything
*

# But not these files...
!script.pl
!template.latex

E provavelmente incluem:

!.gitignore

Referência

Em https://git-scm.com/docs/gitignore :

Um prefixo opcional " !" que nega o padrão; qualquer arquivo correspondente excluído por um padrão anterior será incluído novamente. Não é possível incluir novamente um arquivo se um diretório pai desse arquivo for excluído. O Git não lista os diretórios excluídos por motivos de desempenho; portanto, qualquer padrão nos arquivos contidos não tem efeito, não importa onde eles estejam definidos. Coloque uma barra invertida (" \") na frente do primeiro " !" para padrões que começam com um literal " !", por exemplo, " \!important!.txt".

...

Exemplo para excluir tudo, exceto um diretório específico foo/bar(observe /*- sem a barra, o curinga também excluiria tudo dentro foo/bar):

$ cat .gitignore
# exclude everything except directory foo/bar
/*
!/foo
/foo/*
!/foo/bar
Will Caim
fonte
0

Parece que encontrei algo que funcionou para mim e que ninguém mais mencionou.

# Ignore everything
*

# But not these files...
!.gitignore
!script.pl
!template.latex
# etc...

# And if you want to include a sub-directory and all sub-directory and files under it, but not all sub-directories
!subdir/
!subdir/**/*

Basicamente, parece impedir que um subdiretório seja ignorado; você precisa ter duas entradas, uma para o subdiretório !subdir/e outra para expandir para todos os arquivos e pastas nele contidos.!subdir/**/*

Didier A.
fonte