deployment tag - Implementar un proyecto usando Git push




crear tipos (17)

Parece que deberías tener dos copias en tu servidor. Una copia simple, desde la cual puede empujar / extraer, la cual empujaría sus cambios cuando termine, y luego clonaría esto en su directorio web y configuraría un cronjob para actualizar git pull desde su directorio web todos los días o asi que.

¿Es posible desplegar un sitio web utilizando git push ? Tengo la corazonada de que tiene algo que ver con el uso de ganchos de git para realizar un git reset --hard en el lado del servidor, pero ¿cómo podría lograrlo?


Usando el siguiente archivo de actualización :

  1. Copie su directorio .git a su servidor web
  2. En su copia local, modifique su archivo .git / config y agregue su servidor web como un control remoto:

    [remote "production"]
        url = [email protected]:/path/to/htdocs/.git
    
  3. En el servidor, reemplace .git / hooks / post-update con el archivo a continuación

  4. Agregue acceso de ejecución al archivo (nuevamente, en el servidor):

    chmod +x .git/hooks/post-update
    
  5. Ahora, solo presione localmente a su servidor web y debería actualizar automáticamente la copia de trabajo:

    git push production
    
#!/bin/sh
#
# This hook does two things:
#
#  1. update the "info" files that allow the list of references to be
#     queries over dumb transports such as http
#
#  2. if this repository looks like it is a non-bare repository, and
#     the checked-out branch is pushed to, then update the working copy.
#     This makes "push" function somewhat similarly to darcs and bzr.
#
# To enable this hook, make this file executable by "chmod +x post-update". 
git-update-server-info 
is_bare=$(git-config --get --bool core.bare) 
if [ -z "$is_bare" ]
then
      # for compatibility's sake, guess
      git_dir_full=$(cd $GIT_DIR; pwd)
      case $git_dir_full in */.git) is_bare=false;; *) is_bare=true;; esac
fi 
update_wc() {
      ref=$1
      echo "Push to checked out branch $ref" >&2
      if [ ! -f $GIT_DIR/logs/HEAD ]
      then
             echo "E:push to non-bare repository requires a HEAD reflog" >&2
             exit 1
      fi
      if (cd $GIT_WORK_TREE; git-diff-files -q --exit-code >/dev/null)
      then
             wc_dirty=0
      else
             echo "W:unstaged changes found in working copy" >&2
             wc_dirty=1
             desc="working copy"
      fi
      if git diff-index --cached [email protected]{1} >/dev/null
      then
             index_dirty=0
      else
             echo "W:uncommitted, staged changes found" >&2
             index_dirty=1
             if [ -n "$desc" ]
             then
                   desc="$desc and index"
             else
                   desc="index"
             fi
      fi
      if [ "$wc_dirty" -ne 0 -o "$index_dirty" -ne 0 ]
      then
             new=$(git rev-parse HEAD)
             echo "W:stashing dirty $desc - see git-stash(1)" >&2
             ( trap 'echo trapped $$; git symbolic-ref HEAD "'"$ref"'"' 2 3 13 15 ERR EXIT
             git-update-ref --no-deref HEAD [email protected]{1}
             cd $GIT_WORK_TREE
             git stash save "dirty $desc before update to $new";
             git-symbolic-ref HEAD "$ref"
             )
      fi 
      # eye candy - show the WC updates :)
      echo "Updating working copy" >&2
      (cd $GIT_WORK_TREE
      git-diff-index -R --name-status HEAD >&2
      git-reset --hard HEAD)
} 
if [ "$is_bare" = "false" ]
then
      active_branch=`git-symbolic-ref HEAD`
      export GIT_DIR=$(cd $GIT_DIR; pwd)
      GIT_WORK_TREE=${GIT_WORK_TREE-..}
      for ref
      do
             if [ "$ref" = "$active_branch" ]
             then
                   update_wc $ref
             fi
      done
fi

Como respuesta complementaria me gustaría ofrecer una alternativa. Estoy usando git-ftp y funciona bien.

https://github.com/git-ftp/git-ftp

Fácil de usar, solo escribe:

git ftp push

y git cargará automáticamente los archivos del proyecto.

Saludos


El updateInstead agregado en Git 2.3 de receive.denyCurrentBranch es una posibilidad.

Establézcalo en el repositorio del servidor, y también actualiza el árbol de trabajo si está limpio.

Ha habido mejoras adicionales en 2.4 con el gancho de push-to-checkout y el manejo de las ramas por nacer .

Uso de la muestra:

git init server
cd server
touch a
git add .
git commit -m 0
git config --local receive.denyCurrentBranch updateInstead

cd ..
git clone server local
cd local
touch b
git add .
git commit -m 1
git push origin master:master

cd ../server
ls

Salida:

a
b

Esto tiene las siguientes deficiencias mencionadas en el anuncio de GitHub :

  • Su servidor contendrá un directorio .git que contiene el historial completo de su proyecto. ¡Probablemente desee asegurarse de que no se pueda servir a los usuarios!
  • Durante las implementaciones, será posible que los usuarios encuentren momentáneamente el sitio en un estado inconsistente, con algunos archivos en la versión anterior y otros en la nueva versión, o incluso archivos a medio escribir. Si este es un problema para su proyecto, es probable que el impulso de implementación no sea para usted.
  • Si su proyecto necesita un paso de "construcción", entonces tendrá que configurarlo explícitamente, tal vez a través de githooks.

Pero todos esos puntos están fuera del alcance de Git y deben ser atendidos por un código externo. Entonces, en ese sentido, esto, junto con los ganchos Git, son la solución definitiva.


Yo uso dos soluciones para el gancho posterior a la recepción:

SOLUCIÓN DE DESPLIEGUE 1

#!/bin/bash 
#  /git-repo/hooks/post-receive - file content on server (chmod as 755 to be executed)
# DEPLOY SOLUTION 1 

    export GIT_DIR=/git/repo-bare.git
    export GIT_BRANCH1=master
    export GIT_TARGET1=/var/www/html
    export GIT_BRANCH2=dev
    export GIT_TARGET2=/var/www/dev
    echo "GIT DIR:  $GIT_DIR/"
    echo "GIT TARGET1:  $GIT_TARGET1/"
    echo "GIT BRANCH1:  $GIT_BRANCH1/"
    echo "GIT TARGET2:  $GIT_TARGET2/"
    echo "GIT BRANCH2:  $GIT_BRANCH2/"
    echo ""

    cd $GIT_DIR/

while read oldrev newrev refname
do
    branch=$(git rev-parse --abbrev-ref $refname)
    BRANCH_REGEX='^${GIT_BRANCH1}.*$'
    if [[ $branch =~ $BRANCH_REGEX ]] ; then
        export GIT_WORK_TREE=$GIT_TARGET1/.
        echo "Checking out branch: $branch";
        echo "Checking out to workdir: $GIT_WORK_TREE"; 

        git checkout -f $branch
    fi

    BRANCH_REGEX='^${GIT_BRANCH2}.*$'
    if [[ $branch =~ $BRANCH_REGEX ]] ; then
        export GIT_WORK_TREE=$GIT_TARGET2/.
        echo "Checking out branch: $branch";
        echo "Checking out to workdir: $GIT_WORK_TREE"; 

        git checkout -f $branch
    fi
done

DESPLEGAR SOLUCIÓN 2

#!/bin/bash 
#  /git-repo/hooks/post-receive - file content on server (chmod as 755 to be executed)
# DEPLOY SOLUTION 2

    export GIT_DIR=/git/repo-bare.git
    export GIT_BRANCH1=master
    export GIT_TARGET1=/var/www/html
    export GIT_BRANCH2=dev
    export GIT_TARGET2=/var/www/dev
    export GIT_TEMP_DIR1=/tmp/deploy1
    export GIT_TEMP_DIR2=/tmp/deploy2
    echo "GIT DIR:  $GIT_DIR/"
    echo "GIT TARGET1:  $GIT_TARGET1/"
    echo "GIT BRANCH1:  $GIT_BRANCH1/"
    echo "GIT TARGET2:  $GIT_TARGET2/"
    echo "GIT BRANCH2:  $GIT_BRANCH2/"
    echo "GIT TEMP DIR1:  $GIT_TEMP_DIR1/"
    echo "GIT TEMP DIR2:  $GIT_TEMP_DIR2/"
    echo ""

    cd $GIT_DIR/

while read oldrev newrev refname
do
    branch=$(git rev-parse --abbrev-ref $refname)
    BRANCH_REGEX='^${GIT_BRANCH1}.*$'
    if [[ $branch =~ $BRANCH_REGEX ]] ; then
        export GIT_WORK_TREE=$GIT_TARGET1/.
        echo "Checking out branch: $branch";
        echo "Checking out to workdir: $GIT_WORK_TREE"; 

        # DEPLOY SOLUTION 2: 
        cd $GIT_DIR/; mkdir -p $GIT_TEMP_DIR1; 
        export GIT_WORK_TREE=$GIT_TEMP_DIR1/.
        git checkout -f $branch
        export GIT_WORK_TREE=$GIT_TARGET1/.
        rsync $GIT_TEMP_DIR1/. -v -q --delete --delete-after -av $GIT_TARGET1/.
        rm -rf $GIT_TEMP_DIR1
    fi

    BRANCH_REGEX='^${GIT_BRANCH2}.*$'
    if [[ $branch =~ $BRANCH_REGEX ]] ; then
        export GIT_WORK_TREE=$GIT_TARGET2/.
        echo "Checking out branch: $branch";
        echo "Checking out to workdir: $GIT_WORK_TREE"; 

        # DEPLOY SOLUTION 2: 
        cd $GIT_DIR/; mkdir -p $GIT_TEMP_DIR2; 
        export GIT_WORK_TREE=$GIT_TEMP_DIR2/.
        git checkout -f $branch
        export GIT_WORK_TREE=$GIT_TARGET2/.
        rsync $GIT_TEMP_DIR2/. -v -q --delete --delete-after -av $GIT_TARGET2/.
        rm -rf $GIT_TEMP_DIR2
    fi
done

Ambas soluciones se basan en soluciones anteriores disponibles en este hilo.

Tenga en cuenta que BRANCH_REGEX = '^ $ {GIT_BRANCH1}. $ 'filtra los nombres de las sucursales que coinciden con la cadena "master " o "dev *", e implementa el árbol de trabajo, si la rama empujada coincide. Esto hace posible desplegar una versión dev y una versión maestra en diferentes lugares.

DEPLOY SOLUTION 1 elimina solo los archivos, que son parte del repositorio, y fue eliminado por una confirmación. Es más rápido que la solución de implementación 2.

DEPLOY SOLUTION 2 tiene la ventaja de que eliminará cualquier archivo nuevo del directorio de producción, que se agregó en el lado del servidor, sin importar si se agregó al repositorio o no. Siempre estará limpio dupe del repo. Es más lento que la solución de implementación 1.


Mi toma en Christians solución de los Christians .

git archive --prefix=deploy/  master | tar -x -C $TMPDIR | rsync $TMPDIR/deploy/ --copy-links -av [email protected]:/home/user/my_app && rm -rf $TMPDIR/deploy
  • Archiva la rama maestra en alquitrán.
  • Extrae el archivo tar en el directorio de implementación en la carpeta temporal del sistema.
  • rsync cambia al servidor
  • eliminar despliegue dir de la carpeta temporal.

Para el escenario de implementación

En nuestro escenario, almacenamos el código en github / bitbucket y queremos implementarlo en servidores en vivo. En este caso, la siguiente combinación funciona para nosotros (es un remix de las respuestas altamente actualizadas aquí) :

  1. Copie su directorio .git a su servidor web
  2. En su copia local git remote add live ssh://[email protected]:port/folder
  3. En el control remoto: git config receive.denyCurrentBranch ignore
  4. En el control remoto: nano .git/hooks/post-receive y agregue este contenido:

    #!/bin/sh GIT_WORK_TREE=/var/www/vhosts/example.org git checkout -f

  5. En el control remoto: chmod +x .git/hooks/post-receive

  6. Ahora puedes empujar allí con git push live

Notas

  • Esta solución funciona con versiones anteriores de git (probadas con 1.7 y 1.9)
  • Debes asegurarte de empujar a github / bitbucket primero, para que tengas un repo consistente en vivo
  • Si su carpeta .git está dentro de la raíz del documento, asegúrese de ocultarla del exterior agregando a .htaccess ( source ):

    RedirectMatch 404 /\..*$


En esencia, todo lo que necesitas hacer es lo siguiente:

server = $1
branch = $2
git push $server $branch
ssh <username>@$server "cd /path/to/www; git pull"

Tengo esas líneas en mi aplicación como un ejecutable llamado deploy .

así que cuando quiero hacer una implementación ./deploy myserver mybranch .


Después de muchos inicios y fallos, finalmente puedo implementar el código del sitio web con solo "git push remote " gracias a este artículo .

La secuencia de comandos posterior a la actualización del autor solo tiene una línea y su solución no requiere la configuración de .htaccess para ocultar el repositorio de Git como hacen otros.

Un par de obstáculos si está implementando esto en una instancia de Amazon EC2;

1) Si usa sudo para crear el repositorio de destino, debe cambiar el propietario del repositorio a ec2-user o el impulso fallará. (Pruebe "chown ec2-user: ec2-user repo ").

2) La inserción fallará si no configura previamente la ubicación de su clave privada-amazon .pem, ya sea en / etc / ssh / ssh_config como un parámetro IdentityFile o en ~ / .ssh / config utilizando "[ Host] - HostName - IdentityFile - Usuario "diseño descrito here ...

... SIN EMBARGO, si el Host está configurado en ~ / .ssh / config y es diferente de HostName, la inserción de Git fallará. (Eso es probablemente un error de Git)


Encontré este script en este sitio y parece funcionar bastante bien.

  1. Copie su directorio .git a su servidor web
  2. En su copia local, modifique su archivo .git / config y agregue su servidor web como un control remoto:

    [remote "production"]
        url = [email protected]:/path/to/htdocs/.git
    
  3. En el servidor, reemplace .git / hooks / post-update con este archivo (en la respuesta a continuación)

  4. Agregue acceso de ejecución al archivo (nuevamente, en el servidor):

    chmod +x .git/hooks/post-update
    
  5. Ahora, solo presione localmente a su servidor web y debería actualizar automáticamente la copia de trabajo:

    git push production
    

La forma en que lo hago es que tengo un repositorio de Git en mi servidor de implementación donde presiona los cambios. Luego inicio sesión en el servidor de implementación, cambio al directorio docs del servidor web real y hago un git pull. No utilizo ningún gancho para intentar hacer esto automáticamente, eso parece más problema de lo que vale.


Terminé creando mi propia herramienta de implementación rudimentaria que automáticamente eliminaría nuevas actualizaciones del repositorio - https://github.com/jesalg/SlimJim - Básicamente escucha el github post-receive-hook y usa un proxy para activar un script de actualización.


Giddyup es un Giddyup git de solo agregar agua de lenguaje agnóstico para automatizar la implementación a través de git push. También le permite tener ganchos de inicio / parada personalizados para reiniciar el servidor web, calentar el caché, etc.

Giddyup

Echa un vistazo a examples .


Estoy usando la siguiente solución de toroid.org , que tiene un script de enganche más simple.

en el servidor:

$ mkdir website.git && cd website.git
$ git init --bare
Initialized empty Git repository in /home/ams/website.git/

e instale el gancho en el servidor:

$ mkdir /var/www/www.example.org
$ cat > hooks/post-receive
#!/bin/sh
GIT_WORK_TREE=/var/www/www.example.org git checkout -f
GIT_WORK_TREE=/var/www/www git clean -f -d # clean directory from removed files

$ chmod +x hooks/post-receive

en su cliente:

$ mkdir website && cd website
$ git init
Initialized empty Git repository in /home/ams/website/.git/
$ echo 'Hello, world!' > index.html
$ git add index.html
$ git commit -q -m "The humble beginnings of my web site."

$ git remote add web ssh://server.example.org/home/ams/website.git
$ git push web +master:refs/heads/master

luego para publicar, solo teclea

$ git push web

Hay una descripción completa en el sitio web: http://toroid.org/ams/git-website-howto


Actualización: ahora estoy usando la solución Lloyd Moore con el agente clave ssh -A ... Empujar a un repositorio principal y luego tirar de él en paralelo desde todas sus máquinas es un poco más rápido y requiere menos configuración en esas máquinas.

No veo esta solución aquí. solo presione ssh si git está instalado en el servidor.

Necesitará la siguiente entrada en su .git / config local

[remote "amazon"]
    url = amazon:/path/to/project.git
    fetch = +refs/heads/*:refs/remotes/amazon/*

Pero oye, ¿qué es eso con amazon: :? En tu ~ / .ssh / config local deberás agregar la siguiente entrada:

Host amazon
    Hostname <YOUR_IP>
    User <USER>
    IdentityFile ~/.ssh/amazon-private-key

ahora puedes llamar

git push amazon master
ssh <USER>@<YOUR_IP> 'cd /path/to/project && git pull'

(Por cierto: /path/to/project.git es diferente al directorio de trabajo real / ruta / a / proyecto)


no instale git en un servidor o copie la carpeta .git allí. para actualizar un servidor desde un clon git puede usar el siguiente comando:

git ls-files -z | rsync --files-from - --copy-links -av0 . [email protected]:/var/www/project

es posible que tenga que eliminar los archivos que se eliminaron del proyecto.

esto copia todos los archivos registrados. rsync usa ssh que está instalado en un servidor de todos modos.

Cuanto menos software haya instalado en un servidor, más seguro estará y más fácil será gestionar su configuración y documentarlo. tampoco es necesario mantener un clon completo de git en el servidor. sólo lo hace más complejo para asegurar todo correctamente.


Primero, creas tu rama localmente:

git checkout -b <branch-name> # Create a new branch and check it out

La rama remota se crea automáticamente cuando la empuja al servidor remoto. Así que cuando te sientas listo para ello, simplemente puedes hacer:

git push <remote-name> <branch-name> 

Donde <remote-name> suele ser el origin , el nombre que git le da al remoto desde el que se clonó. Tus colegas solo tirarían de esa rama y se crearía automáticamente de forma local.

Tenga en cuenta sin embargo que formalmente, el formato es:

git push <remote-name> <local-branch-name>:<remote-branch-name>

Pero cuando omites uno, se asume que ambos nombres de rama son iguales. Dicho esto, como advertencia , no cometa el error crítico de especificar solo :<remote-branch-name> (con los dos puntos), ¡o la rama remota se eliminará!

Para que un git pull posterior de git pull sepa qué hacer, es posible que desee utilizar:

git push --set-upstream <remote-name> <local-branch-name> 

Como se describe a continuación, la opción --set-upstream configura una rama upstream:

Para cada rama que esté actualizada o que se haya enviado con éxito, agregue la referencia en sentido ascendente (seguimiento), utilizada por git-pull (1) sin argumentos y otros comandos.





git deployment webserver githooks