2010-10-01 16 views
59

Próbuję skonfigurować Gita do przetaktowania mojej witryny, aby móc git pull uzyskać aktualną wersję do pracy lokalnie, a następnie git push, aby przesłać zmiany do zdalnego serwera. Mam go skonfigurowany tak, że działa tak, jak chcę, ale po naciśnięciu, muszę ręcznie uruchomić git checkout -f lub git reset --hard HEAD na serwerze zdalnym.Git Hook post-Receive dla witryny WWW

Próbowałem umieścić je w skrypcie powłoki jako haczyku po otrzymaniu na serwerze, ale po prostu nie wydaje się mieć żadnego wpływu. Wiem, że skrypt jest uruchomiony, ponieważ widzę komunikat "Zmiany przekazane do serwera" po tym, jak pchnę. Oto po otrzymać haczyk:

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

@VonC: Najważniejsza część [Twoja odpowiedź] (http://stackoverflow.com/ pytania/3838727/git-post-receive-hook-for-website-staging/3838796 # 3838796) został napisany głównie w języku 'bash', podczas gdy downvoter zapewnił zapewne jego rodzimy;) – takeshin

Odpowiedz

73

Odpowiedź na to pytanie jest tutaj: http://toroid.org/ams/git-website-howto

W skrócie, co chcesz zrobić, to dodać "oderwane drzewo praca" do nagiego repozytorium. Zwykle myślisz o swoim drzewie pracy jako zawierającym katalog .git. Nagie repozytoria nie mają drzewa pracy z definicji, ale można je utworzyć tak długo, jak w innym katalogu niż nagie repozytorium.

Hak po otrzymaniu jest prostym kodem git checkout -f do replikowania katalogu repozytorium HEAD do katalogu roboczego. Apache używa go jako głównego katalogu dokumentów i wszystko gotowe. Za każdym razem, gdy będziesz naciskał na nagie repozytorium, Apache natychmiast rozpocznie jego obsługę.

Generalnie używam tego, aby automatycznie przesłać na serwer pomostowy, aby sprawdzić, czy "prawdziwe" środowisko będzie ingerować w moje zmiany. Wdrażanie na serwer na żywo to zupełnie inna historia. :-)

+0

Dziękuję, wciąż jestem nowy w Git i kiedy zacząłem pracę nad tym projektem, nie byłem pewien, dlaczego powinno być nagie repozytorium, gdybym mógł wejść do katalogu głównego i po prostu git init. Myślę, że rozumiem teraz, że po prostu utrzymuje metadane git z głównego katalogu dokumentów. Czy to jest poprawne? – Matt

+0

Również przykład w powyższym linku pokazuje, jak zacząć od zera i przesłać do serwera z lokalnego repozytorium. Jaka jest najlepsza metoda uzyskania nagiego repozytorium (poza katalogiem głównym dokumentu) z tego, który jest tam obecnie? – Matt

+0

Matt, nagie repozytorium jest zwykle używane na centralnym serwerze. Jeśli masz tylko jedną kopię repozytorium i wdrażasz ją bezpośrednio, szybko napotkasz problemy. Utwórz nagie repozytorium w innym katalogu za pomocą 'git init --bare'. Następnie w lokalnym klonie repozytorium, wykonaj 'git origin add path_to_central_repo', aby oznaczyć nowe centralne repozytorium jako oryginał. Wreszcie, 'git push origin master' popchnie wszystko, co zrobiłeś do mistrza.Utwórz oddzielone drzewo robocze z centralnego repo, a Twoja strona będzie się wyświetlać za każdym naciśnięciem przycisku "od" twojego klona. – Paul

15

Aktualizacja marzec 2015

Jak już wspomniano w "What is this Git warning message when pushing changes to a remote repository?", to rzeczywiście może wypchnąć bezpośrednio na zakaz nagiej repo NOW (Git 2.3.0+, luty 2015) z:

git config receive.denyCurrentBranch updateInstead 

aktualizowania drzewa działa odpowiednio, ale odmówić zrobić, czy są jakieś niezatwierdzone zmiany.

Pozwoliłoby to uniknąć wszelkich haków po otrzymaniu.


(odpowiedź oryginalny: paź 2010)

GitFAQ zaleca dla non-bare repo tego haka post-Update:
(może to daje więcej pojęcia, co faktycznie dzieje się w realizacji haka. zauważ, że jest to hak post-update, a nie po odbierać)

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

aby to działało, to nadal trzeba specjalnie pozwalają pchania zmiany do bieżącej gałęzi przy użyciu albo na e od tych ustawień konfiguracyjnych:

git config receive.denyCurrentBranch ignore 

lub

git config receive.denyCurrentBranch warn 
+4

+1: Skrypt może wydawać się nieporęczny lub gadatliwy, ale tak jest z dobrego powodu; w przeciwieństwie do prostego podejścia do zwykłego 'git reset --hard' lub' git checkout -f', zachowa wszelkie niezatwierdzone zmiany w skrytce. –

+0

Ten skrypt jest całkowicie fubaryczny i nie robi nic. Udało mi się go naprawić (mam nadzieję, że poprawnie), zobacz moją odpowiedź ... – Tronic

+0

Z Git 2.3 nie potrzebujesz już tego haka, możesz zrobić 'git config receive.denyCurrentBranch updateInstead'. Zobacz https://github.com/blog/1957-git-2-3-has-been-released. – Aurelien

1

Zgaduję, ale może to być problem z pozwoleniem (pełna ścieżka jest potrzebna?Sprawdź, co tak naprawdę dzieje się w plikach dziennika.

Jednak publikowanie plików za pośrednictwem git jest zawsze tylko jednym z zadań procesu publikacji. Zazwyczaj trzeba skopiować niektóre pliki, usunąć inne, skonfigurować, zaktualizować uprawnienia, wygenerować dokumenty itp.

Dla złożonego rozwiązania skrypt budujący może być lepszy niż jakikolwiek inny hak. Narzędzia, które mogą obsługiwać te zadania bardzo dobrze:

(zdaję sobie sprawę, to nie jest odpowiedź spodziewasz, ale to zbyt długo post w komentarzu)

11

Miałem dokładnie ten sam problem. W odpowiedzi na ten link: http://toroid.org/ams/git-website-howto - Następujące polecenie wykonał go:

sudo chmod +x hooks/post-receive 

Brakowało nam zezwolenie sudo najpierw skonfigurowany rzeczy.

6

Naprawiono wersję skryptu VonC, działa dla mnie (absolutnie bez gwarancji).

#!/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 Ciekawe opinie. Będę musiał to przetestować. – VonC

6

Prosty skrypt do ustawiania tego rozmieszczenia git:

Przygotowanie post-otrzymywać Hak:

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 

Dopuszczenie włożyć do tego repozytorium, choć nie jest nagi:

git config receive.denycurrentbranch false 
+1

Można również użyć zewnętrznego worktree: 'git config core.worktree/path/to/workdir'. Możesz wyłączyć nagie repozytorium w jeden z worktree ('git config core.bare false') –

+0

Dlaczego potrzebujesz' git reset --hard' BTW? –

+3

Możesz także dodać 'git diff -R --cached --name-status' przed pobraniem, aby uzyskać ładną listę plików aktualizowanych po stronie pchającej. –