Fai un "git export" (come "svn export")?


2356

Mi chiedevo se esiste una buona soluzione "git export" che crea una copia di un albero senza la .gitdirectory del repository. Esistono almeno tre metodi che conosco:

  1. git cloneseguito rimuovendo la .gitdirectory del repository.
  2. git checkout-index allude a questa funzionalità ma inizia con "Basta leggere l'albero desiderato nell'indice ..." che non sono del tutto sicuro di come fare.
  3. git-exportè uno script di terze parti che esegue essenzialmente git cloneuna posizione temporanea seguita dalla rsync --exclude='.git'destinazione finale.

Nessuna di queste soluzioni mi sembra davvero soddisfacente. La più vicina svn exportpotrebbe essere l'opzione 1, poiché entrambe richiedono che la directory di destinazione sia vuota per prima. Ma l'opzione 2 sembra ancora migliore, supponendo che riesca a capire cosa significhi leggere un albero nell'indice.


1
@rnrTom: vedi la risposta di Somov. (non c'è niente di "compresso" in un archivio tar).
Etarion,

23
@mrTom git archive --format zip --output "output.zip" master -0ti darà un archivio non compresso (-0 è la bandiera per non compresso). git-scm.com/docs/git-archive .

7
Concordo con @mrTom e non credo che l'archivio sia compresso o non compresso sia il problema principale. Con SVN, posso exportuna sottodirectory da 250 kB direttamente dal repository remoto (che altrimenti potrebbe avere una dimensione di 200 MB, escluse le revisioni) - e colpirò la rete solo per un trasferimento di download di 250 kB (o giù di lì). Con git, archivedeve essere abilitato sul server (quindi non posso provarlo) - clone --depth 1dal server potrebbe ancora recuperare un repository di 25 MB, in cui la .gitsottocartella da sola richiede 15 MB. Pertanto, direi ancora che la risposta è "no".
sdaau,

@mrTom la risposta è in realtà Vedi la risposta dell'OP - il comando ègit checkout-index
nocache

Ecco un modo semplice e piacevole:git archive -o latest.zip HEAD
Evgeni Sergeev,

Risposte:


2397

Probabilmente il modo più semplice per raggiungere questo obiettivo è con git archive. Se hai davvero bisogno solo dell'albero espanso, puoi fare qualcosa del genere.

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

Il più delle volte che ho bisogno di "esportare" qualcosa da Git, voglio comunque un archivio compresso, quindi faccio qualcosa del genere.

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

Archivio ZIP:

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

git help archive per maggiori dettagli, è abbastanza flessibile.


Ricorda che anche se l'archivio non conterrà la directory .git, conterrà comunque altri file specifici nascosti specifici di git come .gitignore, .gitattributes, ecc. Se non li desideri nell'archivio, assicurati di usa l'attributo export-ignore in un file .gitattributes e commettilo prima di fare il tuo archivio. Leggi di più...


Nota: se si desidera esportare l'indice, il comando è

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

(Vedi la risposta di Greg per maggiori dettagli)


198
Archivio ZIP:git archive --format zip --output /full/path master
Vadim,

221
Tenere presente che l'archivio non conterrà la directory .git, ma conterrà altri file specifici di git nascosti come .gitignore, .gitattributes, ecc. Quindi, se non li si desidera, assicurarsi di utilizzare l'attributo export-ignore in un file .gitattributes e commettilo prima di fare il tuo archivio. Vedi feed.cloud.geek.nz/2010/02/…
mj1531

54
Per dare seguito alla nota degli stream: è possibile aggiungere una stringa '--prefix = qualcosa /' al comando per controllare il nome della directory che verrà compresso all'interno dello zip. Ad esempio, se si utilizza git archive --format zip --output /path/to/file.zip --prefix=newdir/ masterl'output verrà chiamato 'file.zip' ma quando lo si scompatta, la directory di livello superiore sarà 'newdir'. (Se si omette l'attributo --prefix, la directory di livello superiore sarebbe 'file'.)
Alan W. Smith

89
Il modo più semplice: git archive -o latest.zip HEADcrea un archivio Zip che contiene i contenuti dell'ultimo commit sul ramo corrente. Si noti che il formato di output è dedotto dall'estensione del file di output.
nacho4d,

37
Non supporta i sottomoduli git :(
umpirsky

320

Ho scoperto cosa significa l'opzione 2. Da un repository, puoi fare:

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

La barra alla fine del percorso è importante, in caso contrario i file saranno in / destinazione con un prefisso "percorso".

Poiché in una situazione normale l'indice contiene i contenuti del repository, non c'è niente di speciale da fare per "leggere l'albero desiderato nell'indice". È già lì.

Il -aflag è necessario per estrarre tutti i file nell'indice (non sono sicuro di cosa significhi omettere questo flag in questa situazione, dal momento che non fa ciò che voglio). Il -fflag forza la sovrascrittura di tutti i file esistenti nell'output, cosa che normalmente non viene eseguita da questo comando.

Questo sembra essere il tipo di "esportazione git" che stavo cercando.


73
... e NON DIMENTICARE LO SLASH ALLA FINE, altrimenti non otterrai l'effetto desiderato;)
conny

1
Il git addcomando modifica il contenuto nell'indice, quindi tutto ciò che viene git statusmostrato come "da impegnare" sono le differenze tra HEAD e il contenuto dell'indice.
Greg Hewgill,

7
@conny: leggi il tuo commento, se ne è dimenticato e ha eseguito il comando senza una barra. consiglio: segui i consigli di
Conny.

35
+1 su consiglio di Conny. Inoltre, non provare a creare '~ / dest /', poiché questo crea una directory chiamata '~' nella tua directory di lavoro, piuttosto che ciò che volevi veramente. Indovina cosa succede quando digiti inconsapevolmente rm -rf ~
Kyle Heironimus,

5
@KyleHeironimus - il tuo avvertimento sull'uso di '~ / dest / `è vero se usi virgolette attorno al tuo percorso prefisso che dice alla shell di non eseguire l'espansione della tilde. Una directory chiamata ~(non '~'!) Verrà creata nella directory di lavoro. Non c'è nulla di speciale git checkout-indexin questo senso: lo stesso vale mkdir '~/dest'( non farlo! ). Ancora un altro buon motivo per evitare i nomi di file che devono essere citati (ad esempio, che hanno uno spazio) :-)
Matt Wallis,

254

git archive funziona anche con repository remoto.

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

Per esportare un percorso particolare all'interno del repository, aggiungi tutti i percorsi che desideri come ultimo argomento da git, ad esempio:

git archive --format=tar \
--remote=ssh://remote_server/remote_repository master path1/ path2/ | tar -xv

6
Questa è l'opzione che mi piace di più. Ha il vantaggio aggiuntivo di funzionare anche su repository nudi.
innaM,

5
La versione migliorata è: git archive --format=tar --prefix=PROJECT_NAME/ --remote=USER@SERVER:PROJECT_NAME.git master | tar -xf - (assicura che il tuo archivio sia in una cartella)
Nick,

7
Nota : il server deve abilitare questa funzione.
Jakub Narębski,

12
Ho provato: git archive --format=zip --output foo.zip --remote=https://github.com/xxx.git mastere sono diventato fatale: operazione non supportata dal protocollo. Fine imprevista del flusso di comandi.
Andyf,

7
@andyf GitHub ha la sua strada: curl -L https://api.github.com/repos/VENDOR/PROJECT/tarball | tar xzf -per documenti
vescovo

63

inserisci qui la descrizione dell'immagine

Una risposta a un caso speciale se il repository è ospitato su GitHub.

Basta usare svn export.

Per quanto ne so, Github non lo consente archive --remote. Sebbene GitHub sia compatibile con svn e abbiano tutti i repository git svnaccessibili in modo da poterlo usare svn exportcome faresti normalmente con alcune modifiche al tuo URL GitHub.

Ad esempio, per esportare un intero repository, notare come trunknell'URL sostituisce master(o qualunque sia il ramo HEAD del progetto impostato ):

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

E puoi esportare un singolo file o anche un determinato percorso o cartella:

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

Esempio con la libreria JavaScript jQuery

Il HEADramo o ramo principale sarà disponibile utilizzando trunk:

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

Le non HEAD filiali saranno accessibili sotto /branches/:

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

Tutti i tag sotto /tags/nello stesso modo:

svn ls https://github.com/jquery/jquery/tags/2.1.3

1
git archivefunziona bene con GitHub, finché usi il protocollo git, sostituiscilo https://con git://nell'URL. Non so perché GitHub non pubblicizzi questa funzione nascosta.
Neil Mayhew,

1
@NeilMayhew Non funziona per me, capisco fatal: The remote end hung up unexpectedly. Ho provato su due server diversi con repo github jQuery.
Anthony Hatzopoulos,

1
Hai ragione. Avevo dimenticato che stavo usando git config url.<base>.insteadOfper memorizzare nella cache il repository remoto. Stavo quindi utilizzando un file://URL in realtà. Dubito che git archivepossa mai funzionare con gli git://URL poiché deve essere in grado di funzionare git-upload-archiveda remoto. Dovrebbe essere possibile usare il sshprotocollo, tranne per il fatto che github non lo consente ( Invalid command: 'git-upload-archive').
Neil Mayhew,

Qualche modo per usare uno strumento server locale che si comporta come github se voglio farlo su repository git ospitati internamente?
Kriss,

1
votato - è del tutto bizzarro che Git non abbia questa funzione e dobbiamo ricorrere a svn
Jason S

40

Dal manuale di Git :

Utilizzo di git-checkout-index per "esportare un intero albero"

L'abilità del prefisso in pratica rende banale usare git-checkout-index come funzione "export as tree". Basta leggere l'albero desiderato nell'indice e fare:

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


19
Penso che la confusione sia la frase "leggi l'albero desiderato nell'indice".
davetron5000,

4
Se vuoi esportare la directory foo nella barra delle filiali, allora questo sarebbe git read-tree bar:fooE poi git checkout-index --prefix=export_dir/ -aforse dovresti farlogit update-index master
Pascal Rosin

1
@JohnWeldon Richiede prima di clonare il repository? In tal caso, non lo accetterei, dal momento che l'intero punto di "svn export" di una sottodirectory è ottenere direttamente una copia di quella sottodirectory; se qualcuno ha un repository Git da 1 GB e tutto ciò che voglio è una sottodirectory da 10kB, è folle richiedere che io cloni il tutto.
Jason S,

3
Inoltre echo @ davetron5000 con il commento "leggi l'albero desiderato nell'indice" che non ho idea di cosa significhi.
Jason S,

38

Ho scritto un semplice wrapper git-checkout-indexche puoi usare in questo modo:

git export ~/the/destination/dir

Se la directory di destinazione esiste già, dovrai aggiungere -fo --force.

L'installazione è semplice; rilascia lo script da qualche parte nel tuo PATHe assicurati che sia eseguibile.

Il repository github per git-export


15
Questo wrapper non è indipendente dalla piattaforma; si basa su / bin / sh. Quindi, se sei su Windows, questa soluzione probabilmente non funzionerà per te.
shovavnik,

18
Uhh, questo script è composto da 57 righe di documentazione, spazi bianchi, installazione, analisi degli argomenti e solo una riga che fa effettivamente qualcosa ...
Vladimir Panteleev

36

Sembra che questo sia un problema minore con Git rispetto a SVN. Git inserisce solo una cartella .git nella radice del repository, mentre SVN inserisce una cartella .svn in ogni sottodirectory. Quindi "svn export" evita la magia ricorsiva della riga di comando, mentre con Git la ricorsione non è necessaria.


26
A partire da SVN 1.7, esiste anche una sola cartella .svn: subversion.apache.org/docs/release-notes/1.7.html#single-db
kostmo

Questo non eliminerà alcun file di build aggiuntivo che svn elimina l'esportazione. Quindi questa non è sicuramente la risposta.
giovedì

28

L'equivalente di

svn export . otherpath

all'interno di un repository esistente è

git archive branchname | (cd otherpath; tar x)

L'equivalente di

svn export url otherpath

è

git archive --remote=url branchname | (cd otherpath; tar x)

1
grazie, questo era quello che mi mancava ... inoltre, per controllare i timestamp dell'esportazione (non saranno conservati come nei file), utilizzare git archive --format=tar --prefix=junk/ HEAD | (tar -t -v --full-time -f -)... Tuttavia, l'archiviazione con timestamp non è esattamente banale, quindi ho pubblicato un esempio sotto .
sdaau,

1
Puoi usare l'opzione C per tar invece della subshell, in questo modo: git archive branchname | tar xC otherpath
James Moore,

Heads up che l' Copzione per tar è solo GNU Tar.
Aredridel,

22

Se non stai escludendo i file con, .gitattributes export-ignoreprovagit checkout

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

-f
Durante il check out dei percorsi dall'indice, non fallire su voci non unite; invece, le voci non unite vengono ignorate.

e

-q
Evitare verbose

Inoltre puoi ottenere qualsiasi Branch o Tag o da una specifica Revisione Commit come in SVN semplicemente aggiungendo SHA1 (SHA1 in Git è l'equivalente del Numero di Revisione in SVN)

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

La /path/to/checkout/deve essere vuoto, Git non cancellare qualsiasi file, ma sarà sovrascrivere i file con lo stesso nome senza alcun preavviso

AGGIORNAMENTO: per evitare il problema decapitato o per lasciare intatto il repository funzionante quando si utilizza il checkout per l'esportazione con tag, rami o SHA1, è necessario aggiungere -- ./alla fine

Il doppio trattino --dice a git che tutto ciò che segue i trattini sono percorsi o file, e anche in questo caso dice git checkoutdi non cambiare ilHEAD

Esempi:

Questo comando otterrà solo la directory libs e anche il readme.txtfile da quel commit esatto

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

Questo creerà (sovrascriverà) my_file_2_behind_HEAD.txtdue commit dietro la testaHEAD^2

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

Per ottenere l'esportazione di un altro ramo

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

Si noti che ./è relativo alla radice del repository


In realtà, tra numerosi altri e voti positivi, questo ha funzionato meglio per me, senza alcuna compressione, lavorando bene con depositi nudi (gitolite).
entro il

1
Si noti che il checkout SHA1 creerà un problema di "decapitazione" nel repository
user5286776117878

attualmente @ITGabs, questo non scarica la cartella ".git". Quindi la cartella scaricata non è un repository git, quindi non è tecnicamente "decapitata"
Fabio Marreco,

@FabioMarreco Il problema della decapitazione è nel repository non nei file esportati / scaricati, sto aggiornando la risposta per maggiori dettagli
user5286776117878

3
Questo ha funzionato alla grande per me. Ma all'inizio ho ricevuto i messaggi di errore "Not a git repository". Poi ho scoperto che "/ path / to / repo /" doveva puntare alla cartella .git. Quindi ha funzionato: --git-dir = / path / to / repo / .git
philburk,

21

Uso ampiamente i sottomoduli git. Questo funziona per me:

rsync -a ./FROM/ ./TO --exclude='.*'

1
Non perderebbero i file i cui nomi iniziano con un punto, come .htaccess?
Greg Hewgill,

8
Una buona soluzione, cambierei --exclude = '. *' In --exclude = '.
Git

18
--exclude-vcs se avessi intenzione di prendere questo tatto
plod

./FROM/ può essere un repository remoto?
Resist Design

2
In quanto FYI, la mia copia di rsyncelenca l'argomento come --cvs-exclude. Inoltre, continua a copiare.gitattributes e.gitignore
Ryan Ransford,

19

Ho visitato questa pagina frequentemente quando cercavo un modo per esportare un repository git. La mia risposta a questa domanda considera tre proprietà che svn export ha in base alla progettazione rispetto a git, poiché svn segue un approccio al repository centralizzato:

  • Riduce al minimo il traffico verso una posizione del repository remoto non esportando tutte le revisioni
  • Non include meta informazioni nella directory di esportazione
  • L'esportazione di un determinato ramo usando svn si ottiene specificando il percorso appropriato

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

Quando si crea una determinata versione è utile clonare un ramo stabile come ad esempio --branch stableo --branch release/0.9.


Questo non funziona se la destinazione esiste e non è vuota.
Eponimo

2
L'unica vera risposta: nasce dal profondo. L' git archive | tarapproccio è inapplicabile agli ambienti shell incompatibili con POSIX (ad es. CI basati su CMD o PowerShell di AppVeyor), che non è l'ideale. L' git checkoutapproccio modifica l'indice dell'albero di lavoro principale, il che è terribile. L' git checkout-indexapproccio richiede che l'indice dell'albero di lavoro principale venga modificato in anticipo, il che è persino terribile. L' git cloneapproccio tradizionale clona l'intera storia del repository prima di eliminare quella storia, il che è dispendioso. Questa è l'unica soluzione sana rimasta.
Cecil Curry,

1
Per esportare localmente, nota che il percorso assoluto dell'albero di lavoro di Git da cui clonare dovrebbe essere preceduto dal file://protocollo (ad es git clone --depth 1 --branch v3.14.15 file:///home/me/src_repo trg_repo.). Non farlo emetterà "warning: --depth is ignored in local clones; use file:// instead."ed eseguirà un clone standard piuttosto che superficiale, vanificando l'intero scopo di questa risposta. Salud!
Cecil Curry,

16

Questo copierà tutti i contenuti, meno i file .dot. Lo uso per esportare progetti clonati git nel repository git della mia app Web senza roba .git.

cp -R ./path-to-git-repo / path / to / destination /

Semplicemente il vecchio bash funziona alla grande :)


Perché non spingere semplicemente sul telecomando? Ancora più semplice di bash.
Nurettin,

2
che dire dei file che fanno parte delle applicazioni Web e il suo nome inizia con il punto? :) pensa a .htaccess
Artur

3
A volte vuoi anche ignorare cosa c'è dentro .gitignore, questo non lo farà.
fregante,

14

Semplice come clone quindi eliminare la cartella .git:

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


4
Onestamente - questa risposta, che è anche la numero 1 nella domanda - è ciò che farai il 99% delle volte. La maggior parte di queste risposte sono pazze e complicate.
Geoff Nixon

11

Per gli utenti GitHub, il git archive --remotemetodo non funzionerà direttamente, poiché l'URL di esportazione è effimero . Devi chiedere a GitHub l'URL, quindi scaricare tale URL. curlrende così facile:

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

Questo ti darà il codice esportato in una directory locale. Esempio:

$ 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

Modifica
Se si desidera inserire il codice in una directory specifica esistente (anziché quella casuale di github):

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

11

Sì, questo è un comando pulito e ordinato per archiviare il codice senza alcuna inclusione di git nell'archivio ed è utile passare in giro senza preoccuparsi della cronologia di git commit.

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

Questo è fantastico, basta rimuovere gitignore dopo ed è fatto e pronto per la condivisione.
Soggetto

La rimozione di .gitgnore ecc. È menzionata nei commenti di risposta accettati: usa il file .gitattributes, vedi feed.cloud.geek.nz/posts/excluding-files-from-git-archive
Sogger

10

Voglio solo sottolineare che nel caso in cui lo sei

  1. esportare una sottocartella del repository (è così che usavo la funzione di esportazione SVN)
  2. sono d'accordo con la copia di tutto da quella cartella alla destinazione di distribuzione
  3. e dal momento che hai già una copia dell'intero repository in atto.

Quindi puoi semplicemente usare al cp foo [destination]posto del menzionato git-archive master foo | -x -C [destination].


9

È possibile archiviare un repository remoto in qualsiasi commit come file zip.

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

8

Implementazione bash di git-export.

Ho segmentato i processi di creazione e rimozione di file .empty in base alla loro stessa funzione, con lo scopo di riutilizzarli nell'implementazione di "git-archive" (verrà pubblicato più avanti).

Ho anche aggiunto il file '.gitattributes' al processo per rimuovere i file non desiderati dalla cartella di esportazione di destinazione. È stata inclusa la verbosità del processo rendendo più efficiente la funzione "git-export".

Empty_file = "svuotare";

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;
  }

Produzione:

$ git-export /tmp/rel-1.0.0

Aggiunta di file ".empty" a cartelle vuote: ... fatto.

Componenti dell'indice di check-out: ... fatto.

Ripristino di HEAD e Index: ... fatto.

Eliminazione dei componenti specifici di Git: ...

'/tmp/rel-1.0.0/{.buildpath}' files ... done. '

'/tmp/rel-1.0.0/{.project}' files ... done. '

'/tmp/rel-1.0.0/{.gitignore}' files ... done. '

'/tmp/rel-1.0.0/{.git}' file ... fatto. '

'/tmp/rel-1.0.0/{.gitattributes}' files ... done. '

'/tmp/rel-1.0.0/{*.mno}' file ... fatto. '

'/tmp/rel-1.0.0/{*~}' files ... done. '

'/tmp/rel-1.0.0/{.*~}' files ... done. '

'/tmp/rel-1.0.0/{*.swp}' files ... done. '

'/tmp/rel-1.0.0/{*.swo}' file ... fatto. '

'/tmp/rel-1.0.0/{.DS_Store}' file ... fatto. '

'/tmp/rel-1.0.0/{.settings}' file ... fatto. '

'/tmp/rel-1.0.0/{.empty}' files ... done. '

fatto.

Archiviazione dei componenti estratti: ... fatto.

-rw-r - r-- 1 rotella admin 25445901 3 nov 12:57 /tmp/rel-1.0.0.tgz

Ora ho incorporato la funzionalità 'git archive' in un singolo processo che utilizza la funzione 'create_empty' e altre funzionalità.

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;
  }

Uso: git-archive [/ var / www / htdocs] /repos/web.domain/website:rel-1.0.0
tocororo

8

Se vuoi qualcosa che funzioni con i sottomoduli, potrebbe valere la pena provare.

Nota:

  • MASTER_DIR = anche un checkout con i tuoi sottomoduli estratti
  • DEST_DIR = dove finirà questa esportazione
  • Se hai rsync, penso che saresti in grado di fare la stessa cosa con ancora meno dolore alla palla.

ipotesi:

  • È necessario eseguirlo dalla directory principale di MASTER_DIR (ovvero dal cd MASTER_DIR ..)
  • Si presume che DEST_DIR sia stato creato. È abbastanza facile da modificare per includere la creazione di un DEST_DIR se lo si desidera

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


6

La mia preferenza sarebbe in realtà quella di avere una dist target nel tuo Makefile (o altro sistema di compilazione) che esporti un archivio distribuibile del tuo codice (.tar.bz2, .zip, .jar o qualunque cosa sia appropriata). Se ti capita di usare gli autotools GNU o i sistemi MakeMaker di Perl, penso che questo esista automaticamente per te. In caso contrario, consiglio vivamente di aggiungerlo.

ETA (2012-09-06): Wow, duri voti negativi. Credo ancora che sia meglio costruire le tue distribuzioni con i tuoi strumenti di costruzione piuttosto che con il tuo strumento di controllo del codice sorgente. Credo nella costruzione di artefatti con strumenti di costruzione. Nel mio attuale lavoro, il nostro prodotto principale è costruito con un bersaglio formica. Siamo nel bel mezzo di cambiare i sistemi di controllo del codice sorgente e la presenza di questo target formica significa una seccatura in meno nella migrazione.


Il progetto che avevo in mente non è un progetto in codice; capita di essere più sulla falsariga di un progetto di sito web.
Greg Hewgill,

Non affronta la domanda.
Andrew Ferrier,

1
Sì, una tale risposta potrebbe non adattarsi alle esigenze di tutti, ma i voti negativi sono bizzarri. Si tratta di una risposta del tutto valida, e anzi, in molti scenari, l'unica risposta corretta. Rende molto valido il fatto che pensare a questo problema come "problema dello strumento vc" stia spesso seguendo la strada sbagliata.
snogglethorpe,

6

Questo copierà i file in un intervallo di commit (da C a G) in un file tar. Nota: questo consentirà solo il commit dei file. Non l'intero repository. Leggermente modificato da qui

Esempio di commit della cronologia

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

Pagina di manuale di git-diff-tree

-r -> recluta in sotto-alberi

--no-commit-id -> git diff-tree genera una riga con l'ID commit quando applicabile. Questo flag ha soppresso l'output dell'ID commit.

--nome-solo -> Mostra solo i nomi dei file modificati.

--diff-filter = ACMRT -> Seleziona solo questi file. Vedi qui per l'elenco completo dei file

C..G -> File in questo intervallo di commit

C ~ -> Includi file da Commit C. Non solo file da Commit C.

| xargs tar -rf myTarFile -> output su tar


5

Quando capisco la domanda, si tratta più di scaricare solo un certo stato dal server, senza cronologia e senza dati di altri rami, piuttosto che estrarre uno stato da un repository locale (come fanno qui molte risposte).

Questo può essere fatto in questo modo:

git clone -b someBranch --depth 1 --single-branch git://somewhere.com/repo.git \
&& rm -rf repo/.git/
  • --single-branch è disponibile da Git 1.7.10 (aprile 2012).
  • --depthè (era?) riferito difettoso, ma per il caso di un'esportazione, i problemi citati non dovrebbero avere importanza.

Nota: ho appena notato che ci sono 2 pagine di anwsers, ne ho guardato solo uno prima di pubblicare. C'è solo una risposta simile con solo --depth, il che implica a --single-branchmeno che non --no-single-branchvenga dato, il che significa che probabilmente ha lo stesso effetto. Non sono sicuro, tuttavia, alcuni esperti potrebbero confermare?
Ondra Žižka,

4

Ne avevo bisogno per uno script deploy e non potevo usare nessuno degli approcci sopra menzionati. Invece ho trovato una soluzione diversa:

#!/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

Qual è stato il problema con una soluzione read-tree / checkout-index o archivio? Per quanto ne so, hai fatto l'equivalente di qualcosa di simile, mkdir -p "$2" && git --git-dir="$1" archive HEAD | tar -x -C "$2"ma un po 'più lungo.
CB Bailey,

1
Non riesco a far funzionare l'albero di lettura da un repository remoto e la soluzione di archiviazione non funziona con github.
troelskn,

Sì con l'archivio ottieni un comando non valido: errore 'git-upload-archive' ... e non ho l'opzione di configurazione core.gitProxy e il set di variabili d'ambiente
GIT_PROXY_COMMAND

4

Facendolo in modo semplice, questa è una funzione per .bash_profile, decomprime direttamente l'archivio nella posizione corrente, configura prima il tuo solito [url: percorso]. NOTA: con questa funzione si evita l'operazione di clonazione, si ottiene direttamente dal repository 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 ​​per .gitconfig, stessa configurazione richiesta (PRENDI CURA eseguendo il comando all'interno dei progetti .git, salta SEMPRE alla directory di base precedentemente come detto qui , fino a quando non viene risolto preferisco personalmente la funzione

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

4

Di gran lunga il modo più semplice che ho visto per farlo (e funziona anche su Windows) è git bundle:

git bundle create /some/bundle/path.bundle --all

Vedi questa risposta per maggiori dettagli: Come posso copiare il mio repository git dal mio computer Windows su un computer Linux tramite unità USB?


git bundleinclude la .gitcartella, che è ciò che l'OP non vuole; git archivesembra il modo più appropriato
ssc

Dov'è la documentazione sullo --allswitch?
Garret Wilson,

4

Ho un'altra soluzione che funziona benissimo se si dispone di una copia locale del repository sulla macchina in cui si desidera creare l'esportazione. In questo caso, passare a questa directory del repository e immettere questo comando:

GIT_WORK_TREE=outputdirectory git checkout -f

Ciò è particolarmente utile se gestisci un sito Web con un repository git e desideri effettuare il checkout di una versione pulita in /var/www/. In questo caso, aggiungi questo comando in uno .git/hooks/post-receivescript ( hooks/post-receivesu un repository nudo, che è più adatto in questa situazione)


3

Penso che il post di @Aredridel fosse il più vicino, ma c'è un po 'di più in questo - quindi lo aggiungerò qui; il fatto è, in svn, se sei in una sottocartella di un repository, e lo fai:

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

quindi svnesporterà tutti i file che sono sotto controllo di revisione (potrebbero anche averli aggiunti di recente; o stato modificato) - e se hai altra "spazzatura" in quella directory (e non sto contando .svnsottocartelle qui, ma cose visibili come .ofile) , sarà non essere esportato; verranno esportati solo i file registrati dal repository SVN. Per me, una cosa bella è che questa esportazione include anche file con modifiche locali che non sono ancora stati impegnati; e un'altra cosa carina è che i timestamp dei file esportati sono gli stessi di quelli originali. O, per svn help exportdirla:

  1. Esporta un albero di directory pulito dalla copia di lavoro specificata da PATH1, alla revisione REV se viene fornito, altrimenti in WORKING, in PATH2. ... Se non viene specificato REV, tutte le modifiche locali verranno conservate. I file non sotto controllo versione non verranno copiati.

Per capire che gitnon manterrà i timestamp, confronta l'output di questi comandi (in una sottocartella di un gitrepository di tua scelta):

/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 io, in ogni caso, noto che git archivefa sì che tutti i timestamp del file archiviato siano gli stessi! git help archivedice:

git archive si comporta in modo diverso quando viene assegnato un ID albero rispetto a quando viene assegnato un ID commit o ID tag. Nel primo caso l'ora corrente viene utilizzata come ora di modifica di ciascun file nell'archivio. In quest'ultimo caso viene invece utilizzato il tempo di commit come registrato nell'oggetto commit di riferimento.

... ma a quanto pare entrambi i casi impostano il "tempo di modifica di ciascun file"; quindi no preservando i timestamp effettivi di quei file!

Quindi, al fine di preservare anche i timestamp, ecco uno bashscript, che in realtà è un "one-liner", anche se un po 'complicato - quindi sotto è pubblicato in più righe:

/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 \
)

Si noti che si presume che tu stia esportando i contenuti nella directory "corrente" (sopra, /media/disk/git_svn/subdir) - e che la destinazione in cui stai esportando sia in qualche modo scomoda, ma è nella DESTvariabile d'ambiente. Si noti che con questo script; devi creare il fileDEST manualmente directory prima di eseguire lo script sopra.

Dopo aver eseguito lo script, dovresti essere in grado di confrontare:

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

... e speriamo di vedere gli stessi timestamp (per quei file che erano sotto il controllo della versione).

Spero che questo aiuti qualcuno,
Salute!


3

un'esportazione git in un archivio zip durante l'aggiunta di un prefisso (ad esempio il nome della directory):

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


1

ho la seguente funzione di utilità nel mio file .bashrc: crea un archivio del ramo corrente in un repository 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
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.