2010-10-01 15 views
59

Estoy tratando de configurar Git para organizar mi sitio web para que pueda git pull para trabajar en la versión actual y luego git push para enviar los cambios al servidor remoto. Lo tengo configurado para que funcione como yo quiero, pero después de presionar, tengo que ejecutar manualmente git checkout -f o git reset --hard HEAD en el servidor remoto.Git Post-Receive Hook para puesta en escena del sitio web

He intentado poner estos en un script de shell como el gancho de post-recepción en el servidor, pero simplemente no parece tener ningún efecto. Sé que el script se está ejecutando porque veo "Cambios empujados al servidor" después de presionar. Aquí está el post-recibir gancho:

#!/bin/sh 
git reset --hard HEAD 
echo "Changes pushed to server." 
+0

@VonC: la parte más importante de [su respuesta] (http://stackoverflow.com/ preguntas/3838727/git-post-receive-hook-for-web-staging/3838796 # 3838796) fue escrito principalmente en lenguaje 'bash', mientras que el downvoter probablemente afirmó su nativo;) – takeshin

Respuesta

73

La respuesta a su pregunta es aquí: http://toroid.org/ams/git-website-howto

En resumen, lo que se quiere hacer es añadir un "árbol de trabajo independiente" al repositorio desnudo. Normalmente, usted piensa que su árbol de trabajo contiene el directorio .git. Los repositorios desnudos no tienen un árbol de trabajo por definición, pero puede crear uno siempre que esté en un directorio diferente al repositorio simple.

El gancho post-recepción es simplemente un simple git checkout -f para replicar el repositorio HEAD en el directorio de trabajo. Apache lo utiliza como su raíz de documento, y ya está todo listo. Cada vez que ingresas al repositorio simple, Apache inmediatamente comenzará a servirlo.

Generalmente utilizo esto para enviar automáticamente a un servidor de transferencia para ver si el entorno "real" vomitará en mis cambios. Desplegar al servidor en vivo es una historia completamente diferente. :-)

+0

Gracias, todavía soy nuevo en Git y cuando comencé con este proyecto, no estaba seguro de por qué debería haber un repositorio vacío cuando podía copiar en la raíz del documento y simplemente iniciarlo. Creo que entiendo ahora que simplemente mantiene los metadatos de git fuera de la raíz del documento. ¿Es eso correcto? – Matt

+0

Además, el ejemplo en el enlace de arriba muestra cómo comenzar desde cero e ingresar al servidor desde un repositorio local. ¿Cuál es el mejor método para obtener un repositorio desnudo (fuera de la raíz del documento web) del que está actualmente allí? – Matt

+0

Matt, un repositorio simple generalmente se usa en su servidor central. Si solo tiene una copia del repositorio y lo está implementando directamente desde allí, se encontrará con problemas rápidamente. Crea un repositorio vacío en otro directorio con 'git init --bare'. Luego, en su clon local del repositorio, haga 'git origin add path_to_central_repo' para marcar el nuevo repositorio central como el original. Finalmente, 'git push origin master' aplicará todo lo que haya hecho al maestro.Cree un árbol de trabajo separado del repositorio central y escenifique su sitio con cada 'push' de su clon. – Paul

15

actualizado en Marzo el año 2015

Como ya he mencionado en "What is this Git warning message when pushing changes to a remote repository?", en realidad se puede empujar directamente a un acuerdo de recompra no descubierto ahora (Git 2.3.0+, de febrero de 2015) con:

git config receive.denyCurrentBranch updateInstead 

actualización del árbol de trabajo en consecuencia, pero se niegan a hacerlo si hay cambios no confirmados.

Eso le permitiría evitar cualquier gancho post-recepción.


(Respuesta original: Oct 2010)

El GitFAQ recomienda para non-bare repo este post-actualización de gancho:
(que podría darle más idea de lo que está sucediendo realmente en la ejecución de gancho. Tenga en cuenta que esto es un gancho posterior a la actualización, no un post-recepción)

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

para que esto funcione, usted todavía necesita para permitir específicamente empujando los cambios en la rama actual utilizando cualquiera de e de estos valores de configuración:

git config receive.denyCurrentBranch ignore 

o

git config receive.denyCurrentBranch warn 
+4

+1: El script puede parecer voluminoso o verboso, pero es así por una buena razón; a diferencia de los enfoques contundentes de usar un simple 'git reset --hard' o' git checkout -f', preservará cualquier cambio no confirmado en un alijo. –

+0

Este script es totalmente fubar y no hace nada. Me las arreglé para repararlo (con suerte), ver mi respuesta ... – Tronic

+0

Con Git 2.3 ya no necesitas este enlace, puedes hacer 'git config receive.denyCurrentBranch updateInstead'. Ver https://github.com/blog/1957-git-2-3-has-been-released. – Aurelien

1

Estoy adivinando, pero esto puede ser un problema de permiso (¿se necesita la ruta completa? cd?).Compruebe lo que realmente está sucediendo en los archivos de registro.

Sin embargo, publicar los archivos a través de git es siempre una tarea del proceso de publicación. Por lo general, necesita copiar algunos archivos, eliminar otros, configurar, actualizar permisos, generar documentos, etc.

Para una solución compleja, un script de compilación podría ser mejor que cualquier git hook. Herramientas que pueden manejar esas tareas muy bien:

(Me di cuenta que no es la respuesta que usted está esperando, pero es demasiado largo para publicar como comentario)

11

Tuve exactamente el mismo problema. En respuesta a este enlace: http://toroid.org/ams/git-website-howto - El siguiente comando lo ha hecho:

sudo chmod +x hooks/post-receive 

Nos perdimos un permiso sudo configura primero la materia.

6

Versión fija del script de VonC, funciona para mí (absolutamente ninguna garantía).

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

set -e 

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 
    # need to touch some files or restart the application? do that here: 
    # touch *.wsgi 
    ) 

} 

if [ x"${is_bare}" = x"false" ] 
then 
    active_branch=$(git symbolic-ref HEAD) 
    export GIT_DIR=$(cd ${GIT_DIR}; pwd) 
    GIT_WORK_TREE="${GIT_DIR}/.." 
    for ref in $(cat) 
    do 
     if [ x"$ref" = x"${active_branch}" ] 
     then 
      update_wc $ref 
     fi 
    done 
fi 
+1

+1 Comentarios interesantes. Tendré que probarlo. – VonC

6

Simple script para configurar este despliegue git:

Preparación post-recibir gancho:

echo '#!/bin/sh'  > .git/hooks/post-receive 
echo 'git checkout -f' >> .git/hooks/post-receive 
echo 'git reset --hard' >> .git/hooks/post-receive 
chmod +x .git/hooks/post-receive 

Permitir empuje en este repositorio, aunque no está desnudo:

git config receive.denycurrentbranch false 
+1

También puede hacer uso de worktree externo: 'git config core.worktree/path/to/workdir'. Puede convertir el repositorio vacío en uno con worktree para eso ('git config core.bare false') –

+0

¿Por qué necesita' git reset --hard' BTW? –

+3

También puede agregar 'git diff -R --cached --name-status' antes de finalizar la compra para obtener una buena lista de los archivos que se están actualizando en el lado de empuje. –

Cuestiones relacionadas