Distribuisci un progetto usando Git push

È ansible implementare un sito Web usando git push ? Ho la sensazione che abbia qualcosa a che fare con l’uso di git hooks per eseguire un git reset --hard sul lato server, ma come potrei fare per realizzare questo?

Ho trovato questo script su questo sito e sembra funzionare abbastanza bene.

  1. Copia la tua directory .git sul tuo server web
  2. Sulla tua copia locale, modifica il tuo file .git / config e aggiungi il tuo server web come remoto:

     [remote "production"] url = [email protected]:/path/to/htdocs/.git 
  3. Sul server, sostituire .git / hook / post-update con questo file (nella risposta sotto)

  4. Aggiungi l’accesso al file (di nuovo, sul server):

     chmod +x .git/hooks/post-update 
  5. Ora, solo localmente, spinga al tuo server web e dovrebbe aggiornare automaticamente la copia di lavoro:

     git push production 

Utilizzando il file post-aggiornamento qui sotto:

  1. Copia la tua directory .git sul tuo server web
  2. Sulla tua copia locale, modifica il tuo file .git / config e aggiungi il tuo server web come remoto:

     [remote "production"] url = [email protected]:/path/to/htdocs/.git 
  3. Sul server, sostituire .git / hooks / post-update con il file sottostante

  4. Aggiungi l’accesso al file (di nuovo, sul server):

     chmod +x .git/hooks/post-update 
  5. Ora, solo localmente, spinga al 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 [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 

Dopo molte false partenze e vicoli ciechi, sono finalmente in grado di implementare il codice del sito web con “git push remote ” solo grazie a questo articolo .

Lo script post-aggiornamento dell’autore è lungo solo una riga e la sua soluzione non richiede la configurazione .htaccess per hide il repository Git come fanno altri.

Un paio di ostacoli se si sta distribuendo questo su un’istanza Amazon EC2;

1) Se si utilizza sudo per creare il repository di destinazione nullo, è necessario cambiare il proprietario del repository in ec2-user o il push fallirà. (Prova “chown ec2-user: ec2-user repo .”)

2) La spinta fallirà se non si preconfigura la posizione della propria chiave amazon-privata .pem, in / etc / ssh / ssh_config come parametro IdentityFile o in ~ / .ssh / config usando “[ Host] – HostName – IdentityFile – User “layout descritto qui …

… TUTTAVIA se Host è configurato in ~ / .ssh / config e diverso da HostName, il push Git fallirà. (Probabilmente è un bug Git)

non installare git su un server o copiare la cartella .git lì. per aggiornare un server da un clone git puoi usare il seguente comando:

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

potrebbe essere necessario eliminare i file che sono stati rimossi dal progetto.

questo copia tutti i file archiviati. rsync usa ssh che è installato su un server comunque.

meno software hai installato su un server più è sicuro e più facile è gestirlo 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 è il seguente:

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

Ho quelle linee nella mia applicazione come un eseguibile chiamato deploy .

quindi quando voglio fare un deploy ./deploy myserver mybranch .

Il modo in cui lo faccio è che ho un repository Git sul server di distribuzione in cui applico le modifiche. Quindi accedo al server di distribuzione, passo alla directory dei documenti del server web e faccio un pull git. Non uso alcun hook per provare a farlo automaticamente, sembra più un problema che non ne vale la pena.

receive.denyCurrentBranch updateInstead aggiunto in Git 2.3 è una possibilità.

Impostalo sul repository del server e aggiorna anche l’albero di lavoro se è pulito.

Ci sono stati ulteriori miglioramenti in 2.4 con il hook push-to-checkout e la gestione dei rami non ancora 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 

Questo ha le seguenti mancanze menzionate nell’annuncio di GitHub :

  • Il tuo server conterrà una directory .git contenente l’intera cronologia del tuo progetto. Probabilmente vuoi essere più sicuro che non possa essere offerto agli utenti!
  • Durante il deploys, gli utenti potrebbero momentaneamente incontrare il sito in uno stato incoerente, con alcuni file nella vecchia versione e altri nella nuova versione, o anche file parzialmente scritti. Se questo è un problema per il tuo progetto, push-to-deploy probabilmente non fa per te.
  • Se il tuo progetto ha bisogno di un passo “build”, dovrai impostarlo esplicitamente, forse tramite githooks.

Ma tutti questi punti sono fuori dallo scopo di Git e devono essere curati da un codice esterno. Quindi in questo senso, questo, insieme ai ganci Git, è la soluzione definitiva.

Aggiornamento: sto utilizzando la soluzione Lloyd Moore con l’agente chiave ssh -A ... Passare a un repository principale e quindi prelevarlo in parallelo da tutte le macchine è un po ‘più veloce e richiede meno impostazioni su quelle macchine.


Non vedendo questa soluzione qui. basta premere tramite ssh se git è installato sul server.

Avrai bisogno della seguente voce nel tuo locale .git / config

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

Ma hey, che cosa è quello con amazon: Nel tuo ~ / .ssh / config locale dovrai aggiungere la seguente voce:

 Host amazon Hostname  User  IdentityFile ~/.ssh/amazon-private-key 

ora puoi chiamare

 git push amazon master ssh @ 'cd /path/to/project && git pull' 

(BTW: /path/to/project.git è diverso dall’effettiva directory di lavoro / percorso / al / progetto)

Utilizziamo capistrano per la gestione della distribuzione. Costruiamo capistrano per la distribuzione su un server di staging, quindi eseguiamo un rsync con tutto il nostro server.

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

Con capistrano, possiamo rendere facile il rollback in caso di bug

 cap deploy:rollback cap deploy:start_rsync 

Per lo scenario di distribuzione

Nel nostro scenario stiamo memorizzando il codice su github / bitbucket e vogliamo effettuare la distribuzione su server live. In questo caso la seguente combinazione funziona per noi (questo è un remix delle risposte con alta stima qui) :

  1. Copia la tua directory .git sul tuo server web
  2. Sulla tua copia locale git remote add live ssh://[email protected]:port/folder
  3. Sul telecomando: git config receive.denyCurrentBranch ignore
  4. Sul telecomando: nano .git/hooks/post-receive e aggiungi questo contenuto:

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

  5. Sul telecomando: chmod +x .git/hooks/post-receive

  6. Ora puoi andare lì con git push live

Gli appunti

  • Questa soluzione funziona con versioni git precedenti (testate con 1.7 e 1.9)
  • Devi assicurarti di spingere prima su github / bitbucket, così avrai un repo coerente in diretta
  • Se la tua cartella .git trova nella root del documento, assicurati di nasconderla dall’esterno aggiungendo a .htaccess ( source ):

    RedirectMatch 404 /\..*$

Giddyup è un aghook git agganciato alla sola lingua per automatizzare la distribuzione tramite git push. Permette inoltre di avere ganci di avvio / arresto personalizzati per riavviare il web server, riscaldare la cache ecc.

https://github.com/mpalmer/giddyup

Guarda gli esempi .

Sembra che tu dovresti avere due copie sul tuo server. Una copia nuda, da cui puoi spingere / tirare, che potresti spingere le tue modifiche quando hai finito, e poi la clonerai nella tua directory web e configurerai un cronjob per aggiornare git pull dalla tua directory web ogni giorno o così.

Si potrebbe concepire un hook git che, quando si dice che viene eseguito un commit per dire il ramo “stable”, estrarrà le modifiche e le applicherà al sito PHP. Il grande svantaggio è che non avrai molto controllo se qualcosa va storto e aggiungerà del tempo ai tuoi test – ma puoi farti un’idea di quanto lavoro sarà coinvolto quando unirai dire il ramo del tronco nel ramo stabile per sapere quanti conflitti potresti incontrare. Sarà importante tenere d’occhio tutti i file che sono specifici del sito (ad esempio i file di configurazione) a meno che non si intenda solo eseguire il solo sito.

In alternativa hai invece cercato di spingere la modifica al sito?

Per informazioni sui git git vedere 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 [email protected]:/home/user/my_app && rm -rf $TMPDIR/deploy 
  • Archivia il ramo master in tar
  • Estrae l’archivio tar nella directory di distribuzione nella cartella temp di sistema.
  • rsync cambia nel server
  • elimina la directory di distribuzione dalla cartella temporanea.

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 il 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

Come risposta complementare mi piacerebbe offrire un’alternativa. Sto usando git-ftp e funziona bene.

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 si hanno più sviluppatori che accedono allo stesso repository, potrebbero essere d’aiuto le seguenti linee guida.

Assicurati di avere un gruppo unix a cui appartengono tutti gli sviluppatori e di dare la proprietà del repository .git a quel gruppo.

  1. Nel file .git / config del repository del server set sharedrepository = true. (Questo dice git per consentire a più utenti che è necessario per i commit e la distribuzione.

  2. impostare la umask di ciascun utente nei propri file bashrc per essere uguale – 002 è un buon inizio

Ho finito per creare il mio strumento di implementazione rudimentale che automaticamente estrapolava i nuovi aggiornamenti dal repository – https://github.com/jesalg/SlimJim – Fondamentalmente ascolta il github post-receive-hook e utilizza un proxy per triggersre un aggiornare lo script.

Io uso due soluzioni per il hook post-ricezione:

SOLUZIONE DI DEPLOY 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 

SOLUZIONE DI DEPLOY 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 sono basate su soluzioni precedenti disponibili in questo thread.

Nota, il BRANCH_REGEX = ‘^ $ {GIT_BRANCH1}. $ ‘filtra per i nomi dei rami che corrispondono alla stringa “master ” o “dev *” e distribuisce l’albero di lavoro, se il ramo premuto corrisponde. Ciò rende ansible 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 qualsiasi nuovo file dalla directory di produzione, che è stato aggiunto sul lato server, indipendentemente dal fatto che sia stato aggiunto al repository o meno. Sarà sempre pulito il duplicato del repository. È più lento di Deployment Solution 1.