¿Hacer una "exportación git" (como "exportación svn")?

2356

Me he estado preguntando si hay una buena solución de "exportación git" que cree una copia de un árbol sin el .gitdirectorio del repositorio. Hay al menos tres métodos que conozco:

  1. git cloneseguido de eliminar el .gitdirectorio del repositorio.
  2. git checkout-index Alude a esta funcionalidad, pero comienza con "Simplemente lea el árbol deseado en el índice ...", que no estoy completamente seguro de cómo hacer.
  3. git-exportes un script de terceros que esencialmente realiza una git cloneubicación temporal seguida rsync --exclude='.git'del destino final.

Ninguna de estas soluciones realmente me parece satisfactoria. La más cercana svn exportpodría ser la opción 1, porque ambas requieren que el directorio de destino esté vacío primero. Pero la opción 2 parece aún mejor, suponiendo que pueda entender lo que significa leer un árbol en el índice.

Greg Hewgill
fuente
1
@rnrTom: Ver la respuesta de Somov. (no hay nada "comprimido" en un archivo tar).
Etarion
23
@mrTom git archive --format zip --output "output.zip" master -0le proporcionará un archivo sin comprimir (-0 es la marca para sin comprimir). git-scm.com/docs/git-archive .
77
Estoy de acuerdo con @mrTom, y no creo que el problema principal sea si el archivo está comprimido o no. Con SVN, puedo exportun subdirectorio de 250 kB directamente desde el repositorio remoto (que de otro modo podría tener un tamaño de 200 MB, excluyendo las revisiones), y solo llegaré a la red para una transferencia de descarga de 250 kB (más o menos). Con git, archivetiene que estar habilitado en el servidor (por lo que no puedo probarlo): clone --depth 1del servidor aún puede recuperar un repositorio de, digamos, 25 MB, donde la .gitsubcarpeta solo ocupa 15 MB. Por lo tanto, todavía diría que la respuesta es "no".
sdaau
@mrTom la respuesta es de hecho Vea la respuesta del OP - el comando esgit checkout-index
nocache
Aquí hay una manera agradable y simple:git archive -o latest.zip HEAD
Evgeni Sergeev

Respuestas:

2397

Probablemente la forma más sencilla de lograr esto es con git archive. Si realmente necesita solo el árbol expandido, puede hacer algo como esto.

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

La mayoría de las veces que necesito 'exportar' algo de git, quiero un archivo comprimido en cualquier caso, así que hago algo como esto.

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

Archivo ZIP:

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

git help archive Para más detalles, es bastante flexible.


Tenga en cuenta que aunque el archivo no contendrá el directorio .git, sin embargo, contendrá otros archivos ocultos específicos de git como .gitignore, .gitattributes, etc. Si no los quiere en el archivo, asegúrese de use el atributo export-ignore en un archivo .gitattributes y confirme esto antes de hacer su archivo. Lee mas...


Nota: Si está interesado en exportar el índice, el comando es

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

(Ver la respuesta de Greg para más detalles)

CB Bailey
fuente
198
Archivo ZIP:git archive --format zip --output /full/path master
Vadim
221
Tenga en cuenta que el archivo no contendrá el directorio .git, pero contendrá otros archivos ocultos específicos de git como .gitignore, .gitattributes, etc. Así que si no los quiere, asegúrese de usar el atributo export-ignore en un archivo .gitattributes y confirme esto antes de hacer su archivo. Ver feeding.cloud.geek.nz/2010/02/…
mj1531
54
Para seguir la nota de Streams: puede agregar una cadena '--prefix = something /' en el comando para controlar el nombre del directorio que se empaquetará dentro del zip. Por ejemplo, si usa git archive --format zip --output /path/to/file.zip --prefix=newdir/ masterla salida se llamará 'file.zip' pero cuando lo desempaquete, el directorio de nivel superior será 'newdir'. (Si omite el atributo --prefix, el directorio de nivel superior sería 'archivo'.)
Alan W. Smith
89
La forma más fácil: git archive -o latest.zip HEADcrea un archivo Zip que contiene el contenido de la última confirmación en la rama actual. Tenga en cuenta que el formato de salida se infiere por la extensión del archivo de salida.
nacho4d 01 de
37
No es compatible con submódulos git :(
umpirsky
320

Descubrí qué significa la opción 2. Desde un repositorio, puede hacer:

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

La barra diagonal al final de la ruta es importante, de lo contrario, los archivos estarán en / destino con el prefijo 'ruta'.

Como en una situación normal el índice contiene el contenido del repositorio, no hay nada especial que hacer para "leer el árbol deseado en el índice". Ya esta ahí.

Se -arequiere el indicador para verificar todos los archivos en el índice (no estoy seguro de lo que significa omitir este indicador en esta situación, ya que no hace lo que quiero). La -fbandera obliga a sobrescribir cualquier archivo existente en la salida, lo que este comando normalmente no hace.

Este parece ser el tipo de "exportación de git" que estaba buscando.

Greg Hewgill
fuente
73
... y NO OLVIDES EL SLASH AL FINAL, o no tendrás el efecto deseado;)
conny
1
El git addcomando cambia el contenido en el índice, por lo que lo que se git statusmuestra como "para confirmar" son las diferencias entre HEAD y el contenido del índice.
Greg Hewgill
77
@conny: lee tu comentario, lo olvidé y ejecuté el comando sin una barra inclinada final. consejo: sigue los consejos de conny -.-
Znarkus
35
+1 al consejo de conny. Además, no intente crear '~ / dest /', ya que esto crea un directorio llamado '~' en su directorio de trabajo, en lugar de lo que realmente quería. Adivina qué sucede cuando
escribes
55
@KyleHeironimus: su advertencia sobre el uso de '~ / dest / `es verdadera si usa comillas alrededor de su ruta de prefijo que le dice al shell que no realice la expansión de tilde. Se creará un directorio llamado ~( '~'¡ no !) En su directorio de trabajo. No hay nada especial git checkout-indexal respecto: lo mismo es cierto mkdir '~/dest'( ¡no hagas eso! ). Otra buena razón para evitar los nombres de archivo que necesitan comillas (por ejemplo, que tienen un espacio en ellos) :-)
Matt Wallis
254

git archive También funciona con repositorio remoto.

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

Para exportar una ruta particular dentro del repositorio, agregue tantas rutas como desee como último argumento para git, por ejemplo:

git archive --format=tar \
--remote=ssh://remote_server/remote_repository master path1/ path2/ | tar -xv
Alexander Somov
fuente
66
Esta es la opción que más me gusta. Tiene el beneficio adicional de que también funciona en repositorios desnudos.
innaM
55
La versión mejorada es: git archive --format=tar --prefix=PROJECT_NAME/ --remote=USER@SERVER:PROJECT_NAME.git master | tar -xf - (asegura que su archivo esté en una carpeta)
Nick
77
Nota : el servidor debe habilitar esta función.
Jakub Narębski
12
Intenté: git archive --format=zip --output foo.zip --remote=https://github.com/xxx.git masterY me puse fatal: Operación no compatible con el protocolo. Fin inesperado de la secuencia de comandos.
andyf
77
@andyf GitHub tiene su propio camino: curl -L https://api.github.com/repos/VENDOR/PROJECT/tarball | tar xzf -por documentos
obispo
63

ingrese la descripción de la imagen aquí

Una respuesta de caso especial si el repositorio está alojado en GitHub.

Solo úsalo svn export.

Que yo sepa, Github no lo permite archive --remote. Aunque GitHub es compatible con svn y tienen todos los repositorios de git svnaccesibles, por lo que podría usarlo svn exportcomo lo haría normalmente con algunos ajustes en su URL de GitHub.

Por ejemplo, para exportar un repositorio completo, observe cómo trunken la URL reemplaza master(o lo que sea que se establezca la rama HEAD del proyecto ):

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

Y puede exportar un solo archivo o incluso una determinada ruta o carpeta:

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

Ejemplo con jQuery JavaScript Library

La HEADsucursal o la sucursal maestra estarán disponibles usando trunk:

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

Las no HEAD sucursales serán accesibles bajo /branches/:

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

Todas las etiquetas debajo /tags/de la misma manera:

svn ls https://github.com/jquery/jquery/tags/2.1.3
Anthony Hatzopoulos
fuente
1
git archivefunciona bien con GitHub, siempre que use el protocolo git, solo reemplace https://con git://en la URL. No sé por qué GitHub no anuncia esta característica oculta.
Neil Mayhew
1
@NeilMayhew No funciona para mí, entiendo fatal: The remote end hung up unexpectedly. Intenté en dos servidores diferentes con jQuery github repo.
Anthony Hatzopoulos el
1
Tienes razón. Había olvidado que estaba usando git config url.<base>.insteadOfpara almacenar en caché el repositorio remoto. Por lo tanto, estaba usando una file://URL en realidad. Dudo que git archivealguna vez pueda funcionar con las git://URL, ya que debe poder ejecutarse git-upload-archiveen el extremo remoto. Debería ser posible usar el sshprotocolo, excepto que github no lo permite ( Invalid command: 'git-upload-archive').
Neil Mayhew
¿Alguna forma de usar una herramienta de servidor local que se comporte como github si quiero hacerlo en repositorios git alojados internamente?
kriss
1
Votado: es completamente extraño que Git no tenga esta característica y tengamos que recurrir a svn
Jason S
40

Del manual de Git :

Usando git-checkout-index para "exportar un árbol completo"

La capacidad del prefijo básicamente hace que sea trivial usar git-checkout-index como una función "exportar como árbol". Simplemente lea el árbol deseado en el índice y haga:

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

jperras
fuente
19
Creo que la confusión es la frase "leer el árbol deseado en el índice".
davetron5000
44
Si desea exportar el directorio foo en la barra de sucursal, esto sería git read-tree bar:fooY luego, git checkout-index --prefix=export_dir/ -atal vez debería hacerlogit update-index master
Pascal Rosin
1
@JohnWeldon ¿Requiere que clones el repositorio primero? Si es así, entonces no lo aceptaría, ya que el objetivo de "svn export" de un subdirectorio es obtener directamente una copia de ese subdirectorio; si alguien tiene un repositorio Git de 1GB y todo lo que quiero es un subdirectorio de 10kB, es una locura requerir que clone todo.
Jason S
3
También haría eco a @ davetron5000 con el comentario "leer el árbol deseado en el índice", que no tengo idea de lo que significa.
Jason S
38

He escrito un contenedor simple git-checkout-indexque puedes usar así:

git export ~/the/destination/dir

Si el directorio de destino ya existe, deberá agregar -fo --force.

La instalación es simple; simplemente suelte el script en algún lugar de su PATH, y asegúrese de que sea ejecutable.

El repositorio de github para git-export

Daniel Schierbeck
fuente
15
Este contenedor no es independiente de la plataforma; se basa en / bin / sh. Entonces, si está en Windows, esta solución probablemente no funcione para usted.
shovavnik
18
Uhh, este script tiene 57 líneas de documentación, espacios en blanco, configuración, análisis de argumentos, y solo una línea que realmente hace algo ...
Vladimir Panteleev
36

Parece que este es un problema menor con Git que SVN. Git solo coloca una carpeta .git en la raíz del repositorio, mientras que SVN coloca una carpeta .svn en cada subdirectorio. Entonces, "svn export" evita la magia recursiva de la línea de comandos, mientras que con Git la recursión no es necesaria.

kostmo
fuente
26
A partir de SVN 1.7, también hay una sola carpeta .svn: subversion.apache.org/docs/release-notes/1.7.html#single-db
kostmo
Esto no eliminará los archivos de compilación adicionales que svn export elimina. Entonces esta definitivamente no es la respuesta.
ygoe
28

El equivalente de

svn export . otherpath

dentro de un repositorio existente es

git archive branchname | (cd otherpath; tar x)

El equivalente de

svn export url otherpath

es

git archive --remote=url branchname | (cd otherpath; tar x)
aredridel
fuente
1
gracias, esto era lo que me faltaba ... también, para verificar las marcas de tiempo de la exportación (no se conservarán como en los archivos), use git archive --format=tar --prefix=junk/ HEAD | (tar -t -v --full-time -f -)... Sin embargo, el archivo con marcas de tiempo no es exactamente trivial, así que publiqué un ejemplo a continuación .
sdaau
1
Puede usar la opción C para el alquitrán en lugar de la subshell, así: git archive branchname | tar xC otherpath
James Moore
Tenga en cuenta que la Copción de alquitrán es solo GNU Tar.
aredridel
22

Si no está excluyendo archivos con .gitattributes export-ignore, intentegit checkout

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

-f
Al retirar rutas del índice, no falle en las entradas no fusionadas; en cambio, las entradas no fusionadas se ignoran.

y

-q
Evita verbosa

Además, puede obtener cualquier rama o etiqueta o de una revisión de confirmación específica como en SVN simplemente agregando el SHA1 (SHA1 en Git es el equivalente al número de revisión en SVN)

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

El /path/to/checkout/debe estar vacío, Git no borrará cualquier archivo, pero se sobreponen a los archivos con el mismo nombre sin ninguna advertencia

ACTUALIZACIÓN: para evitar el problema de decapitación o dejar intacto el repositorio de trabajo cuando se utiliza el proceso de pago para la exportación con etiquetas, ramas o SHA1, debe agregar -- ./al final

El guión doble --le dice a git que todo después de los guiones son rutas o archivos, y también en este caso le indica git checkoutque no cambie elHEAD

Ejemplos:

Este comando obtendrá solo el directorio libs y también el readme.txtarchivo de esa confirmación exacta

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

Esto creará (sobrescribirá) my_file_2_behind_HEAD.txtdos confirmaciones detrás de la cabezaHEAD^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 obtener la exportación de otra sucursal

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

Observe que ./es relativo a la raíz del repositorio

usuario5286776117878
fuente
En realidad, entre muchos otros y votos a favor, esto funcionó mejor para mí, sin compresiones, funcionando bien con repositorios desnudos (gitolita).
tomas
1
Tenga en cuenta que el pago de SHA1 creará un problema de "decapitación" en el repositorio
usuario5286776117878
actualmente @ITGabs, esto no descarga la carpeta ".git". Entonces, la carpeta descargada no es un repositorio git, por lo que técnicamente no está "decapitada"
Fabio Marreco
@FabioMarreco El problema de la decapitación está en el repositorio, no en los archivos exportados / descargados, estoy actualizando la respuesta para obtener más detalles
usuario5286776117878
3
Esto funciono muy bien para mi. Pero al principio recibí mensajes de error "No es un repositorio git". Luego descubrí que "/ path / to / repo /" tenía que apuntar a la carpeta .git. Así que esto funcionó: --git-dir = / path / to / repo / .git
philburk
21

Yo uso git-submodules ampliamente. Esta funciona para mí:

rsync -a ./FROM/ ./TO --exclude='.*'
slatvick
fuente
1
¿No faltarían archivos cuyos nombres comienzan con un punto, como .htaccess?
Greg Hewgill
8
Una buena solución, cambiaría --exclude = '. *' A --exclude = '.
Git
18
--exclude-vcs si ibas a tomar este tacto
plod
¿Puede ./FROM/ ser un repositorio remoto?
Diseño resistente el
2
Como FYI, mi copia de rsyncenumera el argumento como --cvs-exclude. Además, todavía se copia .gitattributesy.gitignore
Ryan Ransford
19

Llegué a esta página con frecuencia cuando buscaba una forma de exportar un repositorio git. Mi respuesta a esta pregunta considera tres propiedades que tiene svn export por diseño en comparación con git, ya que svn sigue un enfoque de repositorio centralizado:

  • Minimiza el tráfico a una ubicación de repositorio remoto al no exportar todas las revisiones
  • No incluye metainformación en el directorio de exportación
  • La exportación de una determinada rama utilizando svn se realiza especificando la ruta adecuada

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

Al construir una determinada versión, es útil clonar una rama estable como, por ejemplo, --branch stableo --branch release/0.9.

Lars Schillingmann
fuente
Esto no funciona si el destino existe y no está vacío.
Epónimo
2
La única respuesta verdadera: surge de las profundidades. El git archive | tarenfoque no es aplicable a entornos shell incompatibles con POSIX (por ejemplo, CI basado en CMD o PowerShell de AppVeyor), lo que no es ideal. El git checkoutenfoque modifica el índice del árbol de trabajo principal, lo cual es horrible. El git checkout-indexenfoque requiere que el índice del árbol de trabajo principal se modifique de antemano, lo que es aún peor. El git cloneenfoque tradicional clona la totalidad del historial del repositorio antes de eliminar ese historial, lo cual es un desperdicio. Esta es la única solución sana que queda.
Cecil Curry
1
Para exportar localmente, tenga en cuenta que la ruta absoluta del árbol de trabajo Git del que se va a clonar debe ir precedida del file://protocolo (por ejemplo, git clone --depth 1 --branch v3.14.15 file:///home/me/src_repo trg_repo). De lo "warning: --depth is ignored in local clones; use file:// instead."contrario , emitirá y realizará un clon estándar en lugar de un clon superficial, lo que anulará el propósito de esta respuesta. Salud!
Cecil Curry
16

Esto copiará todo el contenido, menos los archivos .dot. Lo uso para exportar proyectos clonados con git al repositorio de git de mi aplicación web sin el material .git.

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

Bash viejo bash funciona simplemente genial :)

Harmon
fuente
¿Por qué no simplemente presionar al control remoto? Incluso más simple que bash.
nurettin
2
¿Qué pasa con los archivos que forman parte de las aplicaciones web y su nombre comienza con punto? :) piensa en .htaccess
Artur
3
A veces también quieres ignorar lo que hay dentro .gitignore, esto no lo hará.
fregante
14

Tan simple como clonar, luego elimine la carpeta .git:

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

teleme.io
fuente
44
Honestamente, esta respuesta, que también es la número 1 en la pregunta, es lo que vas a hacer el 99% del tiempo. La mayoría de estas respuestas son locamente complicadas.
Geoff Nixon
11

Para los usuarios de GitHub, el git archive --remotemétodo no funcionará directamente, ya que la URL de exportación es efímera . Debes pedirle a GitHub la URL, luego descargar esa URL. curllo hace fácil:

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

Esto le dará el código exportado en un directorio local. Ejemplo:

$ 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
Si desea que el código se coloque en un directorio específico existente (en lugar del aleatorio de github):

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

Sí, este es un comando limpio y ordenado para archivar su código sin ninguna inclusión de git en el archivo y es bueno pasarlo sin preocuparse por ningún historial de confirmación de git.

git archive --format zip --output /full/path/to/zipfile.zip master 
zeeawan
fuente
Esto es genial, solo necesita eliminar gitignore después y ya está hecho y listo para compartir.
Sogger
La eliminación de .gitgnore, etc., se menciona en los comentarios de respuesta aceptados: use el archivo .gitattributes, consulte feeding.cloud.geek.nz/posts/excluding-files-from-git-archive
Sogger
10

Solo quiero señalar que en el caso de que seas

  1. exportar una subcarpeta del repositorio (así solía usar la función de exportación SVN)
  2. están de acuerdo con copiar todo desde esa carpeta al destino de implementación
  3. y dado que ya tiene una copia de todo el repositorio en su lugar.

Luego puede usar en cp foo [destination]lugar de lo mencionado git-archive master foo | -x -C [destination].

dkinzer
fuente
9

Puede archivar un repositorio remoto en cualquier confirmación como archivo zip.

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

Bash-implementación de git-export.

He segmentado los procesos de creación y eliminación de archivos .empty en su propia función, con el propósito de reutilizarlos en la implementación 'git-archive' (se publicará más adelante).

También he agregado el archivo '.gitattributes' al proceso para eliminar los archivos no deseados de la carpeta de exportación de destino. Incluye verbosidad al proceso al tiempo que hace que la función 'git-export' sea más eficiente.

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

Salida:

$ git-export /tmp/rel-1.0.0

Agregar archivos '.empty' a carpetas vacías: ... hecho.

Componentes del índice de desprotección: ... hecho.

Restableciendo HEAD e Índice: ... hecho.

Purga de componentes específicos de Git: ...

'/tmp/rel-1.0.0/{.buildpath}' archivos ... hecho '.

'/tmp/rel-1.0.0/{.project}' archivos ... hecho '.

'/tmp/rel-1.0.0/{.gitignore}' archivos ... hecho '.

'/tmp/rel-1.0.0/{.git}' archivos ... hecho '.

'/tmp/rel-1.0.0/{.gitattributes}' archivos ... hecho '.

'/tmp/rel-1.0.0/{*.mno}' archivos ... hecho '.

'/tmp/rel-1.0.0/{*~}' archivos ... hecho '.

'/tmp/rel-1.0.0/{.*~}' archivos ... hecho '.

'/tmp/rel-1.0.0/{*.swp}' archivos ... hecho '.

'/tmp/rel-1.0.0/{*.swo}' archivos ... hecho '.

'/tmp/rel-1.0.0/{.DS_Store}' archivos ... hecho '.

'/tmp/rel-1.0.0/{.settings}' archivos ... hecho '.

'/tmp/rel-1.0.0/{.empty}' archivos ... hecho '.

hecho.

Archivado de componentes desprotegidos: ... hecho.

-rw-r - r-- 1 rueda de administración 25445901 3 de noviembre 12:57 /tmp/rel-1.0.0.tgz

Ahora he incorporado la funcionalidad 'git archive' en un solo proceso que hace uso de la función 'create_empty' y otras características.

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

Si quieres algo que funcione con submódulos, vale la pena intentarlo.

Nota:

  • MASTER_DIR = un pago con sus submódulos desprotegidos también
  • DEST_DIR = donde terminará esta exportación
  • Si tiene rsync, creo que podría hacer lo mismo con incluso menos dolor de bola.

Suposiciones

  • Debe ejecutar esto desde el directorio principal de MASTER_DIR (es decir, desde MASTER_DIR cd ..)
  • Se supone que DEST_DIR se ha creado. Esto es bastante fácil de modificar para incluir la creación de un DEST_DIR si desea

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
fuente
6

Mi preferencia en realidad sería tener un destino dist en su Makefile (u otro sistema de compilación) que exporte un archivo distribuible de su código (.tar.bz2, .zip, .jar o lo que sea apropiado). Si está utilizando las herramientas automáticas GNU o los sistemas MakeMaker de Perl, creo que esto existe para usted automáticamente. Si no, recomiendo agregarlo.

ETA (2012-09-06): Vaya, votos negativos duros. Todavía creo que es mejor construir sus distribuciones con sus herramientas de construcción en lugar de su herramienta de control de código fuente. Creo en la construcción de artefactos con herramientas de construcción. En mi trabajo actual, nuestro producto principal está construido con un objetivo de hormigas. Estamos en medio de cambiar los sistemas de control de código fuente, y la presencia de este objetivo de hormigas significa una molestia menos en la migración.

skiphoppy
fuente
El proyecto que tenía en mente no es un proyecto de código; resulta ser más similar a un proyecto de sitio web.
Greg Hewgill
No aborda la pregunta.
Andrew Ferrier
1
Sí, tal respuesta puede no satisfacer las necesidades de todos, pero los votos negativos son extraños. Que es una respuesta totalmente válida, y de hecho, en muchos casos, la respuesta sólo es correcto. Es muy válido señalar que pensar en este problema como un "problema de herramienta vc" a menudo va por el camino equivocado por completo.
snogglethorpe
6

Esto copiará los archivos en un rango de confirmaciones (C a G) en un archivo tar. Nota: esto solo confirmará los archivos. No todo el repositorio. Ligeramente modificado desde aquí

Ejemplo de historial de confirmación

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 del manual de git-diff-tree

-r -> recurse en subárboles

--no-commit-id -> git diff-tree genera una línea con el ID de confirmación cuando corresponde. Esta bandera suprimió la salida de ID de confirmación.

--name-only -> Muestra solo los nombres de los archivos modificados.

--diff-filter = ACMRT -> Seleccione solo estos archivos. Vea aquí la lista completa de archivos

C..G -> Archivos en este rango de confirmaciones

C ~ -> Incluir archivos de Commit C. No solo archivos desde Commit C.

El | xargs tar -rf myTarFile -> salidas a tar

Caqui Fuyu
fuente
5

Según entiendo la pregunta, se trata más de descargar solo cierto estado del servidor, sin historial y sin datos de otras ramas, en lugar de extraer un estado de un repositorio local (como lo hacen muchas respuestas aquí).

Eso se puede hacer así:

git clone -b someBranch --depth 1 --single-branch git://somewhere.com/repo.git \
&& rm -rf repo/.git/
  • --single-branch está disponible desde Git 1.7.10 (abril de 2012).
  • --depthes (¿fue?) supuestamente defectuoso, pero para el caso de una exportación, los problemas mencionados no deberían importar.
Ondra Žižka
fuente
Nota: Acabo de notar que hay 2 páginas de respuestas, solo miré una antes de publicar. Hay una respuesta similar con solo --depth, lo que implica a --single-branchmenos que --no-single-branchse dé, lo que significa que probablemente tenga el mismo efecto. Sin embargo, no estoy seguro, ¿algún experto puede confirmarlo?
Ondra Žižka
4

Necesitaba esto para un script de implementación y no podía usar ninguno de los enfoques mencionados anteriormente. En cambio, descubrí una solución 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
fuente
¿Cuál fue el problema con un árbol de lectura / índice de pago o una solución de archivo? Por lo que puedo decir, has hecho el equivalente de algo así mkdir -p "$2" && git --git-dir="$1" archive HEAD | tar -x -C "$2"pero algo más largo sin aliento.
CB Bailey
1
No pude hacer que el árbol de lectura funcione desde un repositorio remoto, y la solución de archivo no funciona con github.
troelskn
Sí, con el archivo obtener un comando no válido: 'git-upload-archive' ... error y no tengo la opción de configuración core.gitProxy y el conjunto de variables de entorno
GIT_PROXY_COMMAND
4

Haciéndolo de manera fácil, esta es una función para .bash_profile, descomprime directamente el archivo en la ubicación actual, configura primero tu [url: ruta] habitual. NOTA: Con esta función evita la operación de clonación, se obtiene directamente del repositorio 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, se requiere la misma configuración (TENGA CUIDADO al ejecutar el comando dentro de los proyectos .git, SIEMPRE salta al directorio base anteriormente como se dijo aquí , hasta que esto se arregle, personalmente prefiero la función

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
fuente
4

Con mucho, la forma más fácil que he visto de hacerlo (y también funciona en Windows) es git bundle:

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

Consulte esta respuesta para obtener más detalles: ¿Cómo puedo copiar mi repositorio git de mi máquina Windows a una máquina Linux a través de una unidad USB?

BT
fuente
git bundleincluye la .gitcarpeta, que es lo que el OP no quiere; git archiveparece la forma más apropiada
ssc
¿Dónde está la documentación en el --allswitch?
Garret Wilson el
4

Tengo otra solución que funciona bien si tiene una copia local del repositorio en la máquina donde desea crear la exportación. En este caso, muévase a este directorio de repositorio e ingrese este comando:

GIT_WORK_TREE=outputdirectory git checkout -f

Esto es particularmente útil si administra un sitio web con un repositorio de git y desea obtener una versión limpia /var/www/. En este caso, agregue este comando en un .git/hooks/post-receivescript ( hooks/post-receiveen un repositorio simple , que es más adecuado en esta situación)

Tom
fuente
3

Creo que la publicación de @Aredridel fue la más cercana, pero hay un poco más de eso, así que agregaré esto aquí; la cosa es, en svn, si estás en una subcarpeta de un repositorio, y haces:

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

luego svnexportará todos los archivos que están bajo control de revisión (también podrían haber agregado recientemente; o estado modificado), y si tiene otra "basura" en ese directorio (y no estoy contando .svnsubcarpetas aquí, sino cosas visibles como .oarchivos) , no se exportará; solo se exportarán los archivos registrados por el repositorio SVN. Para mí, algo bueno es que esta exportación también incluye archivos con cambios locales que aún no se han confirmado; y otra cosa buena es que las marcas de tiempo de los archivos exportados son las mismas que las originales. O, como svn help exportdice:

  1. Exporta un árbol de directorio limpio de la copia de trabajo especificada por PATH1, en la revisión REV si se proporciona, de lo contrario en WORKING, a PATH2. ... Si no se especifica REV, se conservarán todos los cambios locales. Los archivos que no estén bajo el control de versión no se copiarán.

Para darse cuenta de que gitno conservará las marcas de tiempo, compare la salida de estos comandos (en una subcarpeta de un gitrepositorio de su elección):

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

... y:

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

... y, en cualquier caso, ¡me doy cuenta de que git archivetodas las marcas de tiempo del archivo archivado son las mismas! git help archivedice:

git archive se comporta de manera diferente cuando se le da una ID de árbol en comparación con una ID de confirmación o ID de etiqueta. En el primer caso, la hora actual se usa como la hora de modificación de cada archivo en el archivo. En este último caso, se utiliza el tiempo de confirmación registrado en el objeto de confirmación referenciado.

... pero aparentemente ambos casos establecen el "tiempo de modificación de cada archivo"; por lo tanto no conserva las marcas de tiempo reales de esos archivos!

Entonces, para preservar también las marcas de tiempo, aquí hay una bashsecuencia de comandos, que en realidad es una "línea única", aunque algo complicada, por lo que a continuación se publica en varias líneas:

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

Tenga en cuenta que se supone que está exportando el contenido en el directorio "actual" (arriba /media/disk/git_svn/subdir), y que el destino al que está exportando está ubicado de manera algo inconveniente, pero está en DESTuna variable de entorno. Tenga en cuenta que con este script; debes crear elDEST directorio manualmente usted mismo, antes de ejecutar el script anterior.

Después de ejecutar el script, debería poder comparar:

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

... y espero ver las mismas marcas de tiempo (para aquellos archivos que estaban bajo control de versiones).

Espero que esto ayude a alguien,
¡salud!

sdaau
fuente
3

una exportación de git a un archivo zip al agregar un prefijo (por ejemplo, nombre de directorio):

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

Tengo la siguiente función de utilidad en mi archivo .bashrc: crea un archivo de la rama actual en un repositorio 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
fuente