2010-10-01 7 views
59

Sto provando a configurare Git per la gestione del mio sito Web in modo che possa git pull per far funzionare la versione corrente a livello locale e quindi git push per inviare le modifiche al server remoto. L'ho configurato in modo che funzioni come preferisco, ma dopo aver premuto, devo eseguire manualmente git checkout -f o git reset --hard HEAD sul server remoto.Git Post-Receive Hook per la gestione dei siti Web

Ho provato a inserirli in uno script di shell come hook di post-ricezione sul server, ma non sembra avere alcun effetto. So che lo script è in esecuzione perché visualizzo "Changes pushed to server" dopo che ho premuto. Ecco il post-ricezione gancio:

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

@VonC: la parte più importante di [la tua risposta] (http://stackoverflow.com/ domande/3838727/git-post-receive-hook-per-website-staging/3838796 # 3838796) è stato scritto principalmente in 'bash', mentre il downvoter probabilmente ha affermato il suo nativo;) – takeshin

risposta

73

La risposta alla tua domanda è qui: http://toroid.org/ams/git-website-howto

In breve, ciò che si vuole fare è aggiungere un "albero di lavoro distaccato" al repository nudo. Normalmente si pensa al proprio albero di lavoro come contenente la directory .git. I repository bare non hanno un albero di lavoro per definizione, ma è possibile crearne uno finché si trova in una directory diversa rispetto al repository nudo.

Il gancio di post-ricezione è solo un semplice git checkout -f per replicare il HEAD del repository nella directory di lavoro. Apache lo usa come root dei documenti e tutto è pronto. Ogni volta che si esegue il push nel repository, Apache inizierà immediatamente a servirlo.

Generalmente uso questo per spingere automaticamente su un server di staging per vedere se l'ambiente "reale" vomiterà sulle mie modifiche. Distribuire sul server live è una storia completamente diversa. :-)

+0

Grazie, sono ancora nuovo a Git e quando ho iniziato con questo progetto, non ero sicuro del motivo per cui ci dovrebbe essere un repository nudo quando potrei cd nella root del documento e solo git init. Penso di capire ora che mantiene solo i metadati git dalla radice del documento. È corretto? – Matt

+0

Inoltre, l'esempio nel link sopra riportato mostra come iniziare da zero e spingere sul server da un repository locale. Qual è il metodo migliore per ottenere un repository nudo (al di fuori della root del documento Web) da quello attualmente in uso? – Matt

+0

Matt, un repository spoglio viene generalmente utilizzato sul server centrale. Se si dispone solo di una copia del repository e si sta distribuendo direttamente da quella, si incontreranno rapidamente problemi. Crea un repository nudo in un'altra directory con 'git init --bare'. Quindi, nel tuo clone locale del repository, esegui 'git origin per aggiungere path_to_central_repo' per contrassegnare il nuovo repository centrale come originale. Infine, 'git push origin master' spingerà tutto ciò che hai fatto al master.Crea un albero di lavoro distaccato dal repository centrale e metti in scena il tuo sito con ogni "push" dal tuo clone. – Paul

15

Aggiornamento marzo 2015

Come ho detto nel "What is this Git warning message when pushing changes to a remote repository?", in realtà si può spingere direttamente ad un repo non nuda ora (Git 2.3.0+, febbraio 2015) con:

git config receive.denyCurrentBranch updateInstead 

Aggiornamento l'albero di lavoro di conseguenza, ma si rifiutano di farlo se ci sono modifiche non.

Ciò consentirebbe di evitare qualsiasi hook di post-ricezione.


(risposta originale: ott 2010)

Il GitFAQ raccomanda per non-bare repo questo gancio post-aggiornamento:
(potrebbe dare più pallida idea di ciò che sta realmente accadendo nella esecuzione gancio. Nota: questo è un gancio di post-aggiornamento, non un post-ricezione)

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

per far funzionare tutto questo, si sarebbe ancora necessario consentire specificatamente spingere le modifiche al ramo corrente utilizzando sia su e di queste impostazioni di configurazione:

git config receive.denyCurrentBranch ignore 

o

git config receive.denyCurrentBranch warn 
+4

+1: la sceneggiatura potrebbe sembrare ingombrante o prolisso, ma è così per una buona ragione; a differenza degli approcci smussati dell'uso di un semplice 'git reset --hard' o' git checkout -f', conserverà tutte le modifiche non salvate in uno stash. –

+0

Questo script è completamente fubar e non fa nulla. Sono riuscito a ripararlo (sperando correttamente), vedere la mia risposta ... – Tronic

+0

Con Git 2.3 non hai più bisogno di questo hook puoi fare 'git config receive.denyCurrentBranch updateInstead'. Vedi https://github.com/blog/1957-git-2-3-has-been-released. – Aurelien

1

Sto solo indovinando, ma questo potrebbe essere un problema di autorizzazione (necessario percorso completo? cd?).Controlla cosa sta realmente accadendo nei file di registro.

Tuttavia pubblicare i file tramite git è sempre solo una delle attività del processo di pubblicazione. Di solito è necessario copiare alcuni file, eliminare altri, configurare, aggiornare le autorizzazioni, generare documenti, ecc.

Per una soluzione complessa, uno script di compilazione potrebbe essere migliore di qualsiasi hook di git. Strumenti in grado di gestire questi compiti molto bene:

(Mi rendo conto che non è la risposta vi aspettate, ma è troppo lungo per post come commento)

11

Ho avuto lo stesso identico problema. In una risposta a questo link: http://toroid.org/ams/git-website-howto - Il seguente comando ce l'ha fatta:

sudo chmod +x hooks/post-receive 

Abbiamo perso un permesso sudo prima configurato la roba.

6

La versione fissa della sceneggiatura di VonC, funziona per me (assolutamente nessuna garanzia).

#!/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 Feedback interessante. Dovrò provarlo. – VonC

6

semplice script per impostare questa distribuzione git:

Preparazione post-ricezione gancio:

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 

Permettere spinta in questo repository, anche se non è nuda:

git config receive.denycurrentbranch false 
+1

È anche possibile utilizzare l'albero di lavoro esterno: 'git config core.worktree/path/to/workdir'. È possibile trasformare il repository nuda in uno con worktree per quello ('git config core.bare false') –

+0

Perché è necessario' git reset --hard' BTW? –

+3

Puoi anche aggiungere 'git diff -R --cached --name-status' prima del checkout per ottenere un buon elenco di quali file vengono aggiornati sul lato push. –