Como posso adicionar um diretório vazio a um repositório Git?

4268

Como posso adicionar um diretório vazio (que não contém arquivos) a um repositório Git?

Laurie Young
fonte
16
Embora não seja útil, existe uma maneira de invadir um diretório vazio (realmente vazio) em seu repositório . No checkoutentanto, não será nas versões atuais do Git.
22412
335
@tiwo Eu discordo que não é útil. Sua hierarquia de diretórios faz parte do seu projeto, portanto deve ser controlada por versão.
precisa saber é o seguinte
114
No meu caso, eu gostaria de adicionar uma estrutura de diretórios para arquivos tmp, mas não os próprios arquivos tmp. Ao fazer isso, meu testador tem a estrutura correta (caso contrário, há erros), mas não obstruo meus commits com dados tmp. Então, sim, é útil para mim!
Adam Marshall
45
@AdamMarshall Acho que você estava dizendo que o hack não é útil, pois é ignorado pelo checkout. Os diretórios Tmp soam como um recurso útil para um VCS.
precisa saber é o seguinte
31
Por que o procedimento que cria os arquivos tmp também não cria o diretório tmp?
21913 RyPeck

Respostas:

4128

Outra maneira de fazer um diretório ficar (quase) vazio (no repositório) é criar um .gitignorearquivo dentro desse diretório que contenha essas quatro linhas:

# Ignore everything in this directory
*
# Except this file
!.gitignore

Então você não precisa fazer o pedido da maneira que precisa na solução do m104 .

Isso também oferece o benefício de que os arquivos nesse diretório não serão exibidos como "não rastreados" quando você fizer um status git.

Tornando o comentário do @GreenAsJade persistente:

Eu acho que vale a pena notar que esta solução faz exatamente o que a pergunta pediu, mas talvez não seja o que muitas pessoas que estão olhando para essa pergunta estejam procurando. Esta solução garante que o diretório permaneça vazio. Ele diz "Eu realmente nunca quero que os arquivos sejam verificados aqui". Ao contrário de "Ainda não tenho arquivos para fazer check-in aqui, mas preciso do diretório aqui, os arquivos podem chegar mais tarde".

Jamie Flournoy
fonte
25
Eu acho que a solução README proposta por @JohnMee deve ser usada junto com esta; o arquivo .gitignore fornece uma explicação sobre o que queremos manter fora do controle de versão, enquanto o arquivo README explica qual é o objetivo do diretório, que são informações muito importantes.
pedromanoel 17/01
18
@pedromanoel Eu escrevo a documentação que você colocaria READMEdentro do .gitignorearquivo (como comentários).
Carlos Campderrós
69
identifique a 1 diferença: 1.) uma pasta vazia, 2.) uma pasta com o arquivo .gitignore. ;-)
Peter Perháč
6
Isso é perfeito para pastas de cache .
redolent 26/03
10
Infelizmente, isso resulta em um diretório não vazio, com um único arquivo oculto.
pedorro
1091

Você não pode. Veja as perguntas frequentes do Git .

Atualmente, o design do índice git (área de preparação) permite apenas a listagem de arquivos, e ninguém competente o suficiente para fazer a alteração para permitir diretórios vazios se preocupou o suficiente com essa situação para remediá-la.

Os diretórios são adicionados automaticamente ao adicionar arquivos dentro deles. Ou seja, os diretórios nunca precisam ser adicionados ao repositório e não são rastreados por si mesmos.

Você pode dizer " git add <dir>" e ele adicionará arquivos lá.

Se você realmente precisa que um diretório exista nos caixas, deve criar um arquivo nele. .gitignore funciona bem para esse fim; você pode deixá-lo vazio ou preencher os nomes dos arquivos que você espera que apareçam no diretório

Andy Lester
fonte
67
A resposta abaixo é MUITO melhor. O fato de o git, o software de baixo nível, não permitir, não importa para mim tanto quanto COMO realmente usar o Git quando preciso de um diretório vazio. Adicionar um .gitignore de 2 linhas parece aceitável para mim.
Amala
1
Bem, se um quer mover arquivos para um novo diretório, eles não podem fazê-lo através git mvde git vai reclamar que o novo diretório não está sob controle de versão
lulalala
16
Você pode ler " é impossível, não pode, etc. " em toda a Internet para essa pergunta frequente. O .gitignoretruque é uma resposta frequente e satisfaz muitas necessidades. No entanto , é possível fazer git controlar um realmente vazio diretório, veja a minha resposta
ofavre
2
Embora, quanto mais eu penso nisso, mais parece que "o hash SHA da cadeia vazia", ​​se existir, seria realmente um identificador bem definido para uma árvore vazia, a menos que fosse impossível dizer se esse objeto é uma árvore ou uma bolha.
Emil Lundberg
21
Eu já vi vários repositórios que usam um arquivo vazio chamado .gitkeeppara esse fim.
Sukima
759

Crie um arquivo vazio chamado .gitkeepno diretório e adicione-o.

Artur79
fonte
58
Eu adicionei uma resposta encorajadora para criar .keep.
Acumenus 29/01
206
.gitkeepnão foi prescrito pelo Git e fará as pessoas adivinharem seu significado, o que as levará a pesquisas no Google, que as levarão aqui. A .gitconvenção de prefixo deve ser reservada para arquivos e diretórios que o próprio Git usa.
t-mart
10
@ t-mart "A .gitconvenção do prefixo deve ser reservada ..." Por quê? O git solicita esta reserva?
Expiação limitada
9
Nesse caso, um arquivo READMEou ABOUTseria tão bom ou melhor. Deixando uma nota para o próximo cara, assim como costumávamos fazer antes dos URLs.
Dave
5
Não funciona se você estiver escrevendo um teste de unidade que deve testar o código em um diretório vazio ...
thebjorn
437

Você sempre pode colocar um arquivo README no diretório com uma explicação de por que deseja esse diretório, caso contrário vazio, no repositório.

John Mee
fonte
39
+1, Boa sugestão, um diretório vazio não faz sentido, a menos que seja usado no futuro. Portanto, crie um arquivo LEIA-ME e escreva para que serve esse diretório e quais arquivos serão colocados lá no futuro. Isso resolve os dois problemas.
Saeedgnu
63
@ilius Nonsense. Uma estrutura de diretório contendo diretórios vazios pode ser altamente desejável em muitas situações (como um aplicativo MVC no qual você deseja um diretório de modelos, mas ainda não conseguiu criar nenhum modelo, ou um diretório de visualizações compartilhadas para o qual planeja adicionar visualizações compartilhadas, posteriormente ) Além disso, colocar um README em cada um deles é um exagero, pois é óbvio para que servem e é fácil esquecer de colocar um README em cada um deles. E você deve se lembrar de remover o README quando adicionar outros arquivos a eles. Basicamente, o git definitivamente deve permitir diretórios vazios.
Jez
20
@Jez: eu discordo. O ponto é que o git é projetado para controlar (e indexar) o código-fonte. Importante, o ID de uma confirmação é um hash do conteúdo. Ou seja, ele deve ter conteúdo. Você não precisa de um README em todas as partes da árvore, apenas nos nós das folhas. Se você tem lugares em que pretende colocar código, mas nenhum código, e nem sequer dedica um tempo para ecoar "lugar para modelos" >> LEIA-ME, então o que você tem é uma ideia, não uma confirmação. Não é de interesse git. Dizer "Quero que o aplicativo em execução tenha diretórios vazios XYZ" é um problema de tempo de execução , não de origem. Manuseie-o com seu instalador.
Joe Atzberger
6
@JoeAtzberger É um recurso ausente, não uma limitação intencional. Das perguntas frequentes do Git: Atualmente, o design do índice Git (área de preparação) permite apenas a listagem de arquivos, e ninguém é competente o suficiente para fazer a alteração para permitir que diretórios vazios se importem o suficiente com essa situação para remediá-la.
precisa saber é o seguinte
7
@ jbo5112 Sim, o "código especial" a que você se refere é o "instalador" que mencionei. Sua instalação do aplicativo da web já precisa lidar com a criação de um banco de dados, configuração local, dependências de extração ou 100 outras operações, mas alguns diretórios vazios estão além disso? Tente gradle, passageiro, chef, um Makefile primitivo etc. Não há diferença de segurança entre a criação de diretórios e o outro trabalho (potencialmente muito mais complicado / perigoso) de instalar um aplicativo. E se você realmente não possui deps, config, DB, etc. e nenhum instalador, basta usar o README. Nenhum caso exige que você faça as duas coisas.
21813 Joe Atzberger
349
touch .keep

No Linux, isso cria um arquivo vazio chamado .keep. Pelo que vale, esse nome é independente do Git, enquanto .gitkeepseria específico do Git. Em segundo lugar, como outro usuário observou, a .gitconvenção de prefixo deve ser reservada para arquivos e diretórios que o próprio Git usa.

Como alternativa, conforme observado em outra resposta , o diretório pode conter um descritivo READMEou README.mdarquivo .

Obviamente, isso exige que a presença do arquivo não cause a quebra do aplicativo.

Acumenus
fonte
1
Isso é bom para um diretório bare inicial, mas e se ele começar a ser preenchido com arquivos? Então o Git irá notá-los e reivindicá-los como arquivos não rastreados. A resposta selecionada aqui funciona de maneira muito mais elegante para permitir a manutenção de um diretório, mas ignorando com segurança o conteúdo.
JakeGould
14
A pergunta e a preocupação geral predominante são sobre a adição de um diretório vazio. Se mais tarde ele tiver um arquivo residente, exclua-o obviamente .keepou simplesmente ignore-o. Se, em vez disso, os arquivos no diretório devem ser ignorados, essa é uma questão completamente diferente.
Acumenus
3
Foi sugerido que isso git clean -nd | sed s/'^Would remove '// | xargs -I{} touch "{}.keep"seja feito em todos os diretórios vazios não rastreados.
Acumenus
1
Não gosto dessa solução, é difícil adivinhar o que esse arquivo faz. Além disso, se você estiver gerando arquivos em seu ambiente de desenvolvimento (como logs ou imagens, etc.), isso não impedirá que o arquivo seja versionado e chegue à produção, o que não é legal.
Danielrvt 19/05/19
1
O Windows não gosta de arquivos sem nomes e requer mágica especial para fazer isso (também conhecido como aplicativo de terminal do tipo bash ou equivalente).
fácil fazer o
303

Por que precisaríamos de pastas com versão vazias

Primeiras coisas primeiro:

Um diretório vazio não pode fazer parte de uma árvore no sistema de versão do Git .

Simplesmente não será rastreado. Mas há cenários nos quais diretórios vazios de "controle de versão" podem ser significativos, por exemplo:

  • andaimes de uma estrutura de pastas predefinida , disponibilizando-a a todos os usuários / contribuidores do repositório; ou, como um caso especializado do acima, criar uma pasta para arquivos temporários , como a cache/ou logs/diretórios, nos quais queremos fornecer a pasta, mas .gitignoreseu conteúdo
  • relacionados ao exposto, alguns projetos não funcionarão sem algumas pastas (o que geralmente é uma sugestão de um projeto mal projetado, mas é um cenário frequente do mundo real e talvez haja, digamos, problemas de permissão a serem resolvidos).

Algumas soluções alternativas sugeridas

Muitos usuários sugerem:

  1. Colocar um READMEarquivo ou outro arquivo com algum conteúdo para tornar o diretório não vazio, ou
  2. Criando um .gitignorearquivo com uma espécie de "lógica reversa" (ou seja, para incluir todos os arquivos) que, no final, serve ao mesmo objetivo da abordagem nº 1.

Enquanto ambas as soluções certamente funcionam, eu as considero inconsistentes com uma abordagem significativa ao versionamento do Git.

  • Por que você deve colocar arquivos falsos ou READMEs que talvez você realmente não queira em seu projeto?
  • Por que usar .gitignorepara fazer algo ( manter arquivos) exatamente o oposto do que se destina ( excluir arquivos), mesmo que seja possível?

abordagem .gitkeep

Use um arquivo vazio chamado.gitkeep para forçar a presença da pasta no sistema de versão.

Embora possa não parecer uma diferença tão grande:

  • Você usa um arquivo que possui o único objetivo de manter a pasta. Você não coloca nenhuma informação que não queira colocar.

    Por exemplo, você deve usar READMEs, bem como READMEs com informações úteis, não como uma desculpa para manter a pasta.

    A separação de preocupações é sempre uma coisa boa, e você ainda pode adicionar um .gitignorepara ignorar arquivos indesejados.

  • A nomeação .gitkeeptorna muito claro e direto do próprio nome do arquivo (e também de outros desenvolvedores , o que é bom para um projeto compartilhado e um dos principais objetivos de um repositório Git) que esse arquivo seja

    • Um arquivo não relacionado ao código (devido ao ponto inicial e ao nome)
    • Um arquivo claramente relacionado ao Git
    • Seu propósito ( manter ) é claramente declarado e consistente e semanticamente oposto no seu significado de ignorar

Adoção

Eu vi a .gitkeepabordagem adotada por estruturas muito importantes como o Laravel , Angular-CLI .

Cranio
fonte
8
Você perdeu um pensamento - qual o motivo para manter uma pasta vazia (por exemplo, / logs, / tmp, / uploads)? Sim - é para manter a pasta vazia. :) Portanto, se você deseja manter uma pasta vazia, é necessário ignorar os arquivos dentro dela.
Roman
14
@RomanAllenstein: não necessariamente. Pode ser que você crie um repositório com uma determinada estrutura que pode ser preenchida posteriormente. Esses arquivos serão adicionados ao repositório assim que forem criados, e será irritante começar a excluir ou editar arquivos .gitignore (e perigoso, porque provavelmente você nem percebe que eles não estão sendo rastreados: o git os está ignorando) )
blueFast
45
@Behnam: Aceito o voto negativo, mas minha pesquisa na meta SO não mostra nenhuma preocupação com respostas detalhadas, desde que elas forneçam detalhes e clareza suficientes para serem úteis a todos os leitores (e a todos os níveis de habilidade). Ainda estou muito aberto a qualquer crítica e obrigado por ter declarado o motivo publicamente, considero isso muito positivo.
Cranio
4
Se você editar sua resposta para substituí-la .gitkeeppor qualquer outro nome de arquivo não prefixado por git, receberá meu voto positivo, acho que essa é a resposta melhor e mais informativa. Motivo: acho que ".git *" deve ser reservado para arquivos prescritos pelo git, enquanto este é apenas um espaço reservado. Meu primeiro palpite quando vi que, por exemplo, um arquivo ".gitkeep" seria ignorado automaticamente (seria um recurso interessante), mas não é esse o caso, certo?
21416 Johnny
5
Eu me pergunto por que as pessoas têm tanta dificuldade em entender por que alguém deseja adicionar pastas "vazias" ao git. Você tem que começar de algum lugar, certo? Portanto, geralmente você começa com a estrutura de pastas do seu projeto e, infelizmente, no início do projeto ainda não há nada. Uma vez concluído o repo do projeto, os funcionários da equipe podem clonar e começar a trabalhar na mesma estrutura.
BitTickler 21/10
127

Conforme descrito em outras respostas, o Git não pode representar diretórios vazios em sua área de preparação. (Consulte as Perguntas frequentes do Git .) No entanto, se, para seus propósitos, um diretório estiver vazio o suficiente se contiver .gitignoreapenas um arquivo, você poderá criar .gitignorearquivos em diretórios vazios apenas através de:

find . -type d -empty -exec touch {}/.gitignore \;
mjs
fonte
21
Você pode querer ignorar o diretório .git: find . -name .git -prune -o -type d -empty -exec touch {}/.gitignore \;
steffen
3
Uma variação mais simples para a maioria das situações éfind * -type d -empty -exec touch {}/.gitignore \;
Akhan
2
Como o OS X cria um arquivo .DS_Store em quase todos os diretórios, isso não funciona lá. A única solução alternativa (PERIGOSA!) Que encontrei foi excluir todos os arquivos .DS_Store primeiro find . -name .DS_Store -exec rm {} \;e, em seguida, usar a variante preferida desta resposta. Certifique-se de executar isso apenas na pasta correta!
precisa saber é o seguinte
1
Alguém sabe uma maneira de fazer isso no Windows a partir da linha de comando? Eu já vi algumas soluções aqui em Ruby e Python, mas eu gostaria de uma solução de barebones, se puder ser gerenciada.
Mig82
1
A adição de algo a .gitignorenão tem influência na -emptybandeira do findcomando. Meu comentário é sobre a remoção dos .DS_Storearquivos em uma árvore de diretórios, para que o -emptysinalizador possa ser aplicado.
Zerweck 6/04
68

Andy Lester é certo, mas se o seu diretório só precisa estar vazia, e não esvaziar vazio, você pode colocar um vazio.gitignore arquivo lá como uma solução alternativa.

Além disso, esse é um problema de implementação, não um problema fundamental de design de armazenamento Git. Como já foi mencionado muitas vezes na lista de discussão do Git, a razão pela qual isso não foi implementado é que ninguém se importou o suficiente para enviar um patch para ele, não que não pudesse ou não deveria ser feito.

Aristóteles Pagaltzis
fonte
4
Foi exatamente o que eu disse. Ambos os parágrafos são abordados no trecho de FAQ que publiquei.
Andy Lester
1
Eu acho que o lado é interessante e útil - ele pode ser corrigido, mas não espere isso tão cedo, quando houver uma solução tão fácil para a maioria dos casos.
wnoise 22/09/08
Desculpe, eu não li o último parágrafo e, embora tenha lido o primeiro parágrafo, bem, não sei por que repeti essas informações.
Aristóteles Pagaltzis 23/09/08
2
Obviamente, essa resposta extra serve para apontar o fato.
Michael Johnson
Cheguei aqui olhando para um caso em que a compilação caiu se o diretório não existir e, por padrão, está vazio, mas não precisa estar vazio. Criar um .gitignore faz a coisa certa.
Joshua
33

A maneira de criação da pasta de log do Ruby on Rails :

mkdir log && touch log/.gitkeep && git add log/.gitkeep

Agora o diretório de log será incluído na árvore. É super útil ao implantar, portanto você não precisará escrever uma rotina para criar diretórios de log.

Os arquivos de log podem ser mantidos de fora, emitindo,

echo log/dev.log >> .gitignore

Mas tu provavelmente sabias disso.

Thomas E
fonte
23
O que isso tem a ver com Ruby on Rails?
Perguntas Quolonel
30

O Git não rastreia diretórios vazios. Veja as Perguntas frequentes do Git para obter mais explicações. A solução alternativa sugerida é colocar um .gitignorearquivo no diretório vazio. Eu não gosto dessa solução, porque o .gitignoreé "oculto" pela convenção do Unix. Também não há explicação para os diretórios estarem vazios.

Sugiro colocar um arquivo README no diretório vazio, explicando por que o diretório está vazio e por que ele precisa ser rastreado no Git. Com o arquivo README em vigor, no que diz respeito ao Git, o diretório não está mais vazio.

A verdadeira questão é por que você precisa do diretório vazio no git? Geralmente você tem algum tipo de script de construção que pode criar o diretório vazio antes de compilar / executar. Caso contrário, faça um. Essa é uma solução muito melhor do que colocar diretórios vazios no git.

Então você tem algum motivo para precisar de um diretório vazio no git. Coloque esse motivo no arquivo LEIA-ME. Dessa forma, outros desenvolvedores (e o futuro você) sabem por que o diretório vazio precisa estar lá. Você também saberá que pode remover o diretório vazio quando o problema que requer o diretório vazio for resolvido.


Para listar todos os diretórios vazios, use o seguinte comando:

find -name .git -prune -o -type d -empty -print

Para criar READMEs de espaço reservado em todos os diretórios vazios:

find -name .git -prune -o -type d -empty -exec sh -c \
  "echo this directory needs to be empty because reasons > {}/README.emptydir" \;

Para ignorar tudo no diretório, exceto o arquivo LEIA-ME, coloque as seguintes linhas no seu .gitignore:

path/to/emptydir/*
!path/to/emptydir/README.emptydir
path/to/otheremptydir/*
!path/to/otheremptydir/README.emptydir

Como alternativa, você pode simplesmente excluir todos os arquivos README de serem ignorados:

path/to/emptydir/*
path/to/otheremptydir/*
!README.emptydir

Para listar todos os README depois que eles já foram criados:

find -name README.emptydir
lesmana
fonte
28

AVISO: Este ajuste não está realmente funcionando como se vê.Desculpe pela inconveniência.

Post original abaixo:

Encontrei uma solução enquanto brincava com Git internals!

  1. Suponha que você esteja em seu repositório.
  2. Crie seu diretório vazio:

    $ mkdir path/to/empty-folder
    
  3. Inclua-o no índice usando um comando de encanamento e a árvore vazia SHA-1 :

    $ git update-index --index-info
    040000 tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904    path/to/empty-folder
    

    Digite o comando e digite a segunda linha. Pressione Entere depois Ctrl+ Dpara finalizar sua entrada. Nota: o formato é o modo [ESPAÇO] do tipo [ESPAÇO] SHA-1; possui o caminho [TAB] (a guia é importante, a formatação da resposta não a preserva).

  4. É isso aí! Sua pasta vazia está no seu índice. Tudo o que você precisa fazer é confirmar.

Esta solução é curta e aparentemente funciona bem ( consulte a edição! ), Mas não é tão fácil de lembrar ...

A árvore vazia SHA-1 pode ser encontrada criando um novo repositório Git vazio, cdpara ele e o problema git write-tree, que gera a árvore vazia SHA-1.

EDITAR:

Eu uso esta solução desde que a encontrei. Parece funcionar exatamente da mesma maneira que a criação de um submódulo, exceto que nenhum módulo está definido em nenhum lugar. Isso leva a erros ao emitir git submodule init|update. O problema é que git update-indexreescreve a 040000 treepeça em160000 commit .

Além disso, qualquer arquivo colocado nesse caminho nunca será percebido pelo Git, pois acredita que pertence a algum outro repositório. Isso é desagradável, pois pode ser facilmente esquecido!

No entanto, se você ainda não (e não usará) nenhum sub-módulo do Git no seu repositório, e a pasta "empty" permanecerá vazia ou se você quiser que o Git saiba de sua existência e ignore seu conteúdo, pode seguir esse ajuste. Seguindo o caminho habitual com os submódulos, são necessários mais passos que esses ajustes.

ofavre
fonte
Depois de colocar a pasta vazia no índice e confirmar, é possível obter git svn dcommito resultado desejado?
Expiação limitada
2
É improvável que esse ajuste funcione com qualquer outra ferramenta. Como declarado no aviso e na edição, eu desencorajo usá-lo, a menos que em um caso bastante restrito.
ofavre
1
E é claro que é por isso que mexer com os internos do git é contra-indicado.
Casey
@abhisekp Como isso é possível?
PyRulez
1
@ PyRulez bem, no mundo do software, nada é impossível. : D Na verdade, eu segui a resposta.
Abhisekp
21

Digamos que você precise de um diretório vazio chamado tmp :

$ mkdir tmp
$ touch tmp/.gitignore
$ git add tmp
$ echo '*' > tmp/.gitignore
$ git commit -m 'Empty directory' tmp

Em outras palavras, você precisa adicionar o arquivo .gitignore ao índice antes de poder dizer ao Git para ignorá-lo (e tudo o mais no diretório vazio).

m104
fonte
11
Duas coisas: você pode "echo '*'> tmp / .gitignore" em vez de tocar, e "git commit -m" não confirma as alterações feitas depois que você adiciona os arquivos ao índice.
Christoffer Hammarström
6
Se você simplesmente echo bla > filenão conseguir, file: File existsporque >substituirá o arquivo se ele já estiver lá ou criará um novo se ele não existir.
Psyrendust
3
/bin/shsuposição cultural! * Se "aqui" estiver cshe a variável noclobberestiver definida, você realmente obterá file: File exists. Se alguém disser "eu entendi", não assuma que é um idiota e responda "não, não". * c2.com/cgi/wiki?AmericanCulturalAssumption
clacke 16/03
1
@clacke Se alguém decide usar um shell diferente do que todos os outros, deve declarar isso expressamente se estiver enfrentando problemas. Ao contrário da nacionalidade, todos têm sua livre escolha de concha.
SeldomNeedy 25/05
2
@SeldomNeedy Talvez eles estejam procurando ajuda porque nem sabem que estão usando um shell diferente do que todos os outros.
clacke
20

Talvez a adição de um diretório vazio pareça ser o caminho de menor resistência, porque você possui scripts que esperam que esse diretório exista (talvez porque seja um destino para os binários gerados). Outra abordagem seria modificar seus scripts para criar o diretório conforme necessário .

mkdir --parents .generated/bin ## create a folder for storing generated binaries
mv myprogram1 myprogram2 .generated/bin ## populate the directory as needed

Neste exemplo, você pode fazer check-in de um link simbólico (quebrado) para o diretório para poder acessá-lo sem o prefixo ".generated" (mas isso é opcional).

ln -sf .generated/bin bin
git add bin

Quando você deseja limpar sua árvore de fontes, pode:

rm -rf .generated ## this should be in a "clean" script or in a makefile

Se você adotar a abordagem frequentemente sugerida de fazer check-in em uma pasta quase vazia, você tem a menor complexidade de excluir o conteúdo sem excluir também o arquivo ".gitignore".

Você pode ignorar todos os seus arquivos gerados adicionando o seguinte ao seu .gitignore raiz:

.generated
nobar
fonte
1
Nota: O link simbólico que sugeri é "quebrado" em um checkout limpo, porque o .generateddiretório não existe inicialmente. Ele não será mais quebrado depois que você fizer sua compilação.
Nobar
2
Concordo que em alguns casos é uma boa ideia, mas em outros (como distribuir um projeto em que você tem um esqueleto vazio com pastas como modelos / e visualizações /), você deseja que o usuário tenha esses diretórios à mão do que ter que ler manualmente, ler os documentos, e pode ser um pouco demais esperar que eles executem algum tipo de script de instalação após a clonagem do repositório. Penso que esta resposta em combinação com a resposta README da @ john-mee deve abranger a maioria, senão todos os casos.
moopet
14

Também enfrentei o problema com diretórios vazios. O problema com o uso de arquivos de espaço reservado é que você precisa criá-los e excluí-los, se não forem mais necessários (porque mais tarde foram adicionados subdiretórios ou arquivos. Com grandes árvores de origem, o gerenciamento desses arquivos de espaço reservado pode ser complicado e ocorrer um erro propenso.

Por isso, decidi escrever uma ferramenta de código aberto que pode gerenciar a criação / exclusão desses arquivos de espaço reservado automaticamente. Ele foi escrito para a plataforma .NET e é executado em Mono (.NET para Linux) e Windows.

Basta dar uma olhada em: http://code.google.com/p/markemptydirs


fonte
14

Gosto das respostas de @ Artur79 e @mjs, por isso tenho usado uma combinação de ambos e o tornou um padrão para nossos projetos.

find . -type d -empty -exec touch {}/.gitkeep \;

No entanto, apenas alguns de nossos desenvolvedores trabalham no Mac ou Linux. Muito trabalho no Windows e não consegui encontrar uma única linha equivalente para realizar o mesmo lá. Alguns tiveram a sorte de instalar o Cygwin por outros motivos, mas prescrevê-lo apenas por isso parecia um exagero.

Edite para uma solução melhor

Portanto, como a maioria dos nossos desenvolvedores já possui o Ant instalado, a primeira coisa que pensei foi montar um arquivo de construção do Ant para fazer isso independentemente da plataforma. Ainda pode ser encontrado aqui

No entanto , mais tarde pensei que seria melhor transformar isso em um pequeno comando utilitário, então recriei-o usando Python e publiquei-o no PyPI aqui . Você pode instalá-lo simplesmente executando:

pip3 install gitkeep2

Isso permitirá que você crie e remova .gitkeeparquivos recursivamente e também adicione mensagens a eles para que seus colegas entendam por que esses diretórios são importantes. Este último bit é bônus. Eu pensei que seria bom se os .gitkeeparquivos pudessem ser auto-documentados.

$ gitkeep --help
Usage: gitkeep [OPTIONS] PATH

  Add a .gitkeep file to a directory in order to push them into a Git repo
  even if they're empty.

  Read more about why this is necessary at: https://git.wiki.kernel.org/inde
  x.php/Git_FAQ#Can_I_add_empty_directories.3F

Options:
  -r, --recursive     Add or remove the .gitkeep files recursively for all
                      sub-directories in the specified path.
  -l, --let-go        Remove the .gitkeep files from the specified path.
  -e, --empty         Create empty .gitkeep files. This will ignore any
                      message provided
  -m, --message TEXT  A message to be included in the .gitkeep file, ideally
                      used to explain why it's important to push the specified
                      directory to source control even if it's empty.
  -v, --verbose       Print out everything.
  --help              Show this message and exit.

Espero que você ache útil.

Mig82
fonte
13

Você não pode e infelizmente nunca será capaz. Esta é uma decisão tomada pelo próprio Linus Torvald. Ele sabe o que é bom para nós.

Há um discurso retórico por aí em algum lugar que li uma vez.

Eu encontrei Re: Diretórios vazios .. , mas talvez haja outro.

Você tem que viver com as soluções alternativas ... infelizmente.

user2334883
fonte
1
Sei que você postou isso como um exemplo de argumento ruim, mas agradeço o link, porque na verdade é um argumento bem fundamentado contra o rastreamento de diretórios. ;-)
clacke 16/03/2015
1
Essa resposta parece ser inconsistente, pois no próximo post do thread referenciado, Linus Torvald diz que espera que eles precisem adicionar rastreamento de diretório: markmail.org/message/libip4vpvvxhyqbl . De fato, ele diz que "gostaria de receber correções que [adicionem suporte ao rastreamento de diretórios vazios]"
Patrick M
Patrick, ele também usa a palavra "idiota" lá. Eu suspeito que o texto dele aborda as pessoas aqui neste tópico e, portanto, presumo que ele não implementará algo "idiota" no Git por si mesmo.
user2334883
10

Quando você adiciona um .gitignorearquivo, se você deseja colocar qualquer quantidade de conteúdo (que você deseja que o Git ignore), adicione uma única linha com apenas um asterisco *para garantir que você não adicione acidentalmente o conteúdo ignorado. .

Michael Johnson
fonte
9

Não há como fazer com que o Git rastreie diretórios; portanto, a única solução é adicionar um arquivo de espaço reservado no diretório que você deseja que o Git rastreie.

O arquivo pode ser nomeado e conter o que você quiser, mas a maioria das pessoas usa um arquivo vazio com o nome .gitkeep(embora algumas pessoas prefiram o agendador de VCS .keep).

O prefixo . marca como um arquivo oculto.

Outra idéia seria adicionar um READMEarquivo explicando para que o diretório será usado.

Zaz
fonte
8

Como mencionado, não é possível adicionar diretórios vazios, mas aqui está um liner que adiciona arquivos .gitignore vazios a todos os diretórios.

ruby -e 'require "fileutils" ; Dir.glob(["target_directory","target_directory/**"]).each { |f| FileUtils.touch(File.join(f, ".gitignore")) if File.directory?(f) }'

Coloquei isso em um Rakefile para facilitar o acesso.

Peter Hoeg
fonte
6
Eu prefiro usarfind . -type d -empty -print0 | xargs --null bash -c 'for a; do { echo "*"; echo "!.gitignore"; } >>"$a/.gitignore"; done' --
Tino
8

A solução de Jamie Flournoy funciona muito bem. Aqui está uma versão um pouco aprimorada para manter o .htaccess:

# Ignore everything in this directory
*
# Except this file
!.gitignore
!.htaccess

Com esta solução, você pode confirmar uma pasta vazia, por exemplo /log, /tmpou /cachea pasta permanecerá vazia.

romano
fonte
2
Ele quer manter um diretório vazio e não um arquivo.
Gvsrepins 29/07
2
E mencionei que ele também manterá o .htaccess. Exemplo: se um software possui um diretório para arquivos de log (como oxid eshop) que não deve ser acessível via web, existe um .htaccess no diretório. Se você colocar o .gitignore acima mencionado na pasta, o .htaccess não será confirmado e a pasta estará acessível via web.
Roman
Se você tiver um arquivo .htaccess sob controle de versão, já terá o diretório que o contém sob controle de versão. Portanto, o problema já está resolvido - o arquivo .gitignore se torna irrelevante.
Ponkadoodle
1
@ Wallacoloo Relacionado à pergunta de que você está certo, no entanto, o arquivo é útil, vou usá-lo para um diretório de upload como aquele onde os arquivos devem ser protegidos por .htaccess. Ao contrário da explicação romana, o arquivo .htaccess será confirmado, pois é excluído pela regra de ignorar. [discussão antiga, eu sei]
David
7

Eu sempre construo uma função para verificar minha estrutura de pastas desejada e construí-la para mim dentro do projeto. Isso contorna esse problema, pois as pastas vazias são mantidas no Git por proxy.

function check_page_custom_folder_structure () {
    if (!is_dir(TEMPLATEPATH."/page-customs"))
        mkdir(TEMPLATEPATH."/page-customs");    
    if (!is_dir(TEMPLATEPATH."/page-customs/css"))
        mkdir(TEMPLATEPATH."/page-customs/css");
    if (!is_dir(TEMPLATEPATH."/page-customs/js"))
        mkdir(TEMPLATEPATH."/page-customs/js");
}

Isso está em PHP, mas tenho certeza de que a maioria das linguagens suporta a mesma funcionalidade e, como a criação das pastas é cuidada pelo aplicativo, as pastas sempre estarão lá.

Fuzz leve
fonte
2
Só para estarmos todos na mesma página, não faço mais isso. É uma perda de tempo. A .gitkeepconvenção é uma prática muito melhor.
Mild Fuzz
Não vejo como isso pode ser uma perda de tempo. Quando seu TEMPLATEPATH é obviamente dinâmico, você não pode usar a solução .gitkeep. E mesmo com uma estrutura de pastas não dinâmica, você deve adicionar mais algumas coisas em vez de remover a solução muito boa de verificar diretórios, por exemplo, verifique as permissões e chmod os arquivos. Adicionar uma maneira de marcar diretórios dentro de um .gitignore global seria perfeito para mim. Algo como #keep / path / to / dir
Jochen Schultz
7

Aqui está um truque, mas é engraçado que funcione (Git 2.2.1). Semelhante ao que a @Teka sugeriu, mas mais fácil de lembrar:

  • Adicione um submódulo a qualquer repositório ( git submodule add path_to_repo)
  • Isso adicionará uma pasta e um arquivo .submodules. Confirme uma alteração.
  • Exclua o .submodulesarquivo e confirme a alteração.

Agora, você tem um diretório que é criado quando o commit é retirado. Uma coisa interessante, porém, é que, se você olhar para o conteúdo do objeto em árvore deste arquivo, obterá:

fatal: Não é um nome de objeto válido b64338b90b4209263b50244d18278c0999867193

Eu não recomendaria usá-lo, pois ele pode parar de funcionar nas versões futuras do Git. O que pode deixar seu repositório corrompido.

Stanislav Bashkyrtsev
fonte
Isso realmente funciona, mas acho que confunde o IntelliJ ...: |
Rogerdpack
Eu criei uma melhor solução com base nesta que não tem esses inconvenientes: stackoverflow.com/a/58543445/277882
ntninja
7

Muitos já responderam a esta pergunta. Apenas adicionando uma versão do PowerShell aqui.

Encontre todas as pastas vazias no diretório

Adicione um arquivo .gitkeep vazio lá

Get-ChildItem 'Path to your Folder' -Recurse -Directory | Where-Object {[System.IO.Directory]::GetFileSystemEntries($_.FullName).Count -eq 0} | ForEach-Object { New-Item ($_.FullName + "\.gitkeep") -ItemType file}
Hainan.Z
fonte
Nice. Fir ༼ ͡☉ ͜ʖ ͡☉
FiringSquadWitness
6

Se você deseja adicionar uma pasta que abriga muitos dados transitórios em vários diretórios semânticos, uma abordagem é adicionar algo assim à sua raiz .gitignore ...

/app/data/**/*.* !/app/data/**/*.md

Em seguida, você pode confirmar arquivos README.md descritivos (ou arquivos em branco, não importa, desde que você possa direcioná-los exclusivamente como *.mdneste caso) em cada diretório para garantir que todos os diretórios permaneçam parte do repositório, mas o arquivos (com extensões) são mantidos ignorados. LIMITAÇÃO:. não são permitidos nos nomes de diretório!

Você pode preencher todos esses diretórios com arquivos xml / images ou qualquer outra coisa e adicionar mais diretórios em /app/data/ o tempo, à medida que as necessidades de armazenamento do seu aplicativo se desenvolverem (com os arquivos README.md servindo para gravar em uma descrição do que é cada diretório de armazenamento exatamente).

Não há necessidade de alterar ainda mais .gitignoreou descentralizar, criando um novo .gitignorepara cada novo diretório. Provavelmente não é a solução mais inteligente, mas é concisa em termos de gitignore e sempre funciona para mim. Agradável e simples! ;)

insira a descrição da imagem aqui

ajmedway
fonte
6

Uma maneira fácil de fazer isso é adicionando um .gitkeeparquivo ao diretório que você deseja (atualmente) manter vazio.

Consulte esta resposta do SOF para obter mais informações - o que também explica por que algumas pessoas acham a convenção concorrente de adicionar um arquivo .gitignore (conforme indicado em muitas respostas aqui) confusas.

arcseldon
fonte
4

Adicionando mais uma opção à briga.

Supondo que você gostaria de adicionar um diretório a gitele, para todos os fins relacionados a git, deve permanecer vazio e nunca ter seu conteúdo rastreado, .gitignorecomo sugerido várias vezes aqui, isso fará o truque.

O formato, como mencionado, é:

*
!.gitignore

Agora, se você quiser uma maneira de fazer isso na linha de comando, de uma só vez, enquanto estiver dentro do diretório que deseja adicionar, você pode executar:

$ echo "*" > .gitignore && echo '!.gitignore' >> .gitignore && git add .gitignore

Eu mesmo, tenho um script de shell que uso para fazer isso. Nomeie o script como desejar, e adicione-o em algum lugar do seu caminho de inclusão ou faça referência diretamente a ele:

#!/bin/bash

dir=''

if [ "$1" != "" ]; then
    dir="$1/"
fi

echo "*" > $dir.gitignore && \
echo '!.gitignore' >> $dir.gitignore && \
git add $dir.gitignore

Com isso, você pode executá-lo no diretório que deseja adicionar ou referenciar o diretório como seu primeiro e único parâmetro:

$ ignore_dir ./some/directory

Outra opção (em resposta a um comentário por @GreenAsJade), se você deseja acompanhar uma pasta vazia que MAIO conter arquivos rastreados no futuro, mas estará vazio por enquanto, você pode omitir a *partir do .gitignorearquivo, e verificar que em. Basicamente, todo o arquivo está dizendo é "não me ignore ", mas, caso contrário, o diretório está vazio e rastreado.

Seu .gitignorearquivo seria semelhante a:

!.gitignore

É isso, verifique isso e você terá um diretório vazio, mas rastreado, no qual poderá rastrear arquivos posteriormente.

A razão pela qual sugiro manter essa linha no arquivo é que ela fornece o .gitignoreobjetivo. Caso contrário, alguém abaixo da linha pode pensar em removê-lo. Pode ser útil se você colocar um comentário acima da linha.

Mike
fonte
4

Às vezes, você precisa lidar com bibliotecas ou softwares gravados incorretos, que precisam de um diretório vazio e existente "real". Colocar um simples .gitignoreou .keeppode quebrá-los e causar um bug. O seguinte pode ajudar nesses casos, mas não há garantia ...

Primeiro, crie o diretório necessário:

mkdir empty

Em seguida, você adiciona um link simbólico quebrado a esse diretório (mas em qualquer outro caso que não seja o caso de uso descrito acima, use a READMEcom uma explicação):

ln -s .this.directory empty/.keep

Para ignorar arquivos nesse diretório, você pode adicioná-lo à sua raiz .gitignore:

echo "/empty" >> .gitignore

Para adicionar o arquivo ignorado, use um parâmetro para forçá-lo:

git add -f empty/.keep

Após a confirmação, você tem um link simbólico quebrado no seu índice e o git cria o diretório O link quebrado tem algumas vantagens, pois não é um arquivo regular e aponta para nenhum arquivo regular. Por isso, até se encaixa na parte da pergunta "(que não contém arquivos)", não pela intenção, mas pelo significado, eu acho:

find empty -type f

Este comando mostra um resultado vazio, pois nenhum arquivo está presente neste diretório. Portanto, a maioria dos aplicativos, que obtém todos os arquivos em um diretório, normalmente não vê esse link, pelo menos se houver um "arquivo existente" ou "legível". Mesmo alguns scripts não encontrarão nenhum arquivo lá:

$ php -r "var_export(glob('empty/.*'));"
array (
  0 => 'empty/.',
  1 => 'empty/..',
)

Mas eu recomendo fortemente usar essa solução apenas em circunstâncias especiais; um bom escrito READMEem um diretório vazio geralmente é uma solução melhor. (E eu não sei se isso funciona com um sistema de arquivos do Windows ...)

Trendfischer
fonte
4

Lendo as respostas de @ofavre e @ stanislav-bashkyrtsev usando referências quebradas do sub-módulo GIT para criar os diretórios GIT, estou surpreso que ninguém tenha sugerido ainda essa simples alteração da idéia de tornar tudo mais saudável e seguro:

Em vez de invadir um submódulo falso no GIT , basta adicionar um módulo real vazio .

Digite: https://gitlab.com/empty-repo/empty.git

Um repositório GIT com exatamente um commit:

commit e84d7b81f0033399e325b8037ed2b801a5c994e0
Author: Nobody <none>
Date: Thu Jan 1 00:00:00 1970 +0000

Nenhuma mensagem, nenhum arquivo confirmado.

Uso

Para adicionar um diretório vazio ao seu repositório GIT:

git submodule add https://gitlab.com/empty-repo/empty.git path/to/dir

Para converter todos os diretórios vazios existentes em submódulos:

find . -type d -empty -delete -exec git submodule add -f https://gitlab.com/empty-repo/empty.git \{\} \;

O Git armazenará o hash de confirmação mais recente ao criar a referência do submódulo, para que você não precise se preocupar comigo (ou no GitLab) usando isso para injetar arquivos maliciosos. Infelizmente, não encontrei nenhuma maneira de forçar qual ID de confirmação é usado durante a finalização da compra, então você terá que verificar manualmente se a ID de confirmação de referência está e84d7b81f0033399e325b8037ed2b801a5c994e0usandogit submodule status após adicionar o repositório.

Ainda não é uma solução nativa, mas o melhor que provavelmente podemos ter sem que alguém tenha as mãos realmente , realmente sujo na base de código do GIT.

Apêndice: Recriando este commit

Você deve recriar essa confirmação exata usando (em um diretório vazio):

# Initialize new GIT repository
git init

# Set author data (don't set it as part of the `git commit` command or your default data will be stored as “commit author”)
git config --local user.name "Nobody"
git config --local user.email "none"

# Set both the commit and the author date to the start of the Unix epoch (this cannot be done using `git commit` directly)
export GIT_AUTHOR_DATE="Thu Jan 1 00:00:00 1970 +0000"
export GIT_COMMITTER_DATE="Thu Jan 1 00:00:00 1970 +0000"

# Add root commit
git commit --allow-empty --allow-empty-message --no-edit

Criar confirmações reproduzíveis do GIT é surpreendentemente difícil…

ntninja
fonte
3

Você não pode. Esta é uma decisão de design intencional pelos mantenedores do Git. Basicamente, o objetivo de um sistema de gerenciamento de código-fonte como o Git é gerenciar código-fonte e diretórios vazios não são código-fonte. O Git também é frequentemente descrito como um rastreador de conteúdo e, novamente, diretórios vazios não são conteúdo (pelo contrário, na verdade), portanto, eles não são rastreados.

Jörg W Mittag
fonte
60
Eu contesto essa visão. Estrutura é conteúdo e tudo o que você nomeia contribui para o conteúdo.
ThomasH
20
Um arquivo vazio também não é um código-fonte ou conteúdo. É apenas um nome. No entanto, o Git rastreará com satisfação arquivos vazios. Não acho que tenha sido uma decisão intencional de design fazer o Git se recusar a rastrear diretórios vazios. Eu acho que rastrear diretórios vazios é um recurso que simplesmente não é necessário 99% do tempo, então eles não se preocuparam em fazer o trabalho extra necessário para fazê-lo funcionar corretamente. O Git pode fazer isso se alguém quiser o recurso o suficiente para implementá-lo. Duvido que os mantenedores do Git se oponham a esse patch se ele fosse feito corretamente.
Dan Molding
1
@TobyAllen aqui está o link atualizado da FAQ. A resposta superior também é recomendada pela FAQ com instruções mais precisas.
Daniel Da Cunha
3
É um recurso ausente (e de baixa prioridade), não uma limitação intencional. Das perguntas frequentes do Git: Atualmente, o design do índice Git (área de preparação) permite apenas a listagem de arquivos, e ninguém competente o suficiente para fazer a alteração para permitir diretórios vazios se preocupou o suficiente com essa situação para remediá-la.
precisa saber é o seguinte
Realmente não concordo. Posso encontrar vários motivos pelos quais desejo rastrear uma pasta vazia. Por exemplo, estou desenvolvendo uma estrutura MVC PHP muito leve para meus projetos. Tenho pastas específicas para colocar modelos, visualizações, etc. Quando crio um novo site com base na minha estrutura, essas pastas estão vazias, pois não existem modelos ou visualizações por padrão, mas eu preciso que a pasta exista, caso contrário, minha estrutura ganhou trabalha!
Gladen
2

Você pode salvar esse código como create_readme.php e executar o código PHP no diretório raiz do seu projeto Git.

> php create_readme.php

Ele adicionará arquivos LEIA-ME a todos os diretórios vazios, para que esses diretórios sejam adicionados ao índice.

<?php
    $path = realpath('.');
    $objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path),       RecursiveIteratorIterator::SELF_FIRST);
    foreach($objects as $name => $object){
        if ( is_dir($name) && ! is_empty_folder($name) ){
            echo "$name\n" ;
            exec("touch ".$name."/"."README");
        }
    }

    function is_empty_folder($folder) {
        $files = opendir($folder);
        while ($file = readdir($files)) {
            if ($file != '.' && $file != '..')
                return true; // Not empty
            }
        }
?>

Então faça

git commit -m "message"
git push
user665190
fonte