.gitignore excluir pasta, mas inclui subpasta específica
965
Eu tenho a pasta application/que adiciono ao .gitignore. Dentro da application/pasta está a pasta application/language/gr. Como posso incluir esta pasta?
Se você excluir application/, tudo o que estiver abaixo será sempre excluído (mesmo que algum padrão de exclusão negativa posterior (“não-reconhecido”) possa corresponder a algo abaixo application/).
Para fazer o que você deseja, é necessário "cancelar a assinatura" de todos os diretórios pai de tudo o que você deseja "cancelar a autenticação". Geralmente, você acaba escrevendo regras para essa situação em pares: ignora tudo em um diretório, mas não em um determinado subdiretório.
# 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
O final /*é significativo:
O padrão dir/exclui um diretório chamado dire (implicitamente) tudo sob ele.
Com dir/, o Git nunca examinará nada abaixo dire, portanto, nunca aplicará nenhum dos padrões de "exclusão" a nada abaixo dir.
O padrão dir/*não diz nada sobre dirsi; apenas exclui tudo que está abaixo dir. Com dir/*, o Git processará o conteúdo direto dir, dando a outros padrões a chance de "excluir" um pouco do conteúdo ( !dir/sub/).
Os asteriscos à direita são significativos? Se sim, qual é a diferença de significado? De acordo com o algoritmo descrito na documentação do gitignore , terminar com uma barra final corresponde a um diretório e caminhos abaixo desse diretório. Terminar com um asterisco passaria a ser tratado como um padrão glob. A experiência mostra a variante de asterisco para funcionar, mas não a que termina em apenas uma barra final. Eu gostaria de entender por que isso é assim.
seh
123
@seh: Sim, a trilha /*é significativa. Se um diretório for excluído, o Git nunca examinará o conteúdo desse diretório. O padrão dir/exclui um diretório chamado dire (implicitamente) tudo sob ele. O padrão dir/*não diz nada sobre dirsi; apenas exclui tudo que está abaixo dir. Com dir/, o Git nunca examinará nada abaixo dire, portanto, nunca aplicará nenhum dos padrões de "exclusão" a nada abaixo dir. Com dir/*, o Git processará o conteúdo direto dir, dando a outros padrões a chance de "excluir" um pouco do conteúdo ( !dir/sub/).
Chris Johnsen
7
Ah, isso explica isso. Não importa quantas vezes eu tenha lido a documentação do gitignore , nunca entendi quando os padrões revertidos não funcionam. Com sua explicação, agora está claro. A documentação do gitignore precisa de uma seção "receita" para explicar como fazer isso.
seh
8
Eu não consegui fazer isso funcionar (arquivo louco .gitignore!), Então, em vez disso, apenas forcei a adição dos arquivos após o cd'ing no diretório que eu queria. git add -f .
K0D4 21/07
2
Observe que você não pode confiar na saída de git status, o que dirá apenas que o diretório de nível superior será adicionado. Em vez disso, faça um git adddiretório do nível superior e, em seguida git status, (esperançosamente) listará o subconjunto de arquivos que foram correspondidos pelo padrão.
gitignore.txt: esclarecer a natureza recursiva dos diretórios excluídos
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. ( *)
( *: a menos que determinadas condições sejam atendidas no git 2.8+, veja abaixo) O
Git não lista os diretórios excluídos por motivos de desempenho; portanto, quaisquer padrões nos arquivos contidos não têm efeito, independentemente de onde 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):
Eu tentei usar o atualizados re-incluem sintaxe publicado no final de sua resposta sobre git para Windows v2.8.1.windows.1, mas ele não aparece para trabalhar :(
David Hancock
1
@DavidHancock Desculpe, editei a resposta: isso ainda não está disponível.
VonC 12/04
1
@DavidHancock também: são mais de 13 respostas de estouro de pilha que tive que editar várias vezes!
VonC 12/04
5
O Git 2.9 foi lançado ontem. A confirmação do padrão application/+ !application/language/gr/mencionado na resposta está funcionando conforme o esperado.
A resposta de @Chris Johnsen é ótima, mas com as versões mais recentes do Git (1.8.2 ou posterior), existe um padrão de asterisco duplo que você pode aproveitar para obter uma solução um pouco mais abreviada:
# assuming the root folder you want to ignore is 'application'
application/**/*
# the subfolder(s) you want to track:
!application/language/gr/
Dessa forma, você não precisa "cancelar a assinatura" do diretório pai da subpasta que deseja rastrear.
Com o Git 2.17.0 (Não sei ao certo quanto tempo antes desta versão. Possivelmente, retorne à 1.8.2), o uso do **padrão combinado com exclusões para cada subdiretório que leva ao (s) arquivo (s) funciona. Por exemplo:
# 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
Infelizmente, isso falha (Git 1.8.4.msysgit.0) porque o padrão **pode corresponder a subpastas zero e *irá corresponder languagee excluí-lo, impedindo a inclusão de gr. A cadeia completa de pais que Chris Johnson recomenda ainda parece necessária.
Sean Gugler 14/02
3
Parece perfeito, mas não funciona para mim no git 2.3.7 ... /www/**/* !/www/config.xml !/www/resconfig.xml e o diretório res ainda são ignorados.
Rob
@ Rob você também precisa adicionar !/www/res/. Você pode usar o folder/**/*padrão, mas ainda precisará adicionar exclusões para cada subdiretório que deseja adicionar. Ainda é mais curto e mais legível do que a combinação de ignorar / excluir.
21718 Ben Kane
Eu sei que é um comentário antigo, mas caso você esteja curioso. Adicionei uma edição à resposta que documenta essa abordagem.
21718 Ben Kane
21
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:
!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.
A maneira mais simples e provavelmente a melhor é tentar adicionar os arquivos manualmente (geralmente isso tem precedência sobre as .gitignoreregras de estilo):
git add /path/to/module
Você pode até querer -Nadicionar o sinalizador, sugerindo que você os adicione, mas não imediatamente. Costumo fazer isso para novos arquivos que ainda não estou pronto para preparar.
Esta é uma cópia de uma resposta publicada sobre o que poderia ser facilmente um controle de qualidade duplicado. Estou reposicionando-o aqui para aumentar a visibilidade - acho mais fácil não ter uma confusão de regras de gitignore.
!/.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
Essa foi a resposta mais útil para mim, pois o visual ajudou. Obrigado!
Joel Murphy
4
Especialmente para as versões mais antigas do Git, a maioria das sugestões não funciona tão bem. Se for esse o caso, eu colocaria um .gitignore separado no diretório em que desejo que o conteúdo seja incluído, independentemente de outras configurações, e permita o necessário.
Por exemplo: /.gitignore
# ignore all .dll files
*.dll
/dependency_files/.gitignore
# include everything
!*
Portanto, tudo em / dependency_files (mesmo arquivos .dll) está incluído.
Eu encontrei um caso semelhante aqui, em que no laravel, por padrão, .gitignoreignora todos usando asterix e substitui o diretório público.
*
!public
!.gitignore
Isso não é suficiente se você se deparar com o cenário OP.
Se você deseja confirmar uma subpasta específica de public, digamos, por exemplo, em seu public/productsdiretório, você deseja incluir arquivos com uma subpasta profunda, por exemplo, para incluir que public/products/a/b.jpgeles não serão detectados corretamente, mesmo se você os adicionar especificamente assim !/public/products,!public/products/* , etc ..
A solução é garantir que você adicione uma entrada para cada nível de caminho como esse para substituir todos eles.
Apenas outro exemplo de percorrer a estrutura de diretórios para obter exatamente o que você deseja. Nota: não excluí, Library/masLibrary/**/*
# .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
gitignore - especifica arquivos não rastreados intencionalmente a serem ignorados.
Exemplo para excluir tudo, exceto um diretório específico foo / bar (observe o / * - sem a barra, o curinga também excluiria tudo dentro de foo / bar ):
Costumo usar essa solução alternativa na CLI, onde, em vez de configurar o meu .gitignore, crio um .includearquivo separado onde defino os (sub) diretórios que desejo que sejam incluídos, apesar dos diretórios serem ignorados direta ou recursivamente por.gitignore .
Assim, eu uso adicionalmente
git add `cat .include`
durante a preparação, antes de confirmar.
Para o OP, sugiro usar um .includeque tenha estas linhas:
<parent_folder_path>/application/language/gr/*
NOTA: O uso catnão permite o uso de aliases (dentro .include) para especificar $ HOME (ou qualquer outro diretório específico). Isso ocorre porque a linha homedir/app1/*
quando passada para o git adduso do comando acima aparece comogit add 'homedir/app1/*' , e os caracteres entre aspas simples ('') preservam o valor literal de cada caractere entre aspas, impedindo o funcionamento de aliases (como homedir ) (consulte Bash Single Citações ).
Aqui está um exemplo de um .includearquivo que eu uso no meu repositório aqui .
.gitignore
documentação do "formato padrão" ficou mais clara (dezembro de 2013). Veja minha resposta abaixoRespostas:
Se você excluir
application/
, tudo o que estiver abaixo será sempre excluído (mesmo que algum padrão de exclusão negativa posterior (“não-reconhecido”) possa corresponder a algo abaixoapplication/
).Para fazer o que você deseja, é necessário "cancelar a assinatura" de todos os diretórios pai de tudo o que você deseja "cancelar a autenticação". Geralmente, você acaba escrevendo regras para essa situação em pares: ignora tudo em um diretório, mas não em um determinado subdiretório.
Nota
O final
/*
é significativo:dir/
exclui um diretório chamadodir
e (implicitamente) tudo sob ele.Com
dir/
, o Git nunca examinará nada abaixodir
e, portanto, nunca aplicará nenhum dos padrões de "exclusão" a nada abaixodir
.dir/*
não diz nada sobredir
si; apenas exclui tudo que está abaixodir
. Comdir/*
, o Git processará o conteúdo diretodir
, dando a outros padrões a chance de "excluir" um pouco do conteúdo (!dir/sub/
).fonte
/*
é significativa. Se um diretório for excluído, o Git nunca examinará o conteúdo desse diretório. O padrãodir/
exclui um diretório chamadodir
e (implicitamente) tudo sob ele. O padrãodir/*
não diz nada sobredir
si; apenas exclui tudo que está abaixodir
. Comdir/
, o Git nunca examinará nada abaixodir
e, portanto, nunca aplicará nenhum dos padrões de "exclusão" a nada abaixodir
. Comdir/*
, o Git processará o conteúdo diretodir
, dando a outros padrões a chance de "excluir" um pouco do conteúdo (!dir/sub/
).git add -f .
git status
, o que dirá apenas que o diretório de nível superior será adicionado. Em vez disso, faça umgit add
diretório do nível superior e, em seguidagit status
, (esperançosamente) listará o subconjunto de arquivos que foram correspondidos pelo padrão.O compromisso 59856de de Karsten Blees (kblees) para o Git 1.9 / 2.0 (primeiro trimestre de 2014) esclarece esse caso:
gitignore.txt
: esclarecer a natureza recursiva dos diretórios excluídosNo seu caso:
Você deve primeiro pastas da lista branca , antes de poder listar arquivos em uma determinada pasta.
Atualização fevereiro / março de 2016:
Observe que, com o git 2.9.x / 2.10 (meados de 2016?), Pode ser possível incluir novamente um arquivo se um diretório pai desse arquivo for excluído se não houver curinga no caminho incluído novamente .
Nguyễn Thái Ngọc Duy (
pclouds
) está tentando adicionar este recurso:Portanto, com o git 2.9+, isso poderia realmente funcionar, mas acabou sendo revertido:
fonte
v2.8.1.windows.1
, mas ele não aparece para trabalhar :(application/
+!application/language/gr/
mencionado na resposta está funcionando conforme o esperado.A resposta de @Chris Johnsen é ótima, mas com as versões mais recentes do Git (1.8.2 ou posterior), existe um padrão de asterisco duplo que você pode aproveitar para obter uma solução um pouco mais abreviada:
Dessa forma, você não precisa "cancelar a assinatura" do diretório pai da subpasta que deseja rastrear.
Com o Git 2.17.0 (Não sei ao certo quanto tempo antes desta versão. Possivelmente, retorne à 1.8.2), o uso do
**
padrão combinado com exclusões para cada subdiretório que leva ao (s) arquivo (s) funciona. Por exemplo:fonte
**
pode corresponder a subpastas zero e*
irá corresponderlanguage
e excluí-lo, impedindo a inclusão degr
. A cadeia completa de pais que Chris Johnson recomenda ainda parece necessária./www/**/* !/www/config.xml !/www/res
config.xml e o diretório res ainda são ignorados.!/www/res/
. Você pode usar ofolder/**/*
padrão, mas ainda precisará adicionar exclusões para cada subdiretório que deseja adicionar. Ainda é mais curto e mais legível do que a combinação de ignorar / excluir.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:
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. Muitas tentativas e erros!
fonte
!
regras na parte inferior.Eu descobri que apenas isso realmente funciona.
fonte
A maneira mais simples e provavelmente a melhor é tentar adicionar os arquivos manualmente (geralmente isso tem precedência sobre as
.gitignore
regras de estilo):Você pode até querer
-N
adicionar o sinalizador, sugerindo que você os adicione, mas não imediatamente. Costumo fazer isso para novos arquivos que ainda não estou pronto para preparar.Esta é uma cópia de uma resposta publicada sobre o que poderia ser facilmente um controle de qualidade duplicado. Estou reposicionando-o aqui para aumentar a visibilidade - acho mais fácil não ter uma confusão de regras de gitignore.
fonte
Então, já que muitos programadores usam o nó. o caso de uso que atende a essa pergunta é excluir,
node_modules
exceto um módulo,module-a
por exemplo:fonte
2.10.2.windows.1
.Adicione uma resposta adicional:
aqui está o resultado:
fonte
Especialmente para as versões mais antigas do Git, a maioria das sugestões não funciona tão bem. Se for esse o caso, eu colocaria um .gitignore separado no diretório em que desejo que o conteúdo seja incluído, independentemente de outras configurações, e permita o necessário.
Por exemplo: /.gitignore
/dependency_files/.gitignore
Portanto, tudo em / dependency_files (mesmo arquivos .dll) está incluído.
fonte
Eu encontrei um caso semelhante aqui, em que no laravel, por padrão,
.gitignore
ignora todos usando asterix e substitui o diretório público.Isso não é suficiente se você se deparar com o cenário OP.
Se você deseja confirmar uma subpasta específica de
public
, digamos, por exemplo, em seupublic/products
diretório, você deseja incluir arquivos com uma subpasta profunda, por exemplo, para incluir quepublic/products/a/b.jpg
eles não serão detectados corretamente, mesmo se você os adicionar especificamente assim!/public/products
,!public/products/*
, etc ..A solução é garantir que você adicione uma entrada para cada nível de caminho como esse para substituir todos eles.
fonte
Apenas outro exemplo de percorrer a estrutura de diretórios para obter exatamente o que você deseja. Nota: não excluí,
Library/
masLibrary/**/*
> git add Library
> git status
fonte
No WordPress, isso me ajudou:
fonte
gitignore - especifica arquivos não rastreados intencionalmente a serem ignorados.
Exemplo para excluir tudo, exceto um diretório específico foo / bar (observe o / * - sem a barra, o curinga também excluiria tudo dentro de foo / bar ):
Outro exemplo para o WordPress :
Mais informações aqui: https://git-scm.com/docs/gitignore
fonte
Costumo usar essa solução alternativa na CLI, onde, em vez de configurar o meu
.gitignore
, crio um.include
arquivo separado onde defino os (sub) diretórios que desejo que sejam incluídos, apesar dos diretórios serem ignorados direta ou recursivamente por.gitignore
.Assim, eu uso adicionalmente
durante a preparação, antes de confirmar.
Para o OP, sugiro usar um
.include
que tenha estas linhas:NOTA: O uso
cat
não permite o uso de aliases (dentro.include
) para especificar $ HOME (ou qualquer outro diretório específico). Isso ocorre porque a linhahomedir/app1/*
quando passada para ogit add
uso do comando acima aparece comogit add 'homedir/app1/*'
, e os caracteres entre aspas simples ('') preservam o valor literal de cada caractere entre aspas, impedindo o funcionamento de aliases (como homedir ) (consulte Bash Single Citações ).Aqui está um exemplo de um
.include
arquivo que eu uso no meu repositório aqui .fonte
Eu queria rastrear arquivos js de produção jquery e isso funcionou:
fonte
minha configuração do JetBrains IntelliJ IDEA .gitignore, em que preciso excluir a
.idea
pasta wholde, exceto.idea/runConfigurations
:consulte: https://github.com/daggerok/gitignore-idea-runConfigurations
fonte