È possibile distribuire un sito Web utilizzando git push
? Ho un sospetto che abbia qualcosa a che fare con l'uso di git hook per eseguire un git reset --hard
lato server, ma come potrei fare per realizzarlo?
È possibile distribuire un sito Web utilizzando git push
? Ho un sospetto che abbia qualcosa a che fare con l'uso di git hook per eseguire un git reset --hard
lato server, ma come potrei fare per realizzarlo?
Risposte:
Ho trovato questo script su questo sito e sembra funzionare abbastanza bene.
Sulla tua copia locale, modifica il tuo file .git / config e aggiungi il tuo server web come remoto:
[remote "production"]
url = username@webserver:/path/to/htdocs/.git
Sul server, sostituire .git / hooks / post-update con questo file (nella risposta di seguito)
Aggiungi esegui l'accesso al file (di nuovo, sul server):
chmod +x .git/hooks/post-update
Ora, spingi localmente sul tuo server web e dovrebbe aggiornare automaticamente la copia di lavoro:
git push production
Utilizzando il file post-aggiornamento di seguito:
Sulla tua copia locale, modifica il tuo file .git / config e aggiungi il tuo server web come remoto:
[remote "production"]
url = username@webserver:/path/to/htdocs/.git
Sul server, sostituire .git / hooks / post-update con il file seguente
Aggiungi esegui l'accesso al file (di nuovo, sul server):
chmod +x .git/hooks/post-update
Ora, spingi localmente sul tuo server web e dovrebbe aggiornare automaticamente la copia di lavoro:
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
Dopo molte false partenze e vicoli ciechi, sono finalmente in grado di distribuire il codice del sito Web con "git push remote " grazie a questo articolo .
Lo script post-aggiornamento dell'autore è lungo solo una riga e la sua soluzione non richiede la configurazione .htaccess per nascondere il repository Git come altri.
Un paio di ostacoli se lo stai distribuendo su un'istanza di Amazon EC2;
1) Se si utilizza sudo per creare il repository di destinazione nudo, è necessario modificare il proprietario del repository in ec2-user o il push fallirà. (Prova "chown ec2-user: ec2-user repo .")
2) Il push fallirà se non si preconfigura la posizione della propria .pem amazon-private-key , in / etc / ssh / ssh_config come parametro IdentityFile o in ~ / .ssh / config usando "[ Host] - HostName - IdentityFile - Layout utente "descritto qui ...
... TUTTAVIA se Host è configurato in ~ / .ssh / config e diverso da HostName, il push di Git fallirà. (Questo è probabilmente un bug Git)
non installare git su un server o copiare lì la cartella .git. per aggiornare un server da un clone git puoi usare il seguente comando:
git ls-files -z | rsync --files-from - --copy-links -av0 . user@server.com:/var/www/project
potresti dover eliminare i file che sono stati rimossi dal progetto.
questo copia tutti i file archiviati. rsync usa comunque ssh che è installato su un server.
meno software hai installato su un server, più è sicuro e più facile è gestirne la configurazione e documentarlo. non è inoltre necessario mantenere un clone git completo sul server. rende solo più complesso proteggere tutto correttamente.
In sostanza tutto ciò che devi fare sono i seguenti:
server = $1
branch = $2
git push $server $branch
ssh <username>@$server "cd /path/to/www; git pull"
Ho quelle righe nella mia applicazione come un eseguibile chiamato deploy
.
quindi quando voglio fare una distribuzione scrivo ./deploy myserver mybranch
.
ssh -A ...
git pull
dovrebbe essere evitato per le distribuzioni automatizzate perché la parte di unione di essa potrebbe richiedere la pulizia manuale in caso di conflitti.
Il modo in cui lo faccio è che ho un repository Git nudo sul mio server di distribuzione in cui invio modifiche. Quindi accedo al server di distribuzione, passo alla directory dei documenti del web server e faccio un pull git. Non uso alcun gancio per provare a farlo automaticamente, questo sembra più problemi di quanti ne valga la pena.
git reset
per tornare indietro tra le ultime modifiche (tutti i commit, non solo l'intero pull). Se è necessario eseguire il rollback di qualcosa di specifico che non è l'ultimo commit, è possibile utilizzarlo git revert
ma probabilmente dovrebbe essere utilizzato solo in situazioni di emergenza ( git revert
crea un nuovo commit che annulla l'effetto di alcuni commit precedenti).
git config --local receive.denyCurrentBranch updateInstead
Aggiunto in Git 2.3, questa potrebbe essere una buona possibilità: https://github.com/git/git/blob/v2.3.0/Documentation/config.txt#L2155
Lo si imposta sul repository del server e aggiorna anche l'albero di lavoro se è pulito.
Ci sono stati ulteriori miglioramenti in 2.4 con l' push-to-checkout
amo e la gestione di rami non nati .
Esempio di utilizzo:
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
Produzione:
a
b
Ciò presenta le seguenti carenze menzionate nell'annuncio di GitHub :
Ma tutti questi punti non rientrano nell'ambito di applicazione di Git e devono essere gestiti da un codice esterno. Quindi, in questo senso, questa, insieme ai ganci Git, è la soluzione definitiva.
Aggiornamento: ora sto usando la soluzione Lloyd Moore con l'agente chiave ssh -A ...
. Passare a un repository principale e quindi estrarlo in parallelo da tutte le macchine è un po 'più veloce e richiede meno configurazione su quelle macchine.
Non vedendo questa soluzione qui. basta spingere via ssh se git è installato sul server.
Avrai bisogno della seguente voce nel tuo .git / config locale
[remote "amazon"]
url = amazon:/path/to/project.git
fetch = +refs/heads/*:refs/remotes/amazon/*
Ma ehi, con che cosa amazon:
? Nella tua ~ / .ssh / config locale dovrai aggiungere la seguente voce:
Host amazon
Hostname <YOUR_IP>
User <USER>
IdentityFile ~/.ssh/amazon-private-key
ora puoi chiamare
git push amazon master
ssh <USER>@<YOUR_IP> 'cd /path/to/project && git pull'
(A proposito: /path/to/project.git è diverso dall'effettiva directory di lavoro / path / to / project)
Nel nostro scenario stiamo memorizzando il codice su github / bitbucket e vogliamo implementarlo su server live. In questo caso la seguente combinazione funziona per noi (che è un remix delle risposte altamente votate qui) :
.git
directory sul tuo server webgit remote add live ssh://user@host:port/folder
git config receive.denyCurrentBranch ignore
Sul telecomando: nano .git/hooks/post-receive
e aggiungi questo contenuto:
#!/bin/sh
GIT_WORK_TREE=/var/www/vhosts/example.org git checkout -f
Sul telecomando: chmod +x .git/hooks/post-receive
git push live
Se la .git
cartella si trova nella radice del documento, assicurati di nasconderla dall'esterno aggiungendo a .htaccess
( sorgente ):
RedirectMatch 404 /\..*$
Usiamo capistrano per gestire la distribuzione. Costruiamo capistrano per la distribuzione su un server di gestione temporanea e quindi eseguiamo un rsync con tutti i nostri server.
cap deploy
cap deploy:start_rsync (when the staging is ok)
Con capistrano, possiamo semplificare il rollback in caso di bug
cap deploy:rollback
cap deploy:start_rsync
Giddyup sono indipendente dal linguaggio just-add-acqua ganci git per automatizzare la distribuzione tramite git push. Consente inoltre di disporre di hook di avvio / arresto personalizzati per il riavvio del server Web, il riscaldamento della cache, ecc.
https://github.com/mpalmer/giddyup
Dai un'occhiata agli esempi .
Sembra che dovresti avere due copie sul tuo server. Una copia nuda, da cui è possibile eseguire il push / pull, da cui si spingerebbero le modifiche al termine, quindi si clonerebbe questo nella directory Web e si imposta un cronjob per aggiornare git pull dalla directory Web ogni giorno o così.
Si potrebbe concepire un hook git che quando dice che è stato fatto un commit per dire il ramo "stabile", tirerà le modifiche e le applicherà al sito PHP. Il grande svantaggio è che non avrai molto controllo se qualcosa va storto e aggiungerà tempo ai tuoi test - ma puoi avere un'idea di quanto lavoro sarà coinvolto quando ti unisci, per dire il ramo del tuo tronco nel ramo stabile per sapere quanti conflitti si possono incontrare. Sarà importante tenere d'occhio tutti i file specifici del sito (ad es. File di configurazione) a meno che non si intenda solo eseguire un solo sito.
In alternativa, hai cercato di spingere la modifica al sito invece?
Per informazioni sui git git consultare la documentazione di githooks .
La mia opinione sulla soluzione dei cristiani .
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
Sto usando la seguente soluzione di toroid.org , che ha uno script hook più semplice.
sul server:
$ mkdir website.git && cd website.git
$ git init --bare
Initialized empty Git repository in /home/ams/website.git/
e installa l'hook sul server:
$ 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
sul tuo cliente:
$ 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
quindi per pubblicare, basta digitare
$ git push web
C'è una descrizione completa sul sito web: http://toroid.org/ams/git-website-howto
git push web +master:refs/heads/master
invece di solo git push web master
?
Come risposta complementare vorrei offrire un'alternativa. Sto usando git-ftp e funziona benissimo.
https://github.com/git-ftp/git-ftp
Facile da usare, digitare solo:
git ftp push
e git caricherà automaticamente i file di progetto.
Saluti
Dato un ambiente in cui più sviluppatori accedono allo stesso repository, possono essere utili le seguenti linee guida.
Assicurati di avere un gruppo unix a cui appartengono tutti gli sviluppatori e assegna la proprietà del repository .git a quel gruppo.
In .git / config del repository del server impostare sharedrepository = true. (Questo dice a git di consentire a più utenti che è necessario per il commit e la distribuzione.
imposta lo stesso umask di ogni utente nei suoi file bashrc per essere lo stesso - 002 è un buon inizio
Ho finito per creare il mio strumento di distribuzione rudimentale che tirare automaticamente i nuovi aggiornamenti dal repo - https://github.com/jesalg/SlimJim - Fondamentalmente si ascolta il github post-ricezione-gancio e utilizza un proxy per attivare un script di aggiornamento.
Uso due soluzioni per l'hook post-ricezione:
DEPLOY SOLUTION 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
DEPLOY SOLUTION 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
Entrambe le soluzioni si basano su soluzioni precedenti disponibili in questo thread.
Nota, BRANCH_REGEX = '^ $ {GIT_BRANCH1}. $ 'filtra i nomi dei rami corrispondenti alla stringa "master " o "dev *" e distribuisce l'albero di lavoro, se il ramo spinto corrisponde. Ciò rende possibile distribuire una versione di sviluppo e una versione principale in luoghi diversi.
DEPLOY SOLUTION 1 rimuove solo i file che fanno parte del repository ed è stato rimosso da un commit. È più veloce di Deployment Solution 2.
DEPLOY SOLUTION 2 ha il vantaggio di rimuovere tutti i nuovi file dalla directory di produzione, che è stata aggiunta sul lato server, indipendentemente dal fatto che sia stata aggiunta o meno al repository. Sarà sempre pulito duplicato del repository. È più lento della soluzione di distribuzione 1.