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




nuevo github (23)

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

Como um aparte, este é um problema de implementação, não um problema fundamental de design de armazenamento Git. Como já foi mencionado várias 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 ele não pudesse ou não devesse ser feito.

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


Eu sempre construo uma função para checar 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á no PHP, mas tenho certeza que a maioria dos idiomas suporta a mesma funcionalidade, e como a criação das pastas é cuidada pelo aplicativo, as pastas sempre estarão lá.


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


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) }'

Eu coloquei isso em um Rakefile para facilitar o acesso.


O Git não rastreia diretórios vazios. Veja o Git FAQ para mais explicações. A solução sugerida é colocar um arquivo .gitignore no diretório vazio. Eu não gosto dessa solução, porque o .gitignore é "escondido" pela convenção Unix. Também não há explicação porque os diretórios estão vazios.

Eu sugiro colocar um arquivo README no diretório vazio explicando porque o diretório está vazio e porque ele precisa ser rastreado no Git. Com o arquivo README no lugar, 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. Se não, então faça um. Essa é uma solução muito melhor do que colocar diretórios vazios no git.

Então você tem alguma razão pela qual você precisa de um diretório vazio no git. Coloque esse motivo no arquivo README. Dessa forma, outros desenvolvedores (e futuros 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 tiver sido 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 README, coloque as seguintes linhas no seu .gitignore :

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

Alternativamente, você poderia 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

Eu tenho enfrentado o problema com diretórios vazios também. O problema com o uso de arquivos de espaço reservado é que você precisa criá-los e excluí-los, se eles não forem mais necessários (porque mais tarde foram adicionados subdiretórios ou arquivos. Com grandes árvores de origem gerenciando esses arquivos de espaço reservado podem ser incômodos e erro propenso.

É por isso que decidi escrever uma ferramenta de código aberto que possa gerenciar a criação / exclusão desses arquivos de espaço reservado automaticamente. Ele é 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


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

Post original abaixo:

Eu encontrei uma solução enquanto brincava com os internos do Git!

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

    $ mkdir path/to/empty-folder
    
  3. Adicione-o ao í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, em seguida, insira a segunda linha. Pressione Enter e, em seguida, Ctrl + D para finalizar sua entrada. Nota: o formato é modo [SPACE] tipo [ESPAÇO] SHA-1hash [TAB] caminho (a guia é importante, a formatação de resposta não preserva isso).

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

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

A árvore vazia SHA-1 pode ser encontrada criando um novo repositório Git vazio, cd dentro dela e emitindo git write-tree , que produz a árvore vazia SHA-1.

EDITAR:

Eu tenho usado essa solução desde que a encontrei. Parece funcionar exatamente da mesma maneira que criar um submódulo, exceto que nenhum módulo é definido em lugar algum. Isto leva a erros ao emitir o git submodule init|update . O problema é que git update-index reescreve a parte da 040000 tree em 160000 commit .

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

No entanto, se você ainda não usa (e não) usa qualquer submódulo do Git em seu repositório, e a pasta "vazia" permanecerá vazia ou se você quiser que o Git saiba de sua existência e ignore seu conteúdo, você pode ir com esse ajuste. Indo da maneira usual com submódulos leva mais passos que esse ajuste.


touch .keep

No Linux, isso cria um arquivo vazio chamado .keep . Esse nome é preferido em relação ao .gitkeep pois o primeiro é agnóstico ao Git, enquanto o segundo é específico do Git. Em segundo lugar, como outro usuário notou, a convenção de prefixo .git deve ser reservada para arquivos e diretórios que o próprio Git usa.

Como alternativa, conforme observado em outra answer , o diretório pode conter um arquivo README ou README.md descritivo.

Claro que isso requer que a presença do arquivo não cause a quebra do seu aplicativo.


Outra maneira de fazer um diretório ficar vazio (no repositório) é criar um arquivo .gitignore dentro desse diretório que contém estas quatro linhas:

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

Então você não precisa fazer o pedido corretamente do jeito que você precisa fazer na solution do m104.

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

Tornando o comentário de @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 questão estarão procurando. Essa solução garante que o diretório permaneça vazio. Diz "Eu realmente nunca quero que os arquivos sejam registrados aqui". Ao contrário de "Eu não tenho nenhum arquivo para verificar aqui, ainda, mas eu preciso do diretório aqui, os arquivos podem vir mais tarde".


Você poderia sempre colocar um arquivo README no diretório com uma explicação de porque você deseja que este diretório, caso contrário vazio, no repositório.


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

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

Com esta solução, você pode enviar uma pasta vazia, por exemplo /log, /tmpou /cachee a pasta ficará vazia.


Se você quiser adicionar uma pasta que hospedará muitos dados temporários em vários diretórios semânticos, então uma abordagem é adicionar algo como isto em sua raiz .gitignore ...

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

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

Você pode preencher todos esses diretórios com arquivos xml / images ou qualquer outro e incluir mais diretórios ao /app/data/longo do tempo conforme as necessidades de armazenamento para seu aplicativo se desenvolvem (com os arquivos README.md sendo exibidos para gravar em uma descrição do que cada diretório de armazenamento é para 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 e funciona sempre para mim. Bom e simples! ;)


Você não pode. Veja o FAQ do Git .

Atualmente, o design do índice git (área de preparação) permite apenas que os arquivos sejam listados, 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 conta própria.

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

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


Por que precisamos de pastas com versões vazias

Primeiras coisas primeiro:

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

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

  • scaffolding uma estrutura de pasta predefinida e disponibilizar esta estrutura para cada usuário / colaborador do repositório; ou, como um caso especializado do acima, criando uma pasta para arquivos temporários , como um cache/ ou logs/ diretórios, onde queremos fornecer a pasta, mas .gitignore seu conteúdo
  • relacionado ao início, alguns projetos não funcionarão sem algumas pastas (o que geralmente é um indício de um projeto mal projetado, mas é um cenário real frequente e talvez possa haver, digamos, problemas de permissão).

Algumas soluções sugeridas

Muitos usuários sugerem:

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

Embora ambas as soluções certamente funcionem , acho que elas são inconsistentes com uma abordagem significativa para o versionamento do Git.

  • Por que você deveria colocar arquivos falsos ou READMEs que talvez você realmente não queira em seu projeto?
  • Por que usar o .gitignore para fazer uma coisa ( manter arquivos) que é exatamente o oposto do que ele significa ( excluindo 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 controle de versão.

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

  • Você usa um arquivo com o único propósito de manter a pasta. Você não coloca nenhuma informação que não queira colocar.

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

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

  • Nomeando isto .gitkeep faz isto muito claro e direto do próprio nome do arquivo (e também para outros desenvolvedores que são bons para um projeto compartilhado e um das finalidades principais de um repositório de Git) que este arquivo é

    • Um arquivo não relacionado ao código (por causa do ponto principal e do nome)
    • Um arquivo claramente relacionado ao Git
    • Sua finalidade ( manter ) é claramente declarada e consistente e semanticamente oposta em seu significado de ignorar

Adoção

Eu vi a abordagem do .gitkeep adotada por frameworks muito importantes como o Laravel , o Angular-CLI .


Não há como fazer com que o Git rastreie diretórios, então a única solução é adicionar um arquivo de espaço reservado dentro do 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 chamado .gitkeep(embora algumas pessoas prefiram o VCS agnóstico .keep).

O prefixo .marca como um arquivo oculto.

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


Conforme descrito em outras respostas, o Git não consegue representar diretórios vazios em sua área de preparação. (Veja a FAQ do Git .) No entanto, se, para seus propósitos, um diretório estiver vazio o suficiente se contiver apenas um arquivo .gitignore , você poderá criar arquivos .gitignore em diretórios vazios somente via:

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

Talvez adicionar um diretório vazio pareça que seria o caminho de menor resistência porque você tem scripts que esperam que o diretório exista (talvez porque seja um destino para 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 verificar em um link simbólico (quebrado) para o diretório para que você possa acessá-lo sem o prefixo ".generated" (mas isso é opcional).

ln -sf .generated/bin bin
git add bin

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

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, terá a menor complexidade de excluir o conteúdo sem excluir o arquivo ".gitignore".

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

.generated

Você não pode. Esta é uma decisão de projeto intencional dos mantenedores do Git. Basicamente, o propósito de um Sistema de Gerenciamento de Código Fonte como o Git é gerenciar o código-fonte e os diretórios vazios não são código-fonte. O Git também é frequentemente descrito como um rastreador de conteúdo e, novamente, os diretórios vazios não estão contidos (muito pelo contrário, na verdade), portanto, eles não são rastreados.


Quando você adiciona um arquivo .gitignore , se você vai colocar qualquer quantidade de conteúdo (que você deseja que o Git ignore) você pode querer adicionar uma única linha com apenas um asterisco * para ter certeza de não adicionar o arquivo. conteúdo ignorado acidentalmente.


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

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

Agora, você tem um diretório que é criado quando a confirmação é finalizada. Uma coisa interessante é que se você olhar o conteúdo do objeto tree deste arquivo, você verá:

fatal: nome de objeto inválido b64338b90b4209263b50244d18278c0999867193

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


Eu gosto das respostas de @ Artur79 e @mjs então eu tenho usado uma combinação de ambos e o tornei um padrão para nossos projetos.

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

No entanto, apenas alguns de nossos desenvolvedores trabalham com Mac ou Linux. Muito trabalho no Windows e eu não consegui encontrar um one-liner simples equivalente para realizar o mesmo lá. Alguns tiveram a sorte de ter o Cygwin instalado por outras razões, mas prescrever o Cygwin apenas por isso pareceu um exagero.

Então, como a maioria dos nossos desenvolvedores já tem o Ant instalado, eu montei um arquivo de compilação para fazer isso independentemente da plataforma.

<?xml version="1.0" encoding="ISO-8859-1"?>
<project name="Gitkeep" basedir="." default="keep">
    <!--Apply to all subdirs of this dir-->
    <target name="keep" description="-> Add a .gitkeep file to all empty subdir's of this dir.">

        <!--Create a ref to all the subdirs in the tree of this dir-->
        <dirset id="dirs.ref" dir="./" includes="**/*"/>
        <!--Create a list of the subdirs under this dir-->
        <property name="dirs.list" refid="dirs.ref" />

        <!--For each subdir-->
        <for list="${dirs.list}" delimiter=";" param="dir">
            <sequential>
                <!--If the subdir is empty this target will add a .gitkeep file to it-->
                <antcall target="gitkeep" inheritall="false">
                    <param name="dir" value="@{dir}"/>
                </antcall>
            </sequential>
        </for>
    </target>

    <!--Add a .gitkeep file to a directory if it's empty-->
    <target name="gitkeep" description="-> Add a .gitkeep file to a specific subdir of this dir. Use -Ddir=relative/path/to/dir">

        <!--Create a ref of the files inside this dir-->
        <fileset dir="${dir}" id="contents.ref"/>

        <!--Create a path to the contents of this directory, ONLY if it's not empty-->
        <pathconvert refid="contents.ref" property="contents.path" setonempty="false"/>

        <if>
            <!--If the dir is empty create the .gitkeep file-->
            <not><isset property="contents.path"/></not>
            <then>
                <!--Create the .gitkeep file-->
                <echo message="Version this dir in Git even if its empty." file="./${dir}/.gitkeep" force="true" append="false"/>
            </then>
        </if>
    </target>
</project>

Agora eu posso simplesmente correr

ant -f gitkeep.xml

E isso cria um arquivo .gitkeep em qualquer subdiretório vazio. Mesmo no Windows :) Nota: Esse arquivo de compilação requer o jar do Ant Contrib .

Eu continuo trabalhando neste conceito here .

here


Às vezes, tenho repositórios com pastas que sempre contêm arquivos considerados "conteúdo", ou seja, não são arquivos que me interessem ser versionados e, portanto, nunca devem ser confirmados. Com o arquivo .gitignore do Git, você pode ignorar diretórios inteiros. Mas há momentos em que ter a pasta no repositório seria benéfico. Aqui está uma excelente solução para realizar essa necessidade.

O que eu fiz no passado foi colocar um arquivo .gitignore na raiz do meu repositório, e então excluir a pasta da seguinte forma:

/app/some-folder-to-exclude
/another-folder-to-exclude/*

No entanto, essas pastas não se tornam parte do repositório. Você poderia adicionar algo como um arquivo README lá. Mas você precisa dizer ao seu aplicativo para não se preocupar com o processamento de arquivos README.

Se o seu aplicativo depender das pastas existentes (embora vazias), basta adicionar um arquivo .gitignore à pasta em questão e usá-lo para atingir dois objetivos:

Diga ao Git que existe um arquivo na pasta, o que faz o Git adicioná-lo ao repositório. Diga ao Git para ignorar o conteúdo desta pasta, menos este arquivo em si. Aqui está o arquivo .gitignore para colocar dentro de seus diretórios vazios:

*
!.gitignore

A primeira linha (*) diz ao Git para ignorar tudo neste diretório. A segunda linha diz ao Git para não ignorar o arquivo .gitignore. Você pode colocar esse arquivo em todas as pastas vazias que você deseja adicionar ao repositório.


Às vezes você tem que lidar com bibliotecas ou softwares mal escritos, 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 nestes casos, mas nenhuma garantia ...

Primeiro crie o diretório necessário:

mkdir empty

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

ln -s .this.directory empty/.keep

Para ignorar arquivos neste diretório, você pode adicioná-lo em 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 o commit você tem um link simbólico quebrado em seu índice e o git cria o diretório. O link quebrado tem algumas vantagens, já que não é um arquivo regular e aponta para nenhum arquivo regular. Então, cabe até a 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, já que nenhum arquivo está presente neste diretório. Portanto, a maioria dos aplicativos, que obtém todos os arquivos em um diretório, geralmente não vê esse link, pelo menos se eles fizerem um "arquivo existir" ou um "for 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 esta solução apenas em circunstâncias especiais, uma boa escrita 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 ...)





git-add