Como faço para clonar um subdiretório apenas de um repository Git?

Eu tenho meu repository Git que, na raiz, tem dois subdiretórios:

/finisht /static 

Quando isso estava no SVN , o /finisht era verificado em um lugar, enquanto o /static estava em outro lugar, assim:

 svn co svn+ssh://admin@domain.com/home/admin/repos/finisht/static static 

Existe uma maneira de fazer isso com o Git?

    Esta resposta está desatualizada e só se aplica a versões do git menores que 1.7.0 (fevereiro de 2012). Veja abaixo as versões mais recentes.

    Não, isso não é possível no Git.

    Implementar algo assim no Git seria um esforço substancial e significaria que a integridade do repository do lado do cliente não poderia mais ser garantida. Se você estiver interessado, procure por discussões em “clone esparso” e “busca esparsa” na lista de discussão git.

    Em geral, o consenso na comunidade Git é que se você tem vários diretórios que são sempre verificados independentemente, então estes são realmente dois projetos diferentes e devem viver em dois repositorys diferentes. Você pode colá-los juntos novamente usando o Git Submodules .

    O que você está tentando fazer é chamado de checkout esparso , e esse recurso foi adicionado no git 1.7.0 (fev 2012). As etapas para fazer um clone esparso são as seguintes:

     mkdir  cd  git init git remote add -f origin  

    Isso cria um repository vazio com seu controle remoto e busca todos os objects, mas não os verifica. Então faça:

     git config core.sparseCheckout true 

    Agora você precisa definir quais arquivos / pastas deseja realmente fazer check-out. Isso é feito listando-os em .git/info/sparse-checkout , por exemplo:

     echo "some/dir/" >> .git/info/sparse-checkout echo "another/sub/tree" >> .git/info/sparse-checkout 

    Por último, mas não menos importante, atualize seu repository vazio com o estado do controle remoto:

     git pull origin master 

    Agora você terá arquivos “check-out” para some/dir e another/sub/tree no seu sistema de arquivos (com esses caminhos ainda) e nenhum outro caminho presente.

    Você pode querer dar uma olhada no tutorial estendido e provavelmente deve ler a documentação oficial para o checkout esparso .

    Como uma function:

     function git_sparse_clone() ( rurl="$1" localdir="$2" && shift 2 mkdir -p "$localdir" cd "$localdir" git init git remote add -f origin "$rurl" git config core.sparseCheckout true # Loops over remaining args for i; do echo "$i" >> .git/info/sparse-checkout done git pull origin master ) 

    Uso:

     git_sparse_clone "http://github.com/tj/n" "./local/location" "/bin" 

    Observe que isso ainda fará o download do repository inteiro do servidor – apenas o checkout é reduzido em tamanho. No momento, não é possível clonar apenas um único diretório. Mas se você não precisa do histórico do repository, você pode pelo menos economizar em largura de banda criando um clone superficial. Veja a resposta de udondan abaixo para obter informações sobre como combinar o clone superficial e o checkout esparso.

    Você pode combinar os resources de verificação esparsa e clone superficial . O clone superficial corta o histórico e o check-out esparso apenas puxa os arquivos correspondentes aos seus padrões.

     git init  cd  git remote add origin  git config core.sparsecheckout true echo "finisht/*" >> .git/info/sparse-checkout git pull --depth=1 origin master 

    Você precisará do mínimo de git 1.9 para que isso funcione. Testado sozinho apenas com 2.2.0 e 2.2.2.

    Desta forma, você ainda será capaz de empurrar , o que não é possível com o git archive .

    Para outros usuários que só querem baixar um arquivo / pasta do github, simplesmente use:

     svn export /trunk/ 

    por exemplo

     svn export https://github.com/lodash/lodash.com/trunk/docs 

    (sim, isso é svn aqui. aparentemente em 2016 você ainda precisa do svn para simplesmente baixar alguns arquivos do github)

    Cortesia: Faça o download de uma única pasta ou diretório de um repository do GitHub

    Importante – Atualize a URL do github e substitua /tree/master/ por ‘/ trunk /’.

    Como script bash:

     git-download(){ folder=${@/tree\/master/trunk} folder=${folder/blob\/master/trunk} svn export $folder } 

    Nota Este método faz o download de uma pasta, não o clona / efetua o check-out. Você não pode enviar as alterações de volta ao repository. Por outro lado – isso resulta em downloads menores em comparação com o checkout esparso ou o checkout superficial.

    O Git 1.7.0 tem “checkouts esparsos”. Veja “core.sparseCheckout” no manpage de configuração do git , “Check-out esparso” na página de manual git read-tree , e “Skip-worktree bit” no git update-index manpage .

    A interface não é tão conveniente quanto a do SVN (por exemplo, não há como fazer um checkout esparso no momento de um clone inicial), mas a funcionalidade básica na qual as interfaces mais simples poderiam ser construídas está agora disponível.

    Se você nunca planeja interagir com o repository do qual você clonou, você pode fazer um clone git completo e rewrite seu repository usando git filter-branch –subdirectory-filter . Desta forma, pelo menos, o histórico será preservado.

    Isso parece muito mais simples:

     git archive --remote=   | tar xvf - 

    Não é possível clonar subdiretórios apenas com o Git, mas abaixo estão algumas soluções alternativas.

    Filial de filtro

    Você pode querer rewrite o repository para parecer como trunk/public_html/ tinha sido a raiz do seu projeto, e descartar todos os outros históricos (usando o filter-branch ), tente na ramificação do checkout:

     git filter-branch --subdirectory-filter trunk/public_html -- --all 

    Notas: O -- que separa opções de ramificação de filtro das opções de revisão e --all para rewrite todas as ramificações e tags. Todas as informações, incluindo tempos de confirmação originais ou informações de mesclagem, serão preservadas . Esse comando homenageia o arquivo .git/info/grafts e refs no refs/replace/ namespace, portanto, se você tiver quaisquer referências ou referências de substituição definidas, a execução desse comando as tornará permanentes.

    Atenção! O histórico reescrito terá nomes de objects diferentes para todos os objects e não convergirá com o ramo original. Você não poderá enviar e distribuir facilmente a ramificação reescrita na parte superior da ramificação original. Por favor, não use este comando se você não souber todas as implicações, e evite usá-lo de qualquer maneira, se um único commit simples for suficiente para resolver seu problema.


    Cheque esparso

    Aqui estão os passos simples com a abordagem de checkout esparsa que preencherá o diretório de trabalho de forma esparsa, para que você possa dizer ao Git quais pastas ou arquivos no diretório de trabalho valem a pena conferir.

    1. Repositório clone como de costume ( --no-checkout é opcional):

       git clone --no-checkout git@foo/bar.git cd bar 

      Você pode pular esta etapa, se você já tiver o seu repository clonado.

      Sugestão: Para grandes recompras, considere o clone superficial ( --depth 1 ) para fazer o checkout apenas da revisão mais recente e / e --single-branch apenas.

    2. Ative a opção sparseCheckout :

       git config core.sparseCheckout true 
    3. Especifique pasta (s) para check-out esparso ( sem espaço no final):

       echo "trunk/public_html/*"> .git/info/sparse-checkout 

      ou edite .git/info/sparse-checkout .

    4. Finalize a ramificação (por exemplo, master ):

       git checkout master 

    Agora você deve ter selecionado pastas em seu diretório atual.

    Você pode considerar links simbólicos se tiver muitos níveis de diretórios ou ramificação de filtragem.


    Acabei de escrever um script para o GitHub .

    Uso:

     python get_git_sub_dir.py path/to/sub/dir  

    Aqui está um script de shell que eu escrevi para o caso de uso de um único subdiretório check-out esparso

    coSubDir.sh

     localRepo=$1 remoteRepo=$2 subDir=$3 # Create local repository for subdirectory checkout, make it hidden to avoid having to drill down to the subfolder mkdir ./.$localRepo cd ./.$localRepo git init git remote add -f origin $remoteRepo git config core.sparseCheckout true # Add the subdirectory of interest to the sparse checkout. echo $subDir >> .git/info/sparse-checkout git pull origin master # Create convenience symlink to the subdirectory of interest cd .. ln -s ./.$localRepo$subDir $localRepo