Wdróż projekt za pomocą Git Push

412

Czy można wdrożyć witrynę za pomocą git push? Mam przeczucie, że ma to coś wspólnego z używaniem haków git do wykonywania git reset --hardpo stronie serwera, ale jak miałbym to zrobić?

Kyle Cronin
źródło
2
Zgaduję, że miałoby to zastosowanie tylko w sytuacjach, gdy istnieje tylko jeden serwer produkcyjny, prawda?
Rijk,
6
@Rijk Cóż, możesz przesyłać na wiele serwerów jednocześnie za pomocą Git, ale kiedy dojdziesz do tego poziomu, możesz chcieć rzeczywistego rozwiązania, a nie takiego hacka.
Kyle Cronin
Z powodzeniem korzystałem z capistrano w moich projektach, które choć pierwotnie zostały zaprojektowane do wdrażania aplikacji Ruby on Rails, dobrze współpracują z PHP i innymi projektami.
Przetłumaczyłem odpowiedzi na rosyjski na ru.so: ru.stackoverflow.com/questions/428483/…
Nick Volynkin

Odpowiedzi:

287

Znalazłem ten skrypt na tej stronie i wydaje się, że działa całkiem dobrze.

  1. Skopiuj katalog .git na serwer WWW
  2. Na kopii lokalnej zmodyfikuj plik .git / config i dodaj serwer WWW jako zdalny:

    [remote "production"]
        url = username@webserver:/path/to/htdocs/.git
    
  3. Na serwerze zastąp .git / hooks / post-update tym plikiem (w odpowiedzi poniżej)

  4. Dodaj dostęp do wykonania do pliku (ponownie na serwerze):

    chmod +x .git/hooks/post-update
    
  5. Teraz po prostu lokalnie wypchnij na serwer sieciowy i powinien on automatycznie zaktualizować kopię roboczą:

    git push production
    
Kyle Cronin
źródło
128
Upewnij się, że masz politykę .htaccess, która chroni katalog .git przed odczytaniem. Ktoś, kto ma ochotę na nurkowanie z adresami URL, może spędzić dzień z całym kodem źródłowym, jeśli jest dostępny.
Jeff Ferland
39
Alternatywnie po prostu ustaw katalog publiczny jako podkatalog repozytorium git. Wtedy możesz mieć prywatne pliki, które możesz mieć pewność, że nie zostaną upublicznione.
tlrobinson
3
ten link jest martwy. czy istnieje inny link do pliku po aktualizacji?
Robert Hurst
6
Może coś mi brakuje, ale czy nie chcesz, aby twoje serwery produkcyjne pobierały z głównej gałęzi produktu repozytoria git? Chyba OP ma tylko jeden serwer? Zwykle mój serwer ciągłej integracji wykonuję wdrożenie mojej witryny (uruchamiam kilka testów przed wdrożeniem).
Adam Gent
4
Postępując zgodnie z tymi krokami z repozytorium, które ma już sekwencję zatwierdzeń; na początku nie można wypychać, ponieważ gałąź główna jest już wypisana. Następnie, jeśli pobierzesz alternatywną gałąź na zdalnym komputerze, tylko różne pliki zostaną pobrane do katalogu roboczego. Spodziewałem się, że hak zresetuje
twardy
80

Korzystając z poniższego pliku po aktualizacji :

  1. Skopiuj katalog .git na serwer WWW
  2. Na kopii lokalnej zmodyfikuj plik .git / config i dodaj serwer WWW jako zdalny:

    [remote "production"]
        url = username@webserver:/path/to/htdocs/.git
    
  3. Na serwerze zastąp .git / hooks / post-update poniższym plikiem

  4. Dodaj dostęp do wykonania do pliku (ponownie na serwerze):

    chmod +x .git/hooks/post-update
    
  5. Teraz po prostu lokalnie wypchnij na serwer sieciowy i powinien on automatycznie zaktualizować kopię roboczą:

    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 HEAD@{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 HEAD@{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
Darío Javier Cravero
źródło
5
Rany ... po prostu napisz ten skrypt w języku, którego używasz do programowania: php, python, groovy lub cokolwiek innego! Nigdy nie rozumiałem tej miłości do skryptów powłoki, które mają (subiektywnie) dość dziwną składnię i tak mało funkcji.
dVaffection,
4
@dVaffection w każdym przypadku, jeśli zamierzasz pisać polecenia powłoki, jeśli używasz git. więc zamiast pisać skrypt w innym języku i ciągle żonglować między tym językiem a powłoką. pisanie wszystkiego w skorupie wydaje się logiczne, nie sądzisz?
Abderrahmane TAHRI JOUTI
Musiałem wykonać polecenie „git config receive.denyCurrentBranch updateInstead” również na serwerze, aby zaakceptował wypychanie. Myślę, że to dlatego, że gałąź została sprawdzona?
stackPusher
60

Po wielu fałszywych uruchomieniach i ślepych zaułkach, w końcu jestem w stanie wdrożyć kod witryny za pomocą „git push remote ” dzięki temu artykułowi .

Skrypt po aktualizacji autora ma tylko jedną linię, a jego rozwiązanie nie wymaga konfiguracji .htaccess, aby ukryć repozytorium Git, jak robią to inni.

Kilka przeszkód, jeśli wdrażasz to na instancji Amazon EC2;

1) Jeśli używasz sudo do utworzenia pustego docelowego repozytorium, musisz zmienić właściciela repo na ec2-user, inaczej push nie powiedzie się. (Spróbuj „chown ec2-user: ec2-user repo .”)

2) Wypychanie zakończy się niepowodzeniem, jeśli nie wstępnie skonfigurujesz lokalizacji swojego prywatnego klucza amazon .pem, albo w / etc / ssh / ssh_config jako parametr IdentityFile, albo w ~ / .ssh / config za pomocą „[ Host] - HostName - IdentityFile - User ”opisany tutaj układ ...

... JEDNAK jeśli Host jest skonfigurowany w ~ / .ssh / config i różni się od HostName, wypychanie Git nie powiedzie się. (To prawdopodobnie błąd Git)

Earl Zedd
źródło
Postępowałem zgodnie z krokami we wspomnianym artykule i wszystko działało jak urok. Zastanawiam się tylko, czy istnieją pewne wady dotyczące bezpieczeństwa lub stabilności. Wszelkie porady na ten temat?
xlttj
xl-t: Zakładając, że używasz Git zamiast SSH, powiedziałbym, że niebezpieczeństwo polega na popełnieniu błędu z Git. Możesz zapytać autora artykułu; kończy to słowami „Pytania i sugestie są mile widziane”. Moja obecna (martwa mózgiem) strategia replikacji polega na użyciu Transmitowania przez Panic Software.
Earl Zedd
1
Artykuł powiązany ma jeden ważny wymóg, gdy używasz haków. Przechwytywanie zakończy się niepowodzeniem, jeśli .git będzie w tym samym schemacie nazewnictwa co katalog roboczy. tj. / foo / bar (katalog roboczy) i /foo/bar.git (repozytorium git barebone). Upewnij się więc, że zmienisz nazwę / foo / bar na coś innego, na przykład /foo/bar.live lub / foo / blah Cóż, na wypadek, gdybyś się zastanawiał, dokładnie ten komunikat o błędzie, który otrzymasz, jeśli katalog roboczy ma taką samą nazwę jak repozytorium barebone jest „zdalne: śmiertelne: nie można wrócić do oryginalnego cwd: brak takiego pliku lub katalogu”
Antony
1
Nie rozumiem, dlaczego potrzebujesz haka po wdrożeniu do uruchomienia. Przekazanie zmian kodu do zdalnego repo oznacza, że ​​repo jest aktualne. czego mi brakuje?
Charlie Schliesser
1
@CharlieS brakuje ci tego, że git nie pozwoli ci zepchnąć gałęzi do repozytorium, w którym ta gałąź została wypisana. W tym przypadku (IMHO bardzo ładna) odpowiedzią jest posiadanie dwóch repozytoriów: nagiego repozytorium, na które się wypychasz, i drugiego repozytorium, którego katalog roboczy jest aktualizowany przez przechwytywanie, gdy repozytorium jest wypychane.
Ben Hughes
21

nie instaluj git na serwerze ani nie kopiuj tam folderu .git. aby zaktualizować serwer z klonu git, możesz użyć następującego polecenia:

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

być może będziesz musiał usunąć pliki, które zostały usunięte z projektu.

powoduje to skopiowanie wszystkich pobranych plików. rsync używa ssh, który i tak jest zainstalowany na serwerze.

im mniej oprogramowania zainstalowałeś na serwerze, tym jest on bezpieczniejszy i łatwiej jest zarządzać jego konfiguracją i dokumentować ją. nie ma również potrzeby utrzymywania pełnego klona git na serwerze. tylko to sprawia, że ​​bardziej skomplikowane jest prawidłowe zabezpieczenie wszystkiego.

chrześcijanin
źródło
3
Jedno zastrzeżenie: synchronizuje pliki, które masz w katalogu roboczym. Myślę, że można tego uniknąć za pomocą skryptu, który ukrywa bieżące zmiany, czyści wszystko, wdraża, a następnie cofa ukrywanie.
mateusz.fiolka
Serwery są mężczyznami?
Ian Warburton
12

W zasadzie wszystko, co musisz zrobić, to:

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

Mam te wiersze w mojej aplikacji jako plik wykonywalny o nazwie deploy.

więc kiedy chcę wykonać wdrożenie, piszę ./deploy myserver mybranch.

Lloyd Moore
źródło
zobacz moją odpowiedź, jak rozwiązać problem, jeśli potrzebujesz innego klucza prywatnego lub nazwy użytkownika dla ssh
Karussell
To rozwiązanie jest szybsze niż moje podczas wdrażania na wielu serwerach! Wystarczy wcisnąć do głównego repozytorium i wyciągnąć równolegle z niego. A jeśli nie chcesz lub nie możesz wdrożyć kluczy do każdej instancji, skorzystaj z agenta kluczy! ssh -A ...
Karussell
1
Byłoby łatwiej, gdybyś zamieścił przewodnik na temat konfigurowania kluczy SSH, na którym opiera się ta odpowiedź, aby działać „bezproblemowo”
Hengjie
Zastosowanie git pullnależy unikać automatycznych wdrożeń, ponieważ część z nich seryjnej może wymagać ręczne czyszczenie czy są jakieś konflikty.
Quinn Comendant
9

Sposób, w jaki to robię, polega na tym, że mam nagie repozytorium Git na moim serwerze wdrażania, gdzie wypycham zmiany. Następnie loguję się do serwera wdrażania, przechodzę do rzeczywistego katalogu dokumentów serwera WWW i wykonuję polecenie git. Nie używam żadnych haczyków, aby spróbować to zrobić automatycznie, co wydaje się większym problemem niż jest warte.

Greg Hewgill
źródło
W przypadku błędu w nowym kodzie, czy resetujesz dla każdego zatwierdzenia czy całego ściągania? (Czy jest tylko 1 możliwy?)
Rudie
1
@ Rudie: Jeśli musisz cofnąć zmiany na serwerze wdrażania, możesz użyć, git resetaby cofnąć się między najnowszymi zmianami (wszystkie zatwierdzenia, nie tylko całe ściągnięcie). Jeśli chcesz przywrócić coś konkretnego, co nie jest ostatnim zatwierdzeniem, możesz go użyć, git revertale prawdopodobnie powinno się go używać tylko w sytuacjach awaryjnych ( git reverttworzy nowe zatwierdzenie, które cofa działanie niektórych poprzednich zatwierdzeń).
Greg Hewgill
Z ciekawości: dlaczego według ciebie haczyki byłyby bardziej kłopotliwe niż warte tego?
Rijk,
@Rijk: W przypadku użycia haków, rzeczywisty katalog dokumentów serwera WWW jest zmieniany przez automatyczny proces w tle. Logowanie pozwala mi mieć większą kontrolę nad tym, kiedy zmiany zostaną zastosowane w katalogu docs. Ponadto łatwiej jest naprawić, gdy coś pójdzie nie tak. Haki mogą być bardziej odpowiednie, jeśli osoby odpowiedzialne nie mają wystarczającego dostępu do zalogowania się na serwerze WWW.
Greg Hewgill
Czy twój folder webapp jest również repozytorium .git? Co z folderem .git, który jest widoczny dla świata zewnętrznego?
Fernando
9

git config --local receive.denyCurrentBranch updateInstead

Dodane w Git 2.3 może to być dobra możliwość: https://github.com/git/git/blob/v2.3.0/Documentation/config.txt#L2155

Ustawiasz go w repozytorium serwera, a także aktualizuje działające drzewo, jeśli jest czyste.

Wprowadzono dalsze ulepszenia w wersji 2.4 z push-to-checkouthakiem i obsługą nienarodzonych gałęzi .

Przykładowe użycie:

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

Wynik:

a
b

Ma to następujące niedociągnięcia wymienione w ogłoszeniu GitHub :

  • Twój serwer będzie zawierał katalog .git zawierający całą historię twojego projektu. Prawdopodobnie chcesz się upewnić, że nie będzie można go udostępnić użytkownikom!
  • Podczas wdrażania użytkownicy mogą chwilowo napotkać witrynę w niespójnym stanie, z niektórymi plikami w starej wersji, a innymi w nowej wersji, a nawet w połowie zapisanymi plikami. Jeśli jest to problem dla twojego projektu, prawdopodobnie nie jest to możliwe w trybie push-to-deploy.
  • Jeśli twój projekt potrzebuje kroku „kompilacji”, musisz to ustawić jawnie, być może za pomocą githooków.

Ale wszystkie te punkty są poza zakresem Git i należy się tym zająć za pomocą zewnętrznego kodu. W tym sensie, to razem z haczykami Git są najlepszym rozwiązaniem.

Ciro Santilli
źródło
Aby to ustawić, uruchom następującą komendę: 'git config receive.denyCurrentBranch updateInstead' w terminalu
stackPusher
5

Aktualizacja: Używam teraz rozwiązania Lloyda Moore'a z kluczowym agentem ssh -A .... Wciśnięcie do głównego repozytorium, a następnie wyciągnięcie go równolegle ze wszystkich twoich maszyn jest nieco szybsze i wymaga mniejszej konfiguracji na tych komputerach.


Nie widzę tutaj tego rozwiązania. po prostu push przez ssh, jeśli git jest zainstalowany na serwerze.

Będziesz potrzebować następującego wpisu w lokalnym .git / config

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

Ale hej, po co to amazon:? W swoim lokalnym ~ / .ssh / config musisz dodać następujący wpis:

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

teraz możesz zadzwonić

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

(BTW: /path/to/project.git jest inny niż rzeczywisty katalog roboczy / ścieżka / do / projektu)

Karussell
źródło
5

Dla scenariusza wdrażania

W naszym scenariuszu przechowujemy kod na github / bitbucket i chcemy wdrożyć na serwerach na żywo. W tym przypadku działa dla nas następująca kombinacja (jest to remiks wysoko ocenianych odpowiedzi tutaj) :

  1. Skopiuj swój .gitkatalog na serwer WWW
  2. Na lokalnej kopii git remote add live ssh://user@host:port/folder
  3. Na pilocie: git config receive.denyCurrentBranch ignore
  4. Na zdalnym: nano .git/hooks/post-receivei dodaj tę treść:

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

  5. Na pilocie: chmod +x .git/hooks/post-receive

  6. Teraz możesz tam naciskać git push live

Notatki

  • To rozwiązanie działa ze starszymi wersjami git (testowane z wersjami 1.7 i 1.9)
  • Najpierw upewnij się, że wypychasz na github / bitbucket, abyś miał spójne repo na żywo
  • Jeśli .gitfolder znajduje się w katalogu głównym dokumentu, upewnij się, że ukryłeś go od zewnątrz, dodając do .htaccess( źródła ):

    RedirectMatch 404 /\..*$

Attila Fulop
źródło
4

Używamy capistrano do zarządzania wdrażaniem. Budujemy capistrano do wdrożenia na serwerze pomostowym, a następnie uruchamiamy rsync na wszystkich serwerach.

cap deploy
cap deploy:start_rsync (when the staging is ok)

Z capistrano możemy łatwo cofnąć w razie błędu

cap deploy:rollback
cap deploy:start_rsync
Supernini
źródło
Czy zintegrowałeś wdrożenie na żywo przez rsync z Capistrano?
Martin Abraham,
1

Wygląda na to, że powinieneś mieć dwie kopie na swoim serwerze. Naga kopia, z której można wypychać / wyciągać, z której można by wypchnąć zmiany, gdy skończysz, a następnie sklonujesz to w swoim katalogu internetowym i skonfigurujesz cronjob, aby codziennie aktualizował git pull z katalogu internetowego lub więc.

Płomień
źródło
1

Można sobie wyobrazić, że gdy powiesz, że dokonano zatwierdzenia, aby powiedzieć, że gałąź „stabilna” jest ustawiona, ściągnie zmiany i zastosuje je na stronie PHP. Dużym minusem jest to, że nie będziesz mieć dużej kontroli, jeśli coś pójdzie nie tak i wydłuży czas testowania - ale możesz zorientować się, ile pracy będzie wymagało, gdy połączysz powiedzenie gałęzi tułowia ze stabilną gałęzią, aby wiedzieć ile konflikty ty może napotkasz. Ważne będzie, aby mieć oko na wszystkie pliki specyficzne dla witryny (np. Pliki konfiguracyjne), chyba że zamierzasz wyłącznie uruchamiać tylko jedną witrynę.

Czy zamiast tego zastanawiałeś się nad zmianą na stronie?

Informacje na temat haków git można znaleźć w dokumentacji githooks .

Chealion
źródło
1

Moje podejście do rozwiązania dla chrześcijan .

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
  • Archiwizuje gałąź główną w tar
  • Wyodrębnia archiwum tar do katalogu wdrażania w folderze temp systemu.
  • rsync zmienia się w serwer
  • usuń katalog wdrażania z folderu tymczasowego.
Priit
źródło
1

Korzystam z następującego rozwiązania toroid.org , które ma prostszy skrypt przechwytujący .

na serwerze:

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

i zainstaluj hak na serwerze:

$ 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

na twoim kliencie:

$ 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

a następnie opublikować, po prostu wpisz

$ git push web

Pełny opis znajduje się na stronie: http://toroid.org/ams/git-website-howto

Synox
źródło
w ten sposób nie usuwaj istniejących plików w repozytorium.
RusAlex
2
Dlaczego git push web +master:refs/heads/masterzamiast tylko git push web master?
Matthieu Moy,
1

Jako odpowiedź uzupełniającą chciałbym zaoferować alternatywę. Używam git-ftp i działa dobrze.

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

Łatwy w użyciu, tylko typ:

git ftp push

a git automatycznie prześle pliki projektu.

pozdrowienia

manuelbcd
źródło
0

Biorąc pod uwagę środowisko, w którym wielu programistów uzyskuje dostęp do tego samego repozytorium, pomocne mogą być następujące wytyczne.

Upewnij się, że masz grupę uniksową, do której należą wszyscy deweloperzy, i przekaż własność repozytorium .git tej grupie.

  1. W .git / config repozytorium serwerów ustaw sharerepository = true. (Mówi to gitowi, aby zezwolić wielu użytkownikom, co jest potrzebne do zatwierdzania i wdrażania.

  2. ustaw umask każdego użytkownika w swoich plikach bashrc, aby były takie same - 002 to dobry początek

Lloyd Moore
źródło
0

Skończyło się na tym, że stworzyłem własne podstawowe narzędzie do wdrażania, które automatycznie ściągałoby nowe aktualizacje z repozytorium - https://github.com/jesalg/SlimJim - Zasadniczo nasłuchuje hitub po otrzymaniu haka i używa proxy do uruchomienia aktualizacja skryptu.

jesal
źródło
0

Używam dwóch rozwiązań dla haka po otrzymaniu:

ROZWIĄZANIE ROZWIĄZANIA 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

ROZWIĄZANIE ROZWIĄZANIA 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

Oba rozwiązania oparte są na wcześniejszych rozwiązaniach dostępnych w tym wątku.

Uwaga: BRANCH_REGEX = '^ $ {GIT_BRANCH1}.$ 'filtruje nazwy gałęzi pasujące do ciągu „master ” lub „dev *” i wdraża drzewo robocze, jeśli wypchnięta gałąź pasuje. Umożliwia to wdrożenie wersji deweloperskiej i głównej w różnych miejscach.

DEPLOY SOLUTION 1 usuwa tylko pliki, które są częścią repo i zostały usunięte przez zatwierdzenie. Jest szybszy niż Deployment Solution 2.

DEPLOY SOLUTION 2 ma tę zaletę, że usuwa wszelkie nowe pliki z katalogu produkcyjnego, który został dodany po stronie serwera, bez względu na to, czy został dodany do repozytorium, czy nie. Zawsze będzie czysty dupe repo. Jest wolniejszy niż rozwiązanie do wdrażania 1.

klor
źródło