Deploy with git: ovvero, come usare Git come strumento per gestire i deploy oltre che per versionare il codice. Questo articolo molto vecchio l’ho trovato originariamente nel blog di Kris Jordan ma mi è tornato utile adesso. Lo accomodo per il caso di mio interesse.
Ho un progetto in un host locale, un ambiente di produzione e un ambiente di staging al quale vorrei applicare in tempo reale le modifiche appena consegnate (commit) alla versione di sviluppo.
Questo aticolo, per arrivare a questo obiettivo, propone di creare un repository “bare” in remoto che serve solo per fare da tramite tra cartella di sviluppo in localhost e la cartella di deploy/stage in remoto, come illustrato nella figura 1

Questa metodologia è stata inizalmente sviluppata da Heroku.
Sommario
Deploy with git: preparazione dei repository
In questa versione personalizzata, a differenza dell’articolo di riferimento (nel quale si mette tutto in localhost):
- lasceremo il repository git “myProject” in localhost;
- creeremo il repository git “push” in mydomain.com
- la directory “stage” ovviamente in mydomain.com
come illustrato in Fig. 1.
me@localhost:$ cd IdeaProjects/myProject
Ora dobbiamo spostarci in remoto e qui è indispensabile avere l’accesso shell al server.
Qui inizializziamo un repository detto “bare” (nudo) che avrà solo la funzione di passamano tra il Git locale e la directory di deploy in remoto
me@localhost:$ ssh myUser@mydomain.com Password: myUser@remotehost:$ git init --bare myProjectPush.git
Questo repository myProjectPush.git non conterrà il codice sorgente, bensì farà da passamano tra il client Git a bordo del nostro server di sviluppo e la cartella di staging “stage” nel server di staging
Ora nel Git locale dobbiamo creare un riferimento al repository remoto di push che chiameremo “push” (magari non è la scelta più felice… ma basta fare attenzione):
me@localhost:$ git remote add push myUser@mydomain.com:myProjectPush.git
Il nuovo repository remoto lo troviamo scritto nel file .git/config:
... [remote "push"] url = myUser@mydomain.com:public_html/myProjectPush.git fetch = +refs/heads/*:refs/remotes/push/*
A questo dobbiamo istruire il Git remoto perché copi i file nella directory stage
Deploy with git: impostazione Push-to-Stage
Dopo aver creato il repository Git remoto dobbiamo scrivere un programma/script che istruisce git su come trattare i file che arrivano dal Git locale. Nella directory hooks della cartella myProjectPush.git ci sono gli script che Git lancia al verificarsi di un particolare evento. Ce ne sono già parecchi di esempio scritti in linguaggio bash, ma per questo scopo si può usare un qualsiasi linguaggio, nell’esempio che ho trovato è scritto in Ruby. Ma prima di tutto creiamo il file:
myUser@remotehost:$ cd myProjectPush.git/.git/hooks myUser@remotehost:$ touch post-receive myUser@remotehost:$ chmod +x post-receive
Il “gancio” che ci serve è quello che ci collega all’evento post-receive che è l’evento che accade quando il repository remoto riceve e accetta un push da parte di un repository di sviluppo. Quindi è necessario che il sistema operativo veda il file come uno script eseguibile.
Poi apriamo con l’editor che vogliamo il file post-receive e copiamo incolliamo questo programma Ruby (accertiamoci che l’interprete ruby sia installato con un comando “which ruby”)
#!/usr/bin/env ruby # post-receive # 1. Read STDIN (Format: "from_commit to_commit branch_name") from, to, branch = ARGF.read.split " " # 2. Only deploy if master branch was pushed if (branch =~ /master$/) == nil puts "Received branch #{branch}, not deploying." exit end # 3. Copy files to deploy directory deploy_to_dir = File.expand_path('../stage') `GIT_WORK_TREE="#{deploy_to_dir}" git checkout -f master` puts "DEPLOY: master(#{to}) copied to '#{deploy_to_dir}'" # 4.TODO: Deployment Tasks # i.e.: Run Puppet Apply, Restart Daemons, etc
Vediamo cosa fa questo script:
- Quando viene attivato lo script post-receive, Git gli passa in STDIN tre parametri: ID commit HEAD precedente, ID commit HEAD presente e il nome del branch da trasferire. Assegnamo questi tre valori alle variabili from, to e branch.
- Facciamo in modo che vengano pushati solo commit sul master branch (quello principale); questo sarebbe ragionevole per un push finale verso un server di produzione, ma io adotterò questa tecnica solo per lo staging, quindi rilasso questa parte (posso fare anche push di branch di bugfix per esempio).
- La prossima cosa da fare è fare un checkout dal branch attuale alla cartelle “stage”, cioè una copia dei file fisici nella cartella stage.
- Il lavoro è finito; sarebbe possibile completare lo script con comandi che dovessero rendersi necessari, come un restart del web server (se ne abbiamo la facoltà) o cancellare file di cache. Ma intanto mi fermo qui.
Salviamo il file e vediamo cosa succede.
Deploy with git: test con Pushing
Possiamo testare facendo un commit e un push verso il remote “push”:
me@localhost:$ git commit -m 'Test push-to-stage' me@localhost:$ git push push master muser@mydomain.com's password: Counting objects: 510, done. Delta compression using up to 4 threads. Compressing objects: 100% (477/477), done. Writing objects: 100% (510/510), 18.16 MiB | 148.00 KiB/s, done. Total 510 (delta 260), reused 0 (delta 0) remote: Already on 'master' remote: DEPLOY: master(915c38ce6cd49905ccff2abf4d9fea9a6ad61a3d) copied to '/home/myUser/domains/mydomain.com/public_html/stage' To mydomain.com:public_html/myProjectPush.git * [new branch] master -> master
Nell’output, le righe che iniziano con “remote:” sono quelle generate del nostro script! In particolare vediamo che è stata fatta la copia nella cartella stage.
That’s all folks!!
Commenti recenti