Faites une «exportation git» (comme «exportation svn»)?

2356

Je me demandais s'il existe une bonne solution "git export" qui crée une copie d'une arborescence sans le .gitrépertoire du référentiel. Il y a au moins trois méthodes que je connais:

  1. git clonesuivi de la suppression du .gitrépertoire du référentiel.
  2. git checkout-index fait allusion à cette fonctionnalité mais commence par "Il suffit de lire l'arborescence souhaitée dans l'index ..." que je ne sais pas trop comment faire.
  3. git-exportest un script tiers qui fait essentiellement un git clonedans un emplacement temporaire suivi de rsync --exclude='.git'la destination finale.

Aucune de ces solutions ne me semble vraiment satisfaisante. L' svn exportoption la plus proche pourrait être l'option 1, car les deux nécessitent que le répertoire cible soit vide en premier. Mais l'option 2 semble encore meilleure, en supposant que je puisse comprendre ce que signifie lire un arbre dans l'index.

Greg Hewgill
la source
1
@rnrTom: Voir la réponse de Somov. (il n'y a rien de "compressé" dans une archive tar).
etarion
23
@mrTom git archive --format zip --output "output.zip" master -0vous donnera une archive non compressée (-0 est le drapeau pour non compressé). git-scm.com/docs/git-archive .
7
Je suis d'accord avec @mrTom, et je ne pense pas que l'archive soit compressée ou non compressée est le principal problème. Avec SVN, je peux exportun sous-répertoire de 250 Ko directement à partir du référentiel distant (qui pourrait autrement avoir une taille de 200 Mo, hors révisions) - et je ne toucherai le réseau que pour un transfert de téléchargement de 250 Ko (ou plus). Avec git, archivedoit être activé sur le serveur (donc je ne peux pas l'essayer) - à clone --depth 1partir du serveur peut toujours récupérer un dépôt de disons 25 Mo, où le .gitsous - dossier à lui seul prend 15 Mo. Par conséquent, je dirais toujours que la réponse est "non".
sdaau
@mrTom la réponse est en fait OUI Voir la réponse de l'OP - la commande estgit checkout-index
nocache
Voici une manière simple et agréable:git archive -o latest.zip HEAD
Evgeni Sergeev

Réponses:

2397

Le moyen le plus simple d'y parvenir est probablement de git archive. Si vous avez vraiment besoin de l'arborescence développée, vous pouvez faire quelque chose comme ça.

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

La plupart du temps, j'ai besoin d'exporter quelque chose de git, je veux en tout cas une archive compressée, donc je fais quelque chose comme ça.

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

Archive ZIP:

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

git help archive pour plus de détails, c'est assez flexible.


Sachez que même si l'archive ne contiendra pas le répertoire .git, elle contiendra cependant d'autres fichiers spécifiques à git cachés comme .gitignore, .gitattributes, etc. Si vous ne les voulez pas dans l'archive, assurez-vous de utilisez l'attribut export-ignore dans un fichier .gitattributes et validez-le avant de faire votre archive. Lire la suite...


Remarque: si vous souhaitez exporter l'index, la commande est

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

(Voir la réponse de Greg pour plus de détails)

CB Bailey
la source
198
Archive ZIP:git archive --format zip --output /full/path master
Vadim
221
Sachez que l'archive ne contiendra pas le répertoire .git, mais contiendra d'autres fichiers cachés spécifiques à git comme .gitignore, .gitattributes, etc. Donc, si vous ne les voulez pas, assurez-vous d'utiliser l'attribut export-ignore dans un fichier .gitattributes et validez-le avant de faire votre archive. Voir feed.cloud.geek.nz/2010/02/…
mj1531
54
Pour suivre la note de Streams: vous pouvez ajouter une chaîne '--prefix = quelque chose /' dans la commande pour contrôler le nom du répertoire qui sera compressé à l'intérieur du zip. Par exemple, si vous utilisez git archive --format zip --output /path/to/file.zip --prefix=newdir/ masterla sortie, elle s'appellera «file.zip» mais lorsque vous la décompressez, le répertoire de niveau supérieur sera «newdir». (Si vous omettez l'attribut --prefix, le répertoire de niveau supérieur serait 'file'.)
Alan W. Smith
89
Le moyen le plus simple: git archive -o latest.zip HEADil crée une archive Zip qui contient le contenu du dernier commit sur la branche courante. Notez que le format de sortie est déduit de l'extension du fichier de sortie.
nacho4d
37
Il ne prend pas en charge les sous-modules git :(
umpirsky
320

J'ai découvert ce que signifie l'option 2. À partir d'un référentiel, vous pouvez faire:

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

La barre oblique à la fin du chemin est importante, sinon elle entraînera que les fichiers se trouvent dans / destination avec un préfixe «chemin».

Comme dans une situation normale, l'index contient le contenu du référentiel, il n'y a rien de spécial à faire pour "lire l'arborescence souhaitée dans l'index". C'est déjà là.

Le -adrapeau est requis pour extraire tous les fichiers de l'index (je ne sais pas ce que cela signifie d'omettre ce drapeau dans cette situation, car il ne fait pas ce que je veux). L' -findicateur force l'écrasement de tous les fichiers existants dans la sortie, ce que cette commande ne fait normalement pas.

Cela semble être le genre de "git export" que je recherchais.

Greg Hewgill
la source
73
... et N'OUBLIEZ PAS LE SLASH À LA FIN, sinon vous n'aurez pas l'effet désiré;)
conny
1
La git addcommande modifie le contenu de l'index, donc tout ce qui git statusapparaît comme "à valider" correspond aux différences entre HEAD et le contenu de l'index.
Greg Hewgill
7
@conny: lisez votre commentaire, oubliez-le et exécutez la commande sans barre oblique de fin. astuce: suivez les conseils de conny -.-
Znarkus
35
+1 aux conseils de conny. N'essayez pas non plus de créer '~ / dest /', car cela crée un répertoire appelé '~' dans votre répertoire de travail, plutôt que ce que vous vouliez vraiment. Devinez ce qui se passe lorsque vous tapez sans réfléchir rm -rf ~
Kyle Heironimus
5
@KyleHeironimus - votre avertissement concernant l'utilisation de '~ / dest / `est vrai si vous utilisez des guillemets autour de votre chemin de préfixe qui indique au shell de ne pas effectuer d'expansion de tilde. Un répertoire appelé ~(pas '~'!) Sera créé dans votre répertoire de travail. Il n'y a rien de spécial git checkout-indexà cet égard: la même chose est vraie de mkdir '~/dest'( ne faites pas ça! ). Encore une autre bonne raison d'éviter les noms de fichiers qui doivent être cités (par exemple, qui contiennent un espace) :-)
Matt Wallis
254

git archive fonctionne également avec le référentiel distant.

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

Pour exporter un chemin particulier à l'intérieur du référentiel, ajoutez autant de chemins que vous le souhaitez comme dernier argument à git, par exemple:

git archive --format=tar \
--remote=ssh://remote_server/remote_repository master path1/ path2/ | tar -xv
Alexander Somov
la source
6
Celui-ci est l'option que je préfère. Il présente l'avantage supplémentaire de fonctionner également sur des référentiels nus.
innaM
5
Une version améliorée est: git archive --format=tar --prefix=PROJECT_NAME/ --remote=USER@SERVER:PROJECT_NAME.git master | tar -xf - (assure que votre archive est dans un dossier)
Nick
7
Remarque : le serveur doit activer cette fonction.
Jakub Narębski
12
J'ai essayé: git archive --format=zip --output foo.zip --remote=https://github.com/xxx.git masterEt j'ai été fatal: Opération non prise en charge par le protocole. Fin inattendue du flux de commandes.
andyf
7
@andyf GitHub a sa propre façon: curl -L https://api.github.com/repos/VENDOR/PROJECT/tarball | tar xzf -par docs
évêque
63

entrez la description de l'image ici

Une réponse à un cas particulier si le référentiel est hébergé sur GitHub.

Utilisez simplement svn export.

Autant que je sache, Github ne le permet pas archive --remote. Bien que GitHub soit compatible svn et que tous les dépôts git soient svnaccessibles, vous pouvez simplement les utiliser svn exportcomme vous le feriez normalement avec quelques ajustements à votre URL GitHub.

Par exemple, pour exporter un référentiel entier, notez comment trunkdans l'URL remplace master(ou quel que soit le branchement HEAD du projet ):

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

Et vous pouvez exporter un seul fichier ou même un certain chemin ou dossier:

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

Exemple avec la bibliothèque JavaScript jQuery

La HEADbranche ou maître branche sera disponible à l' aide trunk:

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

Les non- HEAD succursales seront accessibles sous /branches/:

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

Tous les tags sous /tags/de la même manière:

svn ls https://github.com/jquery/jquery/tags/2.1.3
Anthony Hatzopoulos
la source
1
git archivefonctionne très bien avec GitHub, tant que vous utilisez le protocole git, remplacez simplement https://par git://dans l'URL. Je ne sais pas pourquoi GitHub ne fait pas de publicité sur cette fonctionnalité cachée.
Neil Mayhew
1
@NeilMayhew Ça ne marche pas pour moi, je comprends fatal: The remote end hung up unexpectedly. J'ai essayé sur deux serveurs différents avec jQuery github repo.
Anthony Hatzopoulos
1
Tu as raison. J'avais oublié que j'utilisais git config url.<base>.insteadOfpour mettre en cache le référentiel distant. J'utilisais donc une file://URL en réalité. Je doute que cela git archivepuisse jamais fonctionner avec des git://URL car il doit pouvoir fonctionner git-upload-archiveà l'extrémité distante. Cela devrait être possible en utilisant le sshprotocole, sauf que github ne le permet pas ( Invalid command: 'git-upload-archive').
Neil Mayhew
Est-il possible d'utiliser un outil de serveur local se comportant comme github si je veux le faire sur des référentiels git hébergés en interne?
kriss
1
a voté - c'est complètement bizarre que Git n'ait pas cette fonctionnalité et nous devons recourir à svn
Jason S
40

Depuis le manuel Git :

Utiliser git-checkout-index pour "exporter un arbre entier"

La capacité de préfixe rend fondamentalement trivial l'utilisation de git-checkout-index comme une fonction "exportation sous forme d'arbre". Il suffit de lire l'arbre souhaité dans l'index et de faire:

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

jperras
la source
19
Je pense que la confusion est l'expression "lire l'arbre souhaité dans l'index".
davetron5000
4
Si vous voulez exporter le répertoire foo dans la barre de branche, alors ce serait git read-tree bar:fooEt git checkout-index --prefix=export_dir/ -aaprès cela, vous devriez peut-être le fairegit update-index master
Pascal Rosin
1
@JohnWeldon Faut-il d'abord cloner le dépôt? Si c'est le cas, je ne l'accepterais pas, car le but de l '"exportation svn" d'un sous-répertoire est d'obtenir directement une copie de ce sous-répertoire; si quelqu'un a un dépôt Git de 1 Go et tout ce que je veux, c'est un sous-répertoire de 10 Ko, il est insensé de m'obliger à cloner le tout.
Jason S
3
Je voudrais également faire écho à @ davetron5000 avec le commentaire "lire l'arbre souhaité dans l'index" dont je n'ai aucune idée de ce que cela signifie.
Jason S
38

J'ai écrit un simple wrapper git-checkout-indexque vous pouvez utiliser comme ceci:

git export ~/the/destination/dir

Si le répertoire de destination existe déjà, vous devrez ajouter -fou --force.

L'installation est simple; déposez simplement le script quelque part dans votre PATH, et assurez-vous qu'il est exécutable.

Le référentiel github pour git-export

Daniel Schierbeck
la source
15
Ce wrapper n'est pas indépendant de la plateforme; il s'appuie sur / bin / sh. Donc, si vous êtes sous Windows, cette solution ne fonctionnera probablement pas pour vous.
shovavnik
18
Euh, ce script est composé de 57 lignes de documentation, d'espaces, de configuration, d'analyse des arguments et d'une seule ligne qui fait réellement quelque chose ...
Vladimir Panteleev
36

Il semble que ce soit moins un problème avec Git qu'avec SVN. Git place uniquement un dossier .git dans la racine du référentiel, tandis que SVN place un dossier .svn dans chaque sous-répertoire. Donc, "svn export" évite la magie récursive en ligne de commande, alors qu'avec Git la récursivité n'est pas nécessaire.

kostmo
la source
26
Depuis SVN 1.7, il n'y a qu'un seul dossier .svn: subversion.apache.org/docs/release-notes/1.7.html#single-db
kostmo
Cela ne supprimera pas les fichiers de construction supplémentaires que l'exportation svn supprime. Ce n'est donc certainement pas la réponse.
ygoe
28

L'équivalent de

svn export . otherpath

à l'intérieur d'un référentiel existant est

git archive branchname | (cd otherpath; tar x)

L'équivalent de

svn export url otherpath

est

git archive --remote=url branchname | (cd otherpath; tar x)
aredridel
la source
1
merci, c'est ce qui me manquait ... aussi, pour vérifier les horodatages de l'export (ils ne seront pas conservés comme sur les fichiers), utilisez git archive --format=tar --prefix=junk/ HEAD | (tar -t -v --full-time -f -)... Cependant, l'archivage avec horodatages n'est pas exactement trivial, donc j'ai posté un exemple ci-dessous .
sdaau
1
Vous pouvez utiliser l'option C pour tar au lieu du sous-shell, comme ceci: git archive branchname | tar xC otherpath
James Moore
Indique que l' Coption de tar est uniquement GNU Tar.
aredridel du
22

Si vous n'excluez pas de fichiers avec, .gitattributes export-ignoreessayezgit checkout

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

-f
Lors de l'extraction de chemins à partir de l'index, n'échouez pas lors des entrées non fusionnées; au lieu de cela, les entrées non fusionnées sont ignorées.

et

-q
Évitez verbeux

De plus, vous pouvez obtenir n'importe quelle branche ou étiquette ou à partir d'une révision de validation spécifique comme dans SVN en ajoutant simplement SHA1 (SHA1 dans Git est l'équivalent du numéro de révision dans SVN)

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

Le /path/to/checkout/doit être vide, Git ne supprimera aucun fichier, mais écrasera les fichiers du même nom sans aucun avertissement

MISE À JOUR: Pour éviter le problème décapité ou pour laisser intact le référentiel de travail lors de l'utilisation de la caisse pour l'exportation avec des balises, des branches ou SHA1, vous devez ajouter -- ./à la fin

Le double tiret --indique à git que tout ce qui se trouve après les tirets sont des chemins ou des fichiers, et dans ce cas, indique également git checkoutde ne pas modifier leHEAD

Exemples:

Cette commande obtiendra uniquement le répertoire libs et également le readme.txtfichier de ce commit

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

Cela va créer (écraser) my_file_2_behind_HEAD.txtdeux commits derrière la têteHEAD^2

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

Pour obtenir l'exportation d'une autre branche

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

Notez que ./c'est relatif à la racine du référentiel

5286776117878
la source
En fait, parmi de nombreux autres et votes positifs, cela a fonctionné le mieux pour moi, sans aucune compression, fonctionnant très bien avec des dépôts nus (gitolite).
prend
1
Notez que l'extraction SHA1 créera un problème de "décapitation" dans le référentiel
user5286776117878
actuellement @ITGabs, cela ne télécharge pas le dossier ".git". Le dossier téléchargé n'est donc pas un dépôt git, il n'est donc pas techniquement "décapité"
Fabio Marreco
@FabioMarreco Le problème de décapitation est sur le référentiel pas dans les fichiers exportés / téléchargés, je mets à jour la réponse pour plus de détails
user5286776117878
3
Cela a très bien fonctionné pour moi. Mais au début, j'ai reçu des messages d'erreur "Pas un dépôt git". Ensuite, j'ai trouvé que "/ path / to / repo /" devait pointer vers le dossier .git. Cela a donc fonctionné: --git-dir = / path / to / repo / .git
philburk
21

J'utilise largement les sous-modules git. Celui-ci fonctionne pour moi:

rsync -a ./FROM/ ./TO --exclude='.*'
slatvick
la source
1
Cela ne manquerait-il pas des fichiers dont les noms commencent par un point, comme .htaccess?
Greg Hewgill,
8
Une bonne solution, je changerais --exclude = '. *' En --exclude = '.
Git
18
--exclude-vcs si vous deviez prendre ce tact
plod
./FROM/ peut-il être un dépôt à distance?
Resist Design
2
En tant que FYI, ma copie de la rsyncliste des arguments comme --cvs-exclude. De plus, il copie encore .gitattributeset.gitignore
Ryan Ransford
19

J'ai souvent visité cette page lorsque je cherche un moyen d'exporter un référentiel git. Ma réponse à cette question considère trois propriétés que svn export a par conception par rapport à git, car svn suit une approche de référentiel centralisé:

  • Il minimise le trafic vers un emplacement de référentiel distant en n'exportant pas toutes les révisions
  • Il n'inclut pas de méta-informations dans le répertoire d'exportation
  • L'exportation d'une certaine branche à l'aide de svn s'effectue en spécifiant le chemin approprié

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

Lors de la construction d'une certaine version, il est utile de cloner une branche stable comme par exemple --branch stableou --branch release/0.9.

Lars Schillingmann
la source
Cela ne fonctionne pas si la destination existe et n'est pas vide.
Éponyme du
2
La seule vraie réponse: elle provient des profondeurs. L' git archive | tarapproche n'est pas applicable aux environnements de shell incompatibles avec POSIX (par exemple, le CMD d'AppVeyor ou le CI basé sur PowerShell), ce qui n'est pas idéal. L' git checkoutapproche modifie l'index de l'arbre de travail principal, ce qui est affreux. L' git checkout-indexapproche nécessite que l'index de l'arbre de travail principal soit modifié au préalable, ce qui est encore pire. L' git cloneapproche traditionnelle clone l'intégralité de l'historique du référentiel avant de supprimer cette histoire, ce qui est inutile. C'est la seule solution saine qui reste.
Cecil Curry
1
Pour exporter localement, notez que le chemin absolu de l'arbre de travail Git à partir duquel le clonage doit être préfixé par le file://protocole (par exemple, git clone --depth 1 --branch v3.14.15 file:///home/me/src_repo trg_repo). Si vous ne le faites pas, vous émettez "warning: --depth is ignored in local clones; use file:// instead."et effectuez un clone standard plutôt que superficiel, ce qui va à l'encontre de l'objectif de cette réponse. Salud!
Cecil Curry
16

Cela copiera tout le contenu, moins les fichiers .dot. Je l'utilise pour exporter des projets git clonés dans le dépôt git de mon application Web sans les trucs .git.

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

Plain old bash fonctionne tout simplement :)

Harmon
la source
Pourquoi ne pas simplement pousser vers la télécommande? Encore plus simple que bash.
nurettin
2
qu'en est-il des fichiers qui font partie des applications Web et son nom commence par un point? :) pensez à .htaccess
Artur
3
Parfois, vous voulez également ignorer ce qui s'y trouve .gitignore, ce ne sera pas le cas.
fregante
14

Aussi simple que cloner, supprimez le dossier .git:

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

teleme.io
la source
4
Honnêtement - cette réponse, qui est également n ° 1 dans la question - est ce que vous allez faire 99% du temps. La plupart de ces réponses sont follement compliquées.
Geoff Nixon
11

Pour les utilisateurs de GitHub, la git archive --remoteméthode ne fonctionnera pas directement, car l'URL d'exportation est éphémère . Vous devez demander l'URL à GitHub, puis télécharger cette URL. curlrend cela facile:

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

Cela vous donnera le code exporté dans un répertoire local. Exemple:

$ 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

Modifier
Si vous voulez que le code soit placé dans un répertoire spécifique existant (plutôt que dans le répertoire aléatoire de github):

curl -L https://api.github.com/repos/VENDOR/PROJECT/tarball | \
tar xzC /path/you/want --strip 1
évêque
la source
11

Oui, c'est une commande propre et soigné pour archiver votre code sans inclusion git dans l'archive et il est bon de passer autour sans se soucier de toute git commit histoire.

git archive --format zip --output /full/path/to/zipfile.zip master 
Zeeawan
la source
C'est super, il suffit de supprimer gitignore après et c'est fait et prêt à partager.
Sogger
La suppression de .gitgnore etc. est mentionnée dans les commentaires de réponse acceptés: utilisez le fichier .gitattributes, voir feed.cloud.geek.nz/posts/excluding-files-from-git-archive
Sogger
10

Je veux juste souligner que dans le cas où vous êtes

  1. exporter un sous-dossier du référentiel (c'est comme ça que j'utilisais la fonction d'exportation SVN)
  2. êtes d'accord pour tout copier de ce dossier vers la destination de déploiement
  3. et puisque vous avez déjà une copie de l'ensemble du référentiel en place.

Ensuite, vous pouvez simplement utiliser à la cp foo [destination]place de ce qui est mentionné git-archive master foo | -x -C [destination].

dkinzer
la source
9

Vous pouvez archiver un dépôt à distance à tout commit en tant que fichier zip.

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

Bash-implémentation de git-export.

J'ai segmenté les processus de création et de suppression de fichiers .empty sur leur propre fonction, dans le but de les réutiliser dans l'implémentation de 'git-archive' (sera publié plus tard).

J'ai également ajouté le fichier «.gitattributes» au processus afin de supprimer les fichiers indésirables du dossier d'exportation cible. Inclus la verbosité du processus tout en rendant la fonction 'git-export' plus efficace.

EMPTY_FILE = ". Empty";

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

Production:

$ git-export /tmp/rel-1.0.0

Ajout de fichiers «.empty» à des dossiers vides: ... terminé.

Extraction des composants de l'index: ... terminé.

Réinitialisation de HEAD et Index: ... terminé.

Purge des composants spécifiques à Git: ...

'/tmp/rel-1.0.0/{.buildpath}' fichiers ... terminé. '

'/tmp/rel-1.0.0/{.project}' fichiers ... terminé. '

'/tmp/rel-1.0.0/{.gitignore}' fichiers ... terminé. '

'/tmp/rel-1.0.0/{.git}' fichiers ... terminé. '

'/tmp/rel-1.0.0/{.gitattributes}' fichiers ... terminé. '

'/tmp/rel-1.0.0/{*.mno}' fichiers ... terminé. '

'/tmp/rel-1.0.0/{*~}' fichiers ... terminé. '

'/tmp/rel-1.0.0/{.*~}' fichiers ... terminé. '

'/tmp/rel-1.0.0/{*.swp}' fichiers ... terminé. '

'/tmp/rel-1.0.0/{*.swo}' fichiers ... terminé. '

'/tmp/rel-1.0.0/{.DS_Store}' fichiers ... terminé. '

'/tmp/rel-1.0.0/{.settings}' fichiers ... terminé. '

'/tmp/rel-1.0.0/{.empty}' fichiers ... terminé. '

terminé.

Archivage des composants extraits: ... terminé.

-rw-r - r-- 1 roue d'administration 25445901 3 nov 12:57 /tmp/rel-1.0.0.tgz

J'ai maintenant intégré la fonctionnalité 'git archive' dans un processus unique qui utilise la fonction 'create_empty' et d'autres fonctionnalités.

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
la source
Utilisation: git-archive [/ var / www / htdocs] /repos/web.domain/website:rel-1.0.0
tocororo
8

Si vous voulez quelque chose qui fonctionne avec des sous-modules, cela pourrait valoir le coup.

Remarque:

  • MASTER_DIR = un paiement avec vos sous-modules récupérés également
  • DEST_DIR = où se terminera cette exportation
  • Si vous avez rsync, je pense que vous pourriez faire la même chose avec encore moins de maux de balle.

Hypothèses:

  • Vous devez l'exécuter à partir du répertoire parent de MASTER_DIR (c'est-à-dire à partir de MASTER_DIR cd ..)
  • DEST_DIR est supposé avoir été créé. C'est assez facile à modifier pour inclure la création d'un DEST_DIR si vous voulez

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
la source
6

Ma préférence serait en fait d'avoir une cible dist dans votre Makefile (ou autre système de build) qui exporte une archive distribuable de votre code (.tar.bz2, .zip, .jar, ou tout ce qui est approprié). S'il vous arrive d'utiliser des outils automatiques GNU ou les systèmes MakeMaker de Perl, je pense que cela existe automatiquement pour vous. Sinon, je recommande fortement de l'ajouter.

ETA (2012-09-06): Wow, des downvotes sévères. Je pense toujours qu'il vaut mieux construire vos distributions avec vos outils de build plutôt qu'avec votre outil de contrôle de code source. Je crois en la construction d'artefacts avec des outils de construction. Dans mon travail actuel, notre produit principal est construit avec une cible de fourmi. Nous sommes en train de changer de système de contrôle de code source, et la présence de cette cible de fourmi signifie un tracas de migration en moins.

skiphoppy
la source
Le projet que j'avais en tête n'est pas un projet de code; il se trouve que cela ressemble davantage à un projet de site Web.
Greg Hewgill
Ne répond pas à la question.
Andrew Ferrier
1
Oui, une telle réponse peut ne pas répondre aux besoins de tout le monde, mais les votes négatifs sont bizarres. Il est une réponse tout à fait valable, et en effet, dans de nombreux scénarios, la seule réponse correcte. Il est très valable de penser que le fait de considérer ce problème comme un "problème d'outil vc" va souvent dans le mauvais sens.
snogglethorpe
6

Cela copiera les fichiers dans une plage de validations (C à G) dans un fichier tar. Remarque: cela ne fera que valider les fichiers. Pas l'intégralité du référentiel. Légèrement modifié d' ici

Exemple d'historique de validation

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

Page de manuel de git-diff-tree

-r -> recurse dans les sous-arbres

--no-commit-id -> git diff-tree affiche une ligne avec l'ID de validation le cas échéant. Cet indicateur a supprimé la sortie de l'ID de validation.

--name-only -> Afficher uniquement les noms des fichiers modifiés.

--diff-filter = ACMRT -> Sélectionnez uniquement ces fichiers. Voir ici pour la liste complète des fichiers

C..G -> Fichiers dans cette gamme de commits

C ~ -> Inclure les fichiers de Commit C. Pas seulement les fichiers depuis Commit C.

| xargs tar -rf myTarFile -> sorties vers tar

Fuyu Persimmon
la source
5

Si je comprends bien la question, il s'agit davantage de télécharger uniquement un certain état du serveur, sans historique et sans données d'autres branches, plutôt que d'extraire un état d'un référentiel local (comme le font de nombreuses réponses ici).

Cela peut se faire comme ceci:

git clone -b someBranch --depth 1 --single-branch git://somewhere.com/repo.git \
&& rm -rf repo/.git/
  • --single-branch est disponible depuis Git 1.7.10 (avril 2012).
  • --depthest (était?) censément défectueux, mais dans le cas d'une exportation, les problèmes mentionnés ne devraient pas avoir d'importance.
Ondra Žižka
la source
Remarque: Je viens de remarquer qu'il y a 2 pages de réponses, je n'en ai regardé qu'une avant de poster. Il n'y a qu'une seule réponse similaire avec --depth, ce qui implique --single-branchque sauf si --no-single-branchest donné, ce qui signifie que cela a probablement le même effet. Pas sûr cependant, un expert peut confirmer?
Ondra Žižka
4

J'en avais besoin pour un script de déploiement et je ne pouvais utiliser aucune des approches mentionnées ci-dessus. Au lieu de cela, j'ai trouvé une solution différente:

#!/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
la source
Quel était le problème avec une solution d'arborescence de lecture / d'index de sortie ou d'archivage? Autant que je sache, vous avez fait l'équivalent de quelque chose comme mkdir -p "$2" && git --git-dir="$1" archive HEAD | tar -x -C "$2"mais un peu plus long.
CB Bailey
1
Je n'ai pas pu faire fonctionner l'arborescence de lecture à partir d'un référentiel distant et la solution d'archivage ne fonctionne pas avec github.
troelskn
Oui avec archive obtenez une commande non valide: 'git-upload-archive' ... erreur et je n'ai pas l'option de configuration core.gitProxy et le jeu de variables d'environnement
GIT_PROXY_COMMAND
4

En le faisant facilement, c'est une fonction pour .bash_profile, il décompresse directement l'archive sur l'emplacement actuel, configurez d'abord votre [url: chemin] habituel. REMARQUE: Avec cette fonction, vous évitez l'opération de clonage, elle provient directement du référentiel distant.

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 ​​pour .gitconfig, même configuration requise (PRENEZ SOIN d'exécuter la commande à l'intérieur des projets .git, il saute TOUJOURS au répertoire de base précédemment comme indiqué ici , jusqu'à ce que ce soit corrigé, je préfère personnellement la fonction

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
la source
4

De loin, la façon la plus simple que j'ai vue de le faire (et fonctionne également sur Windows) est git bundle:

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

Voir cette réponse pour plus de détails: Comment puis-je copier mon référentiel git de ma machine Windows vers une machine Linux via un lecteur USB?

BT
la source
git bundleinclut le .gitdossier, ce que l'OP ne veut pas; git archivesemble la façon la plus appropriée
ssc
Où est la documentation sur le --allcommutateur?
Garret Wilson
4

J'ai une autre solution qui fonctionne bien si vous avez une copie locale du référentiel sur la machine où vous souhaitez créer l'exportation. Dans ce cas, accédez à ce répertoire de référentiel et entrez cette commande:

GIT_WORK_TREE=outputdirectory git checkout -f

Cela est particulièrement utile si vous gérez un site Web avec un référentiel git et souhaitez extraire une version propre dans /var/www/. Dans ce cas, ajoutez cette commande dans un .git/hooks/post-receivescript ( hooks/post-receivesur un référentiel nu, ce qui est plus approprié dans cette situation)

À M
la source
3

Je pense que le message de @Aredridel était le plus proche, mais il y a un peu plus - je vais donc ajouter ceci ici; la chose est, dans svn, si vous êtes dans un sous-dossier d'un repo, et vous faites:

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

puis svnexportera tous les fichiers qui sont sous contrôle de révision (ils pourraient également avoir été récemment ajoutés; ou état modifié) - et si vous avez d'autres "ordures" dans ce répertoire (et je ne compte pas les .svnsous-dossiers ici, mais des choses visibles comme des .ofichiers) , il ne sera pas exporté; seuls les fichiers enregistrés par le dépôt SVN seront exportés. Pour moi, une bonne chose est que cette exportation inclut également des fichiers avec des modifications locales qui n'ont pas encore été validées; et une autre bonne chose est que les horodatages des fichiers exportés sont les mêmes que ceux d'origine. Ou, comme le svn help exportdit:

  1. Exporte une arborescence de répertoires propre de la copie de travail spécifiée par PATH1, à la révision REV si elle est donnée, sinon à WORKING, dans PATH2. ... Si REV n'est pas spécifié, toutes les modifications locales seront conservées. Les fichiers qui ne sont pas sous contrôle de version ne seront pas copiés.

Pour réaliser que gitcela ne préservera pas les horodatages, comparez la sortie de ces commandes (dans un sous-dossier d'un gitdépôt de votre choix):

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

... et:

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

... et je remarque en tout cas que git archivetous les horodatages du fichier archivé sont identiques! git help archivedit:

git archive se comporte différemment quand on lui donne un ID d'arbre par rapport à quand on lui donne un ID de commit ou un ID de tag. Dans le premier cas, l'heure actuelle est utilisée comme heure de modification de chaque fichier de l'archive. Dans ce dernier cas, le temps de validation enregistré dans l'objet de validation référencé est utilisé à la place.

... mais apparemment les deux cas fixent le "temps de modification de chaque fichier"; donc pas préservant les horodatages réels de ces fichiers!

Donc, afin de préserver également les horodatages, voici un bashscript, qui est en fait un "one-liner", quoique quelque peu compliqué - donc ci-dessous il est affiché sur plusieurs lignes:

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

Notez que l'on suppose que vous exportez le contenu dans le répertoire "actuel" (ci-dessus, /media/disk/git_svn/subdir) - et que la destination dans laquelle vous exportez est quelque peu gênante, mais elle est dans DESTla variable d'environnement. Notez qu'avec ce script; vous devez créer leDEST répertoire manuellement vous-même, avant d'exécuter le script ci-dessus.

Une fois le script exécuté, vous devriez pouvoir comparer:

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

... et j'espère voir les mêmes horodatages (pour les fichiers qui étaient sous contrôle de version).

J'espère que cela aide quelqu'un,
Cheers!

sdaau
la source
3

une exportation git vers une archive zip tout en ajoutant un préfixe (par exemple le nom du répertoire):

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

j'ai la fonction utilitaire suivante dans mon fichier .bashrc: il crée une archive de la branche actuelle dans un référentiel 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
la source