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 --hard
po stronie serwera, ale jak miałbym to zrobić?
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 --hard
po stronie serwera, ale jak miałbym to zrobić?
Odpowiedzi:
Znalazłem ten skrypt na tej stronie i wydaje się, że działa całkiem dobrze.
Na kopii lokalnej zmodyfikuj plik .git / config i dodaj serwer WWW jako zdalny:
[remote "production"]
url = username@webserver:/path/to/htdocs/.git
Na serwerze zastąp .git / hooks / post-update tym plikiem (w odpowiedzi poniżej)
Dodaj dostęp do wykonania do pliku (ponownie na serwerze):
chmod +x .git/hooks/post-update
Teraz po prostu lokalnie wypchnij na serwer sieciowy i powinien on automatycznie zaktualizować kopię roboczą:
git push production
Korzystając z poniższego pliku po aktualizacji :
Na kopii lokalnej zmodyfikuj plik .git / config i dodaj serwer WWW jako zdalny:
[remote "production"]
url = username@webserver:/path/to/htdocs/.git
Na serwerze zastąp .git / hooks / post-update poniższym plikiem
Dodaj dostęp do wykonania do pliku (ponownie na serwerze):
chmod +x .git/hooks/post-update
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
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)
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 . user@server.com:/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.
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
.
ssh -A ...
git pull
należy unikać automatycznych wdrożeń, ponieważ część z nich seryjnej może wymagać ręczne czyszczenie czy są jakieś konflikty.
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.
git reset
aby 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 revert
ale prawdopodobnie powinno się go używać tylko w sytuacjach awaryjnych ( git revert
tworzy nowe zatwierdzenie, które cofa działanie niektórych poprzednich zatwierdzeń).
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-checkout
hakiem 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 :
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.
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)
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) :
.git
katalog na serwer WWWgit remote add live ssh://user@host:port/folder
git config receive.denyCurrentBranch ignore
Na zdalnym: nano .git/hooks/post-receive
i dodaj tę treść:
#!/bin/sh
GIT_WORK_TREE=/var/www/vhosts/example.org git checkout -f
Na pilocie: chmod +x .git/hooks/post-receive
git push live
Jeśli .git
folder 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 /\..*$
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
Giddyup to niezależne od języka haczyki Git typu „ tylko dodaj wodę” do automatyzacji wdrażania za pomocą git push. Pozwala także mieć niestandardowe zaczepy start / stop do restartowania serwera WWW, podgrzewania pamięci podręcznej itp.
https://github.com/mpalmer/giddyup
Sprawdź przykłady .
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.
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 .
Moje podejście do rozwiązania dla chrześcijan .
git archive --prefix=deploy/ master | tar -x -C $TMPDIR | rsync $TMPDIR/deploy/ --copy-links -av username@server.com:/home/user/my_app && rm -rf $TMPDIR/deploy
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
git push web +master:refs/heads/master
zamiast tylko git push web master
?
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
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.
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.
ustaw umask każdego użytkownika w swoich plikach bashrc, aby były takie same - 002 to dobry początek
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.
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.