Faça uma "exportação git" (como "svn export")?

2356

Fiquei me perguntando se existe uma boa solução "git export" que crie uma cópia de uma árvore sem o .gitdiretório do repositório. Existem pelo menos três métodos que conheço:

  1. git cloneseguido pela remoção do .gitdiretório do repositório.
  2. git checkout-index alude a essa funcionalidade, mas começa com "Basta ler a árvore desejada no índice ...", o que não sei ao certo como fazer.
  3. git-exporté um script de terceiros que essencialmente faz um git cloneem um local temporário seguido pelo rsync --exclude='.git'destino final.

Nenhuma dessas soluções realmente me parece satisfatória. O mais próximo svn exportpode ser a opção 1, porque ambos exigem que o diretório de destino esteja vazio primeiro. Mas a opção 2 parece ainda melhor, supondo que eu possa descobrir o que significa ler uma árvore no índice.

Greg Hewgill
fonte
1
@rnrTom: Veja a resposta de Somov. (não há nada "compactado" em um arquivo tar).
Etarion 23/05/12
23
O @mrTom git archive --format zip --output "output.zip" master -0fornecerá um arquivo descompactado (-0 é o sinalizador para descompactado). git-scm.com/docs/git-archive .
7
Concordo com o @mrTom e não acho que o arquivo esteja compactado ou descompactado é o principal problema. Com o SVN, posso obter exportum subdiretório de 250 kB diretamente do repositório remoto (que poderia ter 200 MB de tamanho, excluindo revisões) - e atingirei a rede apenas para transferência de download de 250 kB (mais ou menos). Com git, archivedeve estar ativado no servidor (por isso não posso experimentá-lo) - o clone --depth 1servidor ainda pode recuperar um repositório de, digamos, 25 MB, onde a .gitsubpasta sozinha ocupa 15 MB. Portanto, eu ainda diria que a resposta é "não".
Sdaau
@mrTom a resposta é na verdade SIM Veja a resposta do OP - o comando égit checkout-index
nocache
Aqui está uma maneira simples e agradável:git archive -o latest.zip HEAD
Evgeni Sergeev

Respostas:

2397

Provavelmente, a maneira mais simples de conseguir isso é com git archive. Se você realmente precisa apenas da árvore expandida, pode fazer algo assim.

git archive master | tar -x -C /somewhere/else

Na maioria das vezes eu preciso 'exportar' algo do git, eu quero um arquivo compactado em qualquer caso, então faço algo assim.

git archive master | bzip2 >source-tree.tar.bz2

Arquivo ZIP:

git archive --format zip --output /full/path/to/zipfile.zip master 

git help archive para mais detalhes, é bastante flexível.


Esteja ciente de que, embora o arquivo morto não contenha o diretório .git, ele conterá outros arquivos específicos do git ocultos, como .gitignore, .gitattributes, etc. Se você não os quiser no arquivo, certifique-se de use o atributo export-ignore em um arquivo .gitattributes e confirme isso antes de fazer seu archive. Consulte Mais informação...


Nota: Se você estiver interessado em exportar o índice, o comando é

git checkout-index -a -f --prefix=/destination/path/

(Veja a resposta de Greg para mais detalhes)

CB Bailey
fonte
198
Arquivo ZIP:git archive --format zip --output /full/path master
Vadim
221
Esteja ciente de que o archive não conterá o diretório .git, mas conterá outros arquivos ocultos específicos do git, como .gitignore, .gitattributes, etc. Portanto, se você não os desejar, use o atributo export-ignore em um arquivo .gitattributes e confirme isso antes de fazer seu archive. Veja feeding.cloud.geek.nz/2010/02/...
mj1531
54
Para acompanhar a nota do Streams: você pode adicionar uma string '--prefix = something /' ao comando para controlar o nome do diretório que será compactado dentro do zip. Por exemplo, se você usar git archive --format zip --output /path/to/file.zip --prefix=newdir/ mastera saída, será chamada 'file.zip', mas quando descompactar, o diretório de nível superior será 'newdir'. (Se você omitir o atributo prefix, a dir nível superior seria 'arquivo'.)
Alan W. Smith
89
A maneira mais fácil: git archive -o latest.zip HEADele cria um arquivo Zip que contém o conteúdo da confirmação mais recente na ramificação atual. Observe que o formato de saída é inferido pela extensão do arquivo de saída.
N
37
Ele não suporta sub-módulos git :(
umpirsky
320

Eu descobri o que a opção 2 significa. Em um repositório, você pode fazer:

git checkout-index -a -f --prefix=/destination/path/

A barra no final do caminho é importante, caso contrário, os arquivos estarão no / destino com um prefixo de 'caminho'.

Como em uma situação normal, o índice contém o conteúdo do repositório, não há nada de especial a fazer para "ler a árvore desejada no índice". Já está lá.

O -asinalizador é necessário para verificar todos os arquivos no índice (não sei o que significa omitir esse sinalizador nessa situação, pois ele não faz o que eu quero). O -fsinalizador força a substituição de arquivos existentes na saída, o que esse comando normalmente não faz.

Esse parece ser o tipo de "exportação de git" que eu estava procurando.

Greg Hewgill
fonte
73
... e não se esqueça da barra no final, ou você não terá o efeito desejado;)
conny
1
O git addcomando altera o conteúdo no índice, portanto, o que git statusaparecer como "a ser confirmado" são as diferenças entre HEAD e o conteúdo do índice.
Greg Hewgill 31/08/09
7
@conny: leia o seu comentário, esqueci-o e executei o comando sem barra. aconselhamento acompanhamento de conny -.-: ponta
Znarkus
35
+1 ao conselho de conny. Além disso, não tente criar '~ / dest /', pois isso cria um diretório chamado '~' em seu diretório de trabalho, e não no que você realmente queria. Adivinha o que acontece quando você digita mindlessly rm -rf ~
Kyle Heironimus
5
@KyleHeironimus - seu aviso sobre o uso de '~ / dest / `é verdadeiro se você usar aspas no caminho do seu prefixo que diz ao shell para não executar a expansão do til. Um diretório chamado ~(não '~'!) Será criado no seu diretório de trabalho. Não há nada de especial a git checkout-indexesse respeito: o mesmo é verdade mkdir '~/dest'( não faça isso! ). No entanto, outro bom motivo para nomes de arquivos evitar que precisam citando (por exemplo, que têm um espaço neles) :-)
Matt Wallis
254

git archive também funciona com repositório remoto.

git archive --format=tar \
--remote=ssh://remote_server/remote_repository master | tar -xf -

Para exportar um caminho específico dentro do repositório, adicione quantos caminhos você desejar como último argumento para o git, por exemplo:

git archive --format=tar \
--remote=ssh://remote_server/remote_repository master path1/ path2/ | tar -xv
Alexander Somov
fonte
6
Essa é a opção que eu mais gosto. Tem o benefício adicional de também funcionar em repositórios vazios.
innaM
5
Sou versão melhorada é: git archive --format=tar --prefix=PROJECT_NAME/ --remote=USER@SERVER:PROJECT_NAME.git master | tar -xf - (garante o seu arquivo está em uma pasta)
Nick
7
Nota : o servidor deve ativar esse recurso.
Jakub Narębski
12
Eu tentei: git archive --format=zip --output foo.zip --remote=https://github.com/xxx.git mastere fui fatal: operação não suportada pelo protocolo. Fim inesperado do fluxo de comandos.
andyf 19/07/2013
7
@andyf GitHub tem sua própria maneira: curl -L https://api.github.com/repos/VENDOR/PROJECT/tarball | tar xzf -por docs
bispo
63

insira a descrição da imagem aqui

Uma resposta de caso especial se o repositório estiver hospedado no GitHub.

Basta usar svn export.

Tanto quanto sei, o Github não permite archive --remote. Embora o GitHub seja compatível com svn e eles tenham todos os repositórios git svnacessíveis, você pode usar svn exportcomo faria normalmente com alguns ajustes no seu URL do GitHub.

Por exemplo, para exportar um repositório inteiro, observe como trunko URL substitui master(ou o que a ramificação HEAD do projeto está configurada ):

svn export https://github.com/username/repo-name/trunk/

E você pode exportar um único arquivo ou mesmo um determinado caminho ou pasta:

svn export https://github.com/username/repo-name/trunk/src/lib/folder

Exemplo com a biblioteca JavaScript jQuery

A HEADfilial ou filial principal estará disponível usando trunk:

svn ls https://github.com/jquery/jquery/trunk

As não HEAD filiais estarão acessíveis em /branches/:

svn ls https://github.com/jquery/jquery/branches/2.1-stable

Todas as tags abaixo /tags/da mesma maneira:

svn ls https://github.com/jquery/jquery/tags/2.1.3
Anthony Hatzopoulos
fonte
1
git archivefunciona bem com o GitHub, desde que você use o protocolo git, basta substituir https://por git://no URL. Não sei por que o GitHub não anuncia esse recurso oculto.
Neil Mayhew
1
@ NeilMayhew Não funciona para mim, eu entendo fatal: The remote end hung up unexpectedly. Tentei em dois servidores diferentes com o repositório jQuery github.
Anthony Hatzopoulos
1
Você está certo. Eu tinha esquecido que estava usando git config url.<base>.insteadOfpara armazenar em cache o repositório remoto. Eu estava, portanto, usando uma file://URL na realidade. Duvido que isso git archivepossa funcionar com git://URLs, pois ele precisa ser executado git-upload-archiveno final remoto. Deve ser possível usar o sshprotocolo, exceto que o github não permite ( Invalid command: 'git-upload-archive').
Neil Mayhew
Alguma maneira de usar uma ferramenta de servidor local se comportando como o github se eu quiser fazê-lo em repositórios git hospedados internamente?
kriss
1
upvoted - é completamente bizarro que Git não tem esta característica e temos que recorrer a svn
Jason S
40

No manual do Git :

Usando o git-checkout-index para "exportar uma árvore inteira"

A capacidade do prefixo basicamente torna trivial o uso do git-checkout-index como uma função "exportar como árvore". Basta ler a árvore desejada no índice e fazer:

$ git checkout-index --prefix=git-export-dir/ -a

jperras
fonte
19
Eu acho que a confusão é a frase "leia a árvore desejada no índice".
Davetron5000 02/10/08
4
Se você deseja exportar diretório foo no bar ramo, então isso seria git read-tree bar:fooE então git checkout-index --prefix=export_dir/ -adepois disso talvez você deve fazergit update-index master
Pascal Rosin
1
@JohnWeldon Requer que você clone o repo primeiro? Nesse caso, eu não aceitaria, pois o objetivo "svn export" de um subdiretório é obter diretamente uma cópia desse subdiretório; se alguém tem um repositório Git de 1 GB e tudo o que eu quero é um subdiretório de 10 kB, é uma loucura exigir que eu clone a coisa toda.
Jason S
3
Também eu ecoaria @ davetron5000 com o comentário "leia a árvore desejada no índice", que não faço ideia do que isso significa.
Jason S
38

Eu escrevi um invólucro simples git-checkout-indexque você pode usar assim:

git export ~/the/destination/dir

Se o diretório de destino já existir, você precisará adicionar -fou --force.

A instalação é simples; basta soltar o script em algum lugar no seu PATHe verifique se ele é executável.

O repositório do github para git-export

Daniel Schierbeck
fonte
15
Este wrapper não é independente de plataforma; depende de / bin / sh. Portanto, se você estiver no Windows, essa solução provavelmente não funcionará para você.
Shovavnik
18
Uhh, este script é de 57 linhas de documentação, espaço em branco, configuração, análise de argumento, e apenas uma linha que realmente faz alguma coisa ...
Vladimir Panteleev
36

Parece que este é um problema menor no Git que no SVN. O Git coloca apenas uma pasta .git na raiz do repositório, enquanto o SVN coloca uma pasta .svn em todos os subdiretórios. Portanto, "svn export" evita a magia recursiva da linha de comando, enquanto que com o Git a recursão não é necessária.

kostmo
fonte
26
Como SVN de 1,7, há também apenas uma pasta Svn: subversion.apache.org/docs/release-notes/1.7.html#single-db
kostmo
Isso não se livra de nenhum arquivo de compilação adicional que o svn export exclui. Então essa definitivamente não é a resposta.
fácil
28

O equivalente a

svn export . otherpath

dentro de um repo existente é

git archive branchname | (cd otherpath; tar x)

O equivalente a

svn export url otherpath

é

git archive --remote=url branchname | (cd otherpath; tar x)
aredridel
fonte
1
obrigado, era isso que eu estava perdendo ... também, para verificar os carimbos de data / hora da exportação (eles não serão preservados como nos arquivos), use git archive --format=tar --prefix=junk/ HEAD | (tar -t -v --full-time -f -)... No entanto, o arquivamento com carimbos de data e hora não é exatamente trivial, por isso postei um exemplo abaixo .
Sdaau
1
Você pode usar a opção C para tar em vez do subshell, assim: git archive branchname | tar xC otherpath
James Moore
Atenção que a Copção de tar é apenas GNU Tar.
Aredridel # 18/17
22

Se você não estiver excluindo arquivos com .gitattributes export-ignore, tentegit checkout

mkdir /path/to/checkout/
git --git-dir=/path/to/repo/.git --work-tree=/path/to/checkout/ checkout -f -q

-f
Ao fazer o check-out de caminhos do índice, não falhe nas entradas não imersas; em vez disso, entradas não mescladas são ignoradas.

e

-q
Evite detalhado

Além disso, você pode obter qualquer ramificação ou etiqueta ou de uma revisão de confirmação específica, como no SVN, apenas adicionando o SHA1 (SHA1 no Git é o equivalente ao número da revisão no SVN)

mkdir /path/to/checkout/
git --git-dir=/path/to/repo/.git --work-tree=/path/to/checkout/ checkout 2ef2e1f2de5f3d4f5e87df7d8 -f -q -- ./

Ele /path/to/checkout/deve estar vazio, o Git não excluirá nenhum arquivo, mas substituirá os arquivos com o mesmo nome sem nenhum aviso

ATUALIZAÇÃO: para evitar o problema decapitado ou deixar intacto o repositório de trabalho ao usar o checkout para exportar com tags, branches ou SHA1, é necessário adicionar -- ./no final

O traço duplo --informa ao git que tudo após os traços são caminhos ou arquivos, e também neste caso diz git checkoutpara não alterar oHEAD

Exemplos:

Este comando obterá apenas o diretório libs e também o readme.txtarquivo que confirma exatamente

git --git-dir=/path/to/repo/.git --work-tree=/path/to/checkout/ checkout fef2e1f2de5f3d4f5e87df7d8 -f -q -- ./libs ./docs/readme.txt

Isso criará (substituirá) my_file_2_behind_HEAD.txtdois commits atrás da cabeçaHEAD^2

git --git-dir=/path/to/repo/.git --work-tree=/path/to/checkout/ checkout HEAD^2 -f -q -- ./my_file_2_behind_HEAD.txt

Para obter a exportação de outra filial

git --git-dir=/path/to/repo/.git --work-tree=/path/to/checkout/ checkout myotherbranch -f -q -- ./

Observe que ./é relativo à raiz do repositório

user5286776117878
fonte
Na verdade, entre muitos outros e upvotes, isso funcionou melhor para mim, sem nenhuma compressão, funcionando bem com repositórios vazios (gitolite).
takeshin
1
Observe que o check-out do SHA1 criará um problema de "decapitação" no repositório
user5286776117878 4/04
atualmente @ITGabs, isso não faz o download da pasta ".git". Assim, a pasta baixado não é um repositório git, por isso não é tecnicamente "decapitado"
Fabio Marreco
@FabioMarreco A questão behead está no repositório não nos arquivos exportados / baixado, estou atualizando a resposta para mais detalhes
user5286776117878
3
Isso funcionou muito bem para mim. Mas, a princípio, recebi mensagens de erro "Não é um repositório git". Então eu descobri que "/ path / to / repo /" tinha que apontar para a pasta .git. Então, isso funcionou: --git-dir = / path / to / repo / .git
philburk
21

Eu uso os submódulos git extensivamente. Este funciona para mim:

rsync -a ./FROM/ ./TO --exclude='.*'
slatvick
fonte
1
Não sentiria falta de arquivos cujos nomes começam com um ponto, como .htaccess?
Greg Hewgill
8
Uma boa solução, eu mudaria --exclude = '. *' Para --exclude = '. Git *'
schmunk
18
--exclude-vcs se você fosse aceitar esse tato #
7/11
Pode ./FROM/ ser um repositório remoto?
Resist Design
2
Como FYI, minha cópia da rsynclista o argumento como --cvs-exclude. Além disso, ele ainda copia .gitattributese.gitignore
Ryan Ransford
19

Acessei esta página frequentemente ao procurar uma maneira de exportar um repositório git. Minha resposta a esta pergunta considera três propriedades que o svn export possui por design em comparação com o git, pois o svn segue uma abordagem de repositório centralizado:

  • Minimiza o tráfego para um local de repositório remoto, não exportando todas as revisões
  • Não inclui informações meta no diretório de exportação
  • A exportação de um determinado ramo usando svn é realizada especificando o caminho apropriado

    git clone --depth 1 --branch master git://git.somewhere destination_path
    rm -rf destination_path/.git
    

Ao criar uma certa versão, é útil clonar uma ramificação estável como por exemplo --branch stableou --branch release/0.9.

Lars Schillingmann
fonte
Isso não funciona se o destino existir e não estiver vazio.
epónimo
2
A única resposta verdadeira: surge das profundezas. A git archive | tarabordagem não é aplicável a ambientes shell incompatíveis com POSIX (por exemplo, IC baseado em CMD ou PowerShell do AppVeyor), o que não é ideal. A git checkoutabordagem modifica o índice da árvore principal de trabalho, o que é terrível. A git checkout-indexabordagem requer que o índice da árvore principal de trabalho seja modificado antecipadamente, o que é ainda mais terrível. A git cloneabordagem tradicional clona a totalidade do histórico do repositório antes de excluir esse histórico, o que é um desperdício. Essa é a única solução sadia que resta.
Cecil Curry
1
Para exportar localmente, observe que o caminho absoluto da árvore de trabalho do Git a ser clonado deve ser prefixado pelo file://protocolo (por exemplo, git clone --depth 1 --branch v3.14.15 file:///home/me/src_repo trg_repo). Não fazer isso emitirá "warning: --depth is ignored in local clones; use file:// instead."e executará um clone padrão em vez de superficial, derrotando todo o objetivo desta resposta. Salud!
Cecil Curry
16

Isso copiará todo o conteúdo, menos os arquivos .dot. Eu uso isso para exportar projetos clonados git para o repositório git do meu aplicativo Web sem o material .git.

cp -R ./path-to-git-repo / caminho / para / destino /

Plain old bash funciona muito bem :)

Harmon
fonte
Por que não empurrar para o controle remoto? Ainda mais simples que o bash.
Nurettin
2
e os arquivos que fazem parte de aplicativos da Web e seu nome começa com ponto? :) pense em .htaccess
Artur
3
Às vezes você também quer ignorar o que está dentro .gitignore, isso não acontece.
Fregante
14

Tão simples quanto o clone, exclua a pasta .git:

git clone url_of_your_repo path_to_export && rm -rf path_to_export/.git

teleme.io
fonte
4
Honestamente - esta resposta, que também é a número 1 na pergunta - é o que você fará 99% do tempo. A maioria dessas respostas é muito complicada.
Geoff Nixon
11

Para usuários do GitHub, o git archive --remotemétodo não funcionará diretamente, pois o URL de exportação é efêmero . Você deve solicitar o URL ao GitHub e fazer o download desse URL. curlfacilita isso:

curl -L https://api.github.com/repos/VENDOR/PROJECT/tarball | tar xzf -

Isso fornecerá o código exportado em um diretório local. Exemplo:

$ curl -L https://api.github.com/repos/jpic/bashworks/tarball | tar xzf -
$ ls jpic-bashworks-34f4441/
break  conf  docs  hack  LICENSE  mlog  module  mpd  mtests  os  README.rst  remote  todo  vcs  vps  wepcrack

Editar
Se você deseja que o código seja colocado em um diretório existente específico (e não no diretório aleatório do github):

curl -L https://api.github.com/repos/VENDOR/PROJECT/tarball | \
tar xzC /path/you/want --strip 1
bispo
fonte
11

Sim, este é um comando limpo e arrumado para arquivar seu código sem nenhuma inclusão do git no arquivo morto e é bom distribuir sem se preocupar com o histórico de confirmação do git.

git archive --format zip --output /full/path/to/zipfile.zip master 
zeeawan
fonte
Isso é ótimo, basta remover o gitignore depois e está pronto e pronto para compartilhar.
Sogger
Removendo .gitgnore etc. é mencionado nos comentários resposta aceita: uso .gitattributes arquivo, consulte feeding.cloud.geek.nz/posts/excluding-files-from-git-archive
Sogger
10

Eu só quero salientar que no caso de você estar

  1. exportar uma subpasta do repositório (era assim que eu costumava usar o recurso de exportação SVN)
  2. tudo bem em copiar tudo dessa pasta para o destino de implantação
  3. e já que você já possui uma cópia de todo o repositório.

Então você pode apenas usar em cp foo [destination]vez do mencionado git-archive master foo | -x -C [destination].

dkinzer
fonte
9

Você pode arquivar um repositório remoto em qualquer confirmação como arquivo zip.

git archive --format=zip --output=archive.zip --remote=USERNAME@HOSTNAME:PROJECTNAME.git HASHOFGITCOMMIT
orkoden
fonte
8

Implementação bash do git-export.

Eu segmente os processos de criação e remoção de arquivos .empty por sua própria função, com o objetivo de reutilizá-los na implementação do 'git-archive' (será publicado posteriormente).

Também adicionei o arquivo '.gitattributes' ao processo para remover arquivos indesejados da pasta de exportação de destino. Inclusão de verbosidade no processo, além de tornar a função 'git-export' mais eficiente.

EMPTY_FILE = ". Vazio";

function create_empty () {
## Processing path (target-dir):
    TRG_PATH="${1}";
## Component(s):
    EXCLUDE_DIR=".git";
echo -en "\nAdding '${EMPTY_FILE}' files to empty folder(s): ...";
    find ${TRG_PATH} -not -path "*/${EXCLUDE_DIR}/*" -type d -empty -exec touch {}/${EMPTY_FILE} \;
#echo "done.";
## Purging SRC/TRG_DIRs variable(s):
    unset TRG_PATH EMPTY_FILE EXCLUDE_DIR;
    return 0;
  }

declare -a GIT_EXCLUDE;
function load_exclude () {
    SRC_PATH="${1}";
    ITEMS=0; while read LINE; do
#      echo -e "Line [${ITEMS}]: '${LINE%%\ *}'";
      GIT_EXCLUDE[((ITEMS++))]=${LINE%%\ *};
    done < ${SRC_PATH}/.gitattributes;
    GIT_EXCLUDE[${ITEMS}]="${EMPTY_FILE}";
## Purging variable(s):
    unset SRC_PATH ITEMS;
    return 0;
  }

function purge_empty () {
## Processing path (Source/Target-dir):
    SRC_PATH="${1}";
    TRG_PATH="${2}";
echo -e "\nPurging Git-Specific component(s): ... ";
    find ${SRC_PATH} -type f -name ${EMPTY_FILE} -exec /bin/rm '{}' \;
    for xRULE in ${GIT_EXCLUDE[@]}; do
echo -en "    '${TRG_PATH}/{${xRULE}}' files ... ";
      find ${TRG_PATH} -type f -name "${xRULE}" -exec /bin/rm -rf '{}' \;
echo "done.'";
    done;
echo -e "done.\n"
## Purging SRC/TRG_PATHs variable(s):
    unset SRC_PATH; unset TRG_PATH;
    return 0;
  }

function git-export () {
    TRG_DIR="${1}"; SRC_DIR="${2}";
    if [ -z "${SRC_DIR}" ]; then SRC_DIR="${PWD}"; fi
    load_exclude "${SRC_DIR}";
## Dynamically added '.empty' files to the Git-Structure:
    create_empty "${SRC_DIR}";
    GIT_COMMIT="Including '${EMPTY_FILE}' files into Git-Index container."; #echo -e "\n${GIT_COMMIT}";
    git add .; git commit --quiet --all --verbose --message "${GIT_COMMIT}";
    if [ "${?}" -eq 0 ]; then echo " done."; fi
    /bin/rm -rf ${TRG_DIR} && mkdir -p "${TRG_DIR}";
echo -en "\nChecking-Out Index component(s): ... ";
    git checkout-index --prefix=${TRG_DIR}/ -q -f -a
## Reset: --mixed = reset HEAD and index:
    if [ "${?}" -eq 0 ]; then
echo "done."; echo -en "Resetting HEAD and Index: ... ";
        git reset --soft HEAD^;
        if [ "${?}" -eq 0 ]; then
echo "done.";
## Purging Git-specific components and '.empty' files from Target-Dir:
            purge_empty "${SRC_DIR}" "${TRG_DIR}"
          else echo "failed.";
        fi
## Archiving exported-content:
echo -en "Archiving Checked-Out component(s): ... ";
        if [ -f "${TRG_DIR}.tgz" ]; then /bin/rm ${TRG_DIR}.tgz; fi
        cd ${TRG_DIR} && tar -czf ${TRG_DIR}.tgz ./; cd ${SRC_DIR}
echo "done.";
## Listing *.tgz file attributes:
## Warning: Un-TAR this file to a specific directory:
        ls -al ${TRG_DIR}.tgz
      else echo "failed.";
    fi
## Purgin all references to Un-Staged File(s):
   git reset HEAD;
## Purging SRC/TRG_DIRs variable(s):
    unset SRC_DIR; unset TRG_DIR;
    echo "";
    return 0;
  }

Resultado:

$ git-export /tmp/rel-1.0.0

Adicionando arquivos '.empty' às pastas vazias: ... pronto.

Componente (s) do índice de check-out: ... pronto.

Redefinindo HEAD e Índice: ... pronto.

Limpando componentes específicos do Git: ...

arquivos '/tmp/rel-1.0.0/{.buildpath}' ... concluído. '

arquivos '/tmp/rel-1.0.0/{.project}' finalizados. '

arquivos '/tmp/rel-1.0.0/{.gitignore}' ... concluído. '

'/tmp/rel-1.0.0/{.git}' arquivos ... concluídos. '

arquivos '/tmp/rel-1.0.0/{.gitattributes}' ... concluído. '

'/tmp/rel-1.0.0/{*.mno}' arquivos ... concluídos. '

'/tmp/rel-1.0.0/{*~}' arquivos ... concluídos. '

'/tmp/rel-1.0.0/{.*~}' arquivos ... concluídos. '

'/tmp/rel-1.0.0/{*.swp}' arquivos ... concluídos. '

'/tmp/rel-1.0.0/{*.swo}' arquivos ... concluídos. '

arquivos '/tmp/rel-1.0.0/{.DS_Store}' ... concluído. '

arquivos '/tmp/rel-1.0.0/{.settings}' concluído ... '.

arquivos '/tmp/rel-1.0.0/{.empty}' ... concluído. '

feito.

Arquivando componente (s) com check-out: ... concluído.

-rw-r - r-- 1 roda de administração 25445901 3 Nov 12:57 /tmp/rel-1.0.0.tgz

Agora incorporei a funcionalidade 'git archive' em um único processo que utiliza a função 'create_empty' e outros recursos.

function git-archive () {
    PREFIX="${1}"; ## sudo mkdir -p ${PREFIX}
    REPO_PATH="`echo "${2}"|awk -F: '{print $1}'`";
    RELEASE="`echo "${2}"|awk -F: '{print $2}'`";
    USER_PATH="${PWD}";
echo "$PREFIX $REPO_PATH $RELEASE $USER_PATH";
## Dynamically added '.empty' files to the Git-Structure:
    cd "${REPO_PATH}"; populate_empty .; echo -en "\n";
#    git archive --prefix=git-1.4.0/ -o git-1.4.0.tar.gz v1.4.0
# e.g.: git-archive /var/www/htdocs /repos/domain.name/website:rel-1.0.0 --explode
    OUTPUT_FILE="${USER_PATH}/${RELEASE}.tar.gz";
    git archive --verbose --prefix=${PREFIX}/ -o ${OUTPUT_FILE} ${RELEASE}
    cd "${USER_PATH}";
    if [[ "${3}" =~ [--explode] ]]; then
      if [ -d "./${RELEASE}" ]; then /bin/rm -rf "./${RELEASE}"; fi
      mkdir -p ./${RELEASE}; tar -xzf "${OUTPUT_FILE}" -C ./${RELEASE}
    fi
## Purging SRC/TRG_DIRs variable(s):
    unset PREFIX REPO_PATH RELEASE USER_PATH OUTPUT_FILE;
    return 0;
  }
tocororo
fonte
Uso: git-archive [/ var / www / htdocs] /repos/web.domain/website:rel-1.0.0
tocororo
8

Se você quiser algo que funcione com submódulos, isso pode valer a pena.

Nota:

  • MASTER_DIR = um check-out com seus submódulos em check-out também
  • DEST_DIR = onde esta exportação terminará
  • Se você tem o rsync, acho que seria capaz de fazer a mesma coisa com ainda menos dor de bola.

Premissas:

  • Você precisa executá-lo no diretório pai do MASTER_DIR (ou seja, do MASTER_DIR cd ..)
  • Supõe-se que DEST_DIR tenha sido criado. É muito fácil modificar isso para incluir a criação de um DEST_DIR se você quiser

cd MASTER_DIR && tar -zcvf ../DEST_DIR/export.tar.gz --exclude = '. git *'. && cd ../DEST_DIR/ && tar xvfz export.tar.gz && rm export.tar.gz

Rob Jensen
fonte
6

Minha preferência seria realmente ter um destino dist no seu Makefile (ou outro sistema de compilação) que exporte um arquivo distribuível do seu código (.tar.bz2, .zip, .jar ou o que for apropriado). Se você estiver usando ferramentas automáticas GNU ou sistemas MakeMaker da Perl, acho que isso existe automaticamente para você. Caso contrário, eu recomendo adicioná-lo.

ETA (06/09/2012): Uau, votos duros. Ainda acredito que é melhor criar suas distribuições com suas ferramentas de compilação do que com a ferramenta de controle de código-fonte. Acredito na construção de artefatos com ferramentas de construção. No meu trabalho atual, nosso principal produto é construído com um alvo de formigas. Estamos no meio da troca de sistemas de controle de código fonte, e a presença desse alvo formiga significa menos problemas na migração.

skiphoppy
fonte
O projeto que eu tinha em mente não é um projeto de código; acontece mais no sentido de um projeto de site.
Greg Hewgill 02/10/08
Não aborda a questão.
Andrew Ferrier
1
Sim, essa resposta pode não atender às necessidades de todos, mas os votos negativos são bizarros. Ele é uma resposta totalmente válido, e de fato, em muitos cenários, a resposta só correta. É válido afirmar que pensar nesse problema como um "problema com a ferramenta vc" geralmente está seguindo o caminho errado.
snogglethorpe
6

Isso copiará os arquivos em um intervalo de confirmações (C a G) para um arquivo tar. Nota: isso só obterá os arquivos confirmados. Não é o repositório inteiro. Ligeiramente modificado daqui

Exemplo de histórico de confirmação

A -> B -> C -> D -> E -> F -> G -> H -> I

git diff-tree -r --no-commit-id --name-only --diff-filter=ACMRT C~..G | xargs tar -rf myTarFile.tar

Página de manual do git-diff-tree

-r -> recursão em subárvores

--no-commit-id -> git diff-tree gera uma linha com o ID de confirmação, quando aplicável. Este sinalizador suprimiu a saída do ID de confirmação.

--name-only -> Mostra apenas os nomes dos arquivos alterados.

--diff-filter = ACMRT -> Selecione apenas esses arquivos. Veja aqui a lista completa de arquivos

C..G -> arquivos neste intervalo de confirmações

C ~ -> Incluir arquivos do Commit C. Não apenas arquivos desde o Commit C.

| xargs tar -rf myTarFile -> saídas para tar

Caqui Fuyu
fonte
5

Pelo que entendi, é mais sobre baixar apenas um determinado estado do servidor, sem histórico e sem dados de outras ramificações, em vez de extrair um estado de um repositório local (como muitas respostas aqui fazem).

Isso pode ser feito assim:

git clone -b someBranch --depth 1 --single-branch git://somewhere.com/repo.git \
&& rm -rf repo/.git/
  • --single-branch está disponível desde Git 1.7.10 (abril de 2012).
  • --depthé (foi?) supostamente defeituoso, mas, no caso de uma exportação, os problemas mencionados não devem importar.
Ondra Žižka
fonte
Nota: Acabei de notar que existem 2 páginas de respostas, só olhei uma antes de postar. Existe apenas uma resposta semelhante --depth, que implica a --single-branchmenos que --no-single-branchseja fornecida, o que significa que provavelmente tem o mesmo efeito. Não tenho certeza, porém, algum especialista pode confirmar?
Ondra Žižka
4

Eu precisava disso para um script de implantação e não podia usar nenhuma das abordagens mencionadas acima. Em vez disso, descobri uma solução diferente:

#!/bin/sh
[ $# -eq 2 ] || echo "USAGE $0 REPOSITORY DESTINATION" && exit 1
REPOSITORY=$1
DESTINATION=$2
TMPNAME="/tmp/$(basename $REPOSITORY).$$"
git clone $REPOSITORY $TMPNAME
rm -rf $TMPNAME/.git
mkdir -p $DESTINATION
cp -r $TMPNAME/* $DESTINATION
rm -rf $TMPNAME
Troelskn
fonte
Qual foi o problema com uma solução de árvore de leitura / índice de check-out ou arquivo? Tanto quanto posso dizer, você fez o equivalente a algo como, mkdir -p "$2" && git --git-dir="$1" archive HEAD | tar -x -C "$2"mas um pouco mais demorado.
CB Bailey
1
Não consegui que a árvore de leitura funcionasse em um repositório remoto, e a solução de arquivamento não funciona com o github.
troelskn
Sim, com arquivo de obter um comando inválido: 'git-upload-arquivo' ... erro e eu não tenho core.gitProxy configuração opção e o ambiente variável conjunto GIT_PROXY_COMMAND
tgkprog
4

Fazendo da maneira mais fácil, esta é uma função para .bash_profile, descompacta diretamente o arquivo na localização atual, configure primeiro o seu habitual [url: path]. NOTA: Com essa função, você evita a operação de clone, ela é obtida diretamente do repositório remoto.

gitss() {
    URL=[url:path]

    TMPFILE="`/bin/tempfile`"
    if [ "$1" = "" ]; then
        echo -e "Use: gitss repo [tree/commit]\n"
        return
    fi
    if [ "$2" = "" ]; then
        TREEISH="HEAD"
    else
        TREEISH="$2"
    fi
    echo "Getting $1/$TREEISH..."
    git archive --format=zip --remote=$URL/$1 $TREEISH > $TMPFILE && unzip $TMPFILE && echo -e "\nDone\n"
    rm $TMPFILE
}

Alias ​​para .gitconfig, a mesma configuração necessária (TAKE CARE executando o comando dentro dos projetos .git, ele SEMPRE salta para o diretório base anteriormente como dito aqui , até que isso seja corrigido. Pessoalmente, prefiro a função

ss = !env GIT_TMPFILE="`/bin/tempfile`" sh -c 'git archive --format=zip --remote=[url:path]/$1 $2 \ > $GIT_TMPFILE && unzip $GIT_TMPFILE && rm $GIT_TMPFILE' -
RkG
fonte
4

Eu tenho outra solução que funciona bem se você tiver uma cópia local do repositório na máquina em que deseja criar a exportação. Nesse caso, vá para este diretório do repositório e digite este comando:

GIT_WORK_TREE=outputdirectory git checkout -f

Isso é particularmente útil se você gerencia um site com um repositório git e gostaria de fazer check-out de uma versão limpa /var/www/. Nesse caso, adicione este comando em um .git/hooks/post-receivescript ( hooks/post-receiveem um repositório vazio, o que é mais adequado nessa situação)

Tom
fonte
3

Eu acho que a postagem de @Aredridel foi a mais próxima, mas há um pouco mais disso - então eu adicionarei isso aqui; o problema é, svnse você estiver em uma subpasta de um repositório, e você faz:

/media/disk/repo_svn/subdir$ svn export . /media/disk2/repo_svn_B/subdir

em seguida svn, exportará todos os arquivos que estão sob controle de revisão (eles também podem ter o status Adicionado recentemente ou Modificado) - e se você tiver outro "lixo" nesse diretório (e não estou contando .svnsubpastas aqui, mas coisas visíveis, como .oarquivos) , não será exportado; somente os arquivos registrados pelo repositório SVN serão exportados. Para mim, uma coisa boa é que essa exportação também inclui arquivos com alterações locais que ainda não foram confirmadas; e outra coisa interessante é que os carimbos de data e hora dos arquivos exportados são os mesmos que os originais. Ou, como svn help exportcoloca:

  1. Exporta uma árvore de diretórios limpa da cópia de trabalho especificada por PATH1, na revisão REV, se for fornecida, caso contrário em WORKING, para PATH2. ... Se REV não for especificado, todas as alterações locais serão preservadas. Arquivos que não estão sob controle de versão não serão copiados.

Para perceber que gitnão preservará os carimbos de data e hora, compare a saída desses comandos (em uma subpasta de um gitrepositório de sua escolha):

/media/disk/git_svn/subdir$ ls -la .

... e:

/media/disk/git_svn/subdir$ git archive --format=tar --prefix=junk/ HEAD | (tar -t -v --full-time -f -)

... e eu, em qualquer caso, noto que git archivefaz com que todos os carimbos de data e hora do arquivo arquivado sejam os mesmos! git help archivediz:

O arquivo git se comporta de maneira diferente quando recebe um ID de árvore e quando recebe um ID de confirmação ou ID de tag. No primeiro caso, a hora atual é usada como a hora de modificação de cada arquivo no arquivo morto. Neste último caso, o tempo de confirmação, conforme registrado no objeto de confirmação referenciado, é usado.

... mas aparentemente ambos os casos definem o "tempo de modificação de cada arquivo"; dessa forma, não preservando os registros de data e hora reais desses arquivos!

Portanto, para preservar também os registros de data e hora, aqui está um bashscript, que é realmente "uma linha", embora um pouco complicado - então, abaixo, ele é postado em várias linhas:

/media/disk/git_svn/subdir$ git archive --format=tar master | (tar tf -) | (\
  DEST="/media/diskC/tmp/subdirB"; \
  CWD="$PWD"; \
  while read line; do \
    DN=$(dirname "$line"); BN=$(basename "$line"); \
    SRD="$CWD"; TGD="$DEST"; \
    if [ "$DN" != "." ]; then \
      SRD="$SRD/$DN" ; TGD="$TGD/$DN" ; \
      if [ ! -d "$TGD" ] ; then \
        CMD="mkdir \"$TGD\"; touch -r \"$SRD\" \"$TGD\""; \
        echo "$CMD"; \
        eval "$CMD"; \
      fi; \
    fi; \
    CMD="cp -a \"$SRD/$BN\" \"$TGD/\""; \
    echo "$CMD"; \
    eval "$CMD"; \
    done \
)

Observe que se supõe que você esteja exportando o conteúdo no diretório "atual" (acima /media/disk/git_svn/subdir) - e o destino para o qual você está exportando é um pouco inconveniente, mas está na DESTvariável de ambiente. Observe que com este script; você deve criar o DESTdiretório manualmente, antes de executar o script acima.

Após a execução do script, você poderá comparar:

ls -la /media/disk/git_svn/subdir
ls -la /media/diskC/tmp/subdirB   # DEST

... e espero ver os mesmos registros de data e hora (para os arquivos que estavam sob controle de versão).

Espero que isso ajude alguém,
Saúde!

sdaau
fonte
3

uma exportação git para um arquivo zip ao adicionar um prefixo (por exemplo, nome do diretório):

git archive master --prefix=directoryWithinZip/  --format=zip -o out.zip
DomTomCat
fonte
1

Eu tenho a seguinte função de utilitário no meu arquivo .bashrc: ele cria um arquivo da ramificação atual em um repositório git.

function garchive()
{
  if [[ "x$1" == "x-h" || "x$1" == "x" ]]; then
    cat <<EOF
Usage: garchive <archive-name>
create zip archive of the current branch into <archive-name>
EOF
  else
    local oname=$1
    set -x
    local bname=$(git branch | grep -F "*" | sed -e 's#^*##')
    git archive --format zip --output ${oname} ${bname}
    set +x
  fi
}
MichaelMoser
fonte