Come implementare Git su sistemi PHP legacy già in produzione senza downtime
A luglio 2025, il titolare di una PMI ligure - azienda di servizi logistici con 15 dipendenti e un gestionale PHP custom su VPS OVH - mi ha chiamato perché aveva "perso due giorni di lavoro". Il giorno prima, un collaboratore aveva modificato un file PHP direttamente in produzione via FileZilla per correggere un bug nel calcolo delle tariffe di spedizione. La modifica era sbagliata, il file precedente era stato sovrascritto senza backup, e il gestionale aveva calcolato tariffe errate per tutto il giorno prima che qualcuno se ne accorgesse. Il ripristino ha richiesto la ricostruzione manuale del file da un vecchio backup parziale - due giorni di lavoro del collaboratore più mezza giornata del titolare per verificare che le tariffe fossero corrette.
Quel tipo di incidente - modifica in produzione via FTP, nessun version control, nessun rollback possibile - è il pattern più comune che trovo nelle PMI italiane con applicazioni PHP legacy. Il gestionale funziona, il business dipende da quello, e ogni modifica è un rischio perché non esiste modo di tornare indietro. In cinque giorni ho implementato Git sul sistema esistente senza un minuto di downtime, e da quel momento ogni modifica è tracciata, reversibile e deployata con un singolo comando. In questo articolo ti racconto come.
Stai cercando un Consulente Informatico esperto per modernizzare il deployment del tuo applicativo PHP? Nel mio profilo professionale trovi l'esperienza concreta su Git, CI/CD e migrazione da FTP a deployment automatizzati. Contattami per una consulenza diretta.
Perché Git è il primo intervento su qualsiasi sistema PHP legacy?
Git non è uno strumento per sviluppatori moderni che usano framework alla moda. È una rete di sicurezza per chiunque modifichi codice in produzione. Senza version control, ogni modifica a un file PHP è irreversibile - se sbagli, l'unica speranza è un backup recente (che spesso non c'è, o non include il codice). Con Git, ogni stato del codice è registrato: puoi tornare indietro a qualsiasi punto, confrontare le differenze, e capire esattamente cosa è cambiato e quando.
La documentazione ufficiale di Git descrive il version control come "un sistema che registra le modifiche a un file o un insieme di file nel tempo, permettendo di recuperare versioni specifiche". Per un gestionale PHP in produzione, questa capacità è la differenza tra un incidente da due minuti (rollback) e un incidente da due giorni (ricostruzione manuale).
Giorno 1: backup, analisi e primo commit
Il primo giorno non si tocca nulla in produzione. Si analizza, si documenta, e si crea il punto di partenza sicuro.
# 1. Backup completo del codice di produzione
ssh user@server "tar -czf /root/backup-pre-git-$(date +%Y%m%d).tar.gz /var/www/html/"
# 2. Analisi della struttura
ssh user@server "find /var/www/html -name '*.php' | wc -l"
ssh user@server "du -sh /var/www/html --exclude=uploads"
# 3. Identificare cosa NON deve entrare in Git
ssh user@server "find /var/www/html -name '*.log' -o -name 'cache' -o -name 'uploads' -type d"Il .gitignore è il file più importante del primo commit - sbagliarlo significa committare credenziali, log enormi o upload degli utenti:
# .gitignore per applicazione PHP legacy
*.log
*.tmp
*.bak
/cache/
/tmp/
/uploads/
/storage/
config_local.php
.env
/vendor/
/node_modules/
*.sql
*.sql.gzL'inizializzazione di Git avviene direttamente nella directory di produzione - non in una copia separata. Questo approccio è controintuitivo ma corretto: Git non modifica nessun file esistente durante l'init, aggiunge solo la directory .git. L'applicazione continua a funzionare esattamente come prima.
cd /var/www/html
git init
git add .
git commit -m "chore: initial import of legacy codebase as-is"Quel commit è il tuo punto zero: da questo momento, qualsiasi modifica futura è registrata e reversibile.
Giorno 2-3: bare repository e deploy automatizzato con post-receive hook
Il passo successivo è creare un flusso di deploy strutturato. Non voglio più che nessuno modifichi i file direttamente sul server - le modifiche devono partire da un repository, essere committate, e arrivare sul server tramite un meccanismo controllato. La soluzione più semplice e robusta per sistemi PHP legacy è un bare repository con post-receive hook.
# Sul server: creare un bare repository separato dalla directory web
mkdir -p /home/gitdeploy/gestionale.git
cd /home/gitdeploy/gestionale.git
git init --bare
# Creare il post-receive hook
cat > hooks/post-receive << 'HOOK'
#!/bin/bash
set -euo pipefail
TARGET="/var/www/html"
BRANCH="main"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
echo "=== Deploy ${TIMESTAMP} ==="
# Backup pre-deploy (snapshot rapido)
tar -czf /root/pre-deploy-${TIMESTAMP}.tar.gz -C ${TARGET} . 2>/dev/null || true
# Checkout del codice nella directory di produzione
git --work-tree=${TARGET} --git-dir=/home/gitdeploy/gestionale.git checkout -f ${BRANCH}
# Fix permessi
chown -R www-data:www-data ${TARGET}
find ${TARGET} -type d -exec chmod 755 {} \;
find ${TARGET} -type f -exec chmod 644 {} \;
# Restart PHP-FPM (se necessario per OPcache)
systemctl reload php8.2-fpm 2>/dev/null || true
# Health check
if curl -sf -o /dev/null --max-time 5 http://127.0.0.1/; then
echo "=== Deploy OK ==="
else
echo "=== Deploy FAILED - rollback ==="
tar -xzf /root/pre-deploy-${TIMESTAMP}.tar.gz -C ${TARGET}
chown -R www-data:www-data ${TARGET}
echo "=== Rollback completato ==="
exit 1
fi
HOOK
chmod +x hooks/post-receiveIl post-receive hook fa quattro cose in sequenza: backup rapido dello stato attuale, checkout del nuovo codice, fix dei permessi, e health check. Se l'health check fallisce - il sito non risponde - il rollback è automatico. Nessun intervento manuale, nessun panico.
Sul PC dello sviluppatore (o del collaboratore), il workflow diventa:
# Aggiungere il remote di produzione
git remote add production gitdeploy@SERVER_IP:/home/gitdeploy/gestionale.git
# Deploy: un singolo comando
git push production main
# Il post-receive hook fa tutto il restoDa "modifica via FTP pregando che funzioni" a "push e il server fa il deploy con rollback automatico" - in un pomeriggio di configurazione.
Giorno 4: il rollback che funziona in 10 secondi
Il valore principale di Git non è il deploy - è il rollback. Quando qualcosa si rompe dopo un deploy (e prima o poi succede), la domanda è: quanto tempo serve per tornare allo stato precedente?
# Rollback istantaneo all'ultimo commit funzionante
# Sul server di produzione:
cd /var/www/html
git log --oneline -5 # vedere gli ultimi 5 commit
git checkout HEAD~1 # tornare al commit precedente
# Oppure a un commit specifico:
git checkout abc1234 # checkout di un commit specifico
# Dopo aver verificato che funziona:
git checkout -b hotfix-rollback # creare un branch per il fixNel caso ligure, il collaboratore ha fatto la stessa modifica sbagliata al file delle tariffe - ma questa volta con Git. Se ne è accorto dopo 20 minuti, ha scritto git checkout HEAD~1 sulla sua macchina locale e ha fatto git push production main. Il server è tornato allo stato precedente in 10 secondi. Quello che prima era costato due giorni di lavoro ora era un incidente da 20 minuti.
Giorno 5: formazione del team e workflow quotidiano
L'ultimo giorno è dedicato alla formazione. Il workflow che insegno ai team di PMI è volutamente semplice - niente feature branch, niente pull request, niente CI/CD complesse. Quelle arrivano dopo, quando il team ha interiorizzato le basi.
Il workflow quotidiano che ho insegnato al team ligure:
# Mattino: sincronizzare
git pull origin main
# Lavorare normalmente: modificare i file
# Prima di deployare: salvare lo stato
git add .
git commit -m "fix: corretto calcolo tariffe zona 3"
# Deploy in produzione
git push production mainTre comandi - pull, commit, push - che sostituiscono la sequenza "apri FileZilla, naviga nella cartella, sovrascrivi il file, prega". Il team ligure ha adottato il workflow in meno di una settimana, e dopo un mese il titolare mi ha detto: "non capisco come abbiamo fatto senza per cinque anni".
Per il passo successivo - aggiungere test automatici, analisi statica con PHPStan e refactoring incrementale - ho scritto un articolo dedicato su come recuperare il controllo di un codebase PHP legacy senza documentazione, e uno specifico sull'introduzione di test minimi su codebase PHP legacy che non richiede di riscrivere l'applicazione.
Git su un sistema PHP legacy non è un upgrade opzionale - è il primo intervento di sopravvivenza. Ogni giorno senza version control è un giorno in cui un singolo errore può costare ore o giorni di lavoro, senza possibilità di tornare indietro. Cinque giorni di setup, zero downtime, e da quel momento qualsiasi modifica è tracciata, reversibile e deployata in sicurezza. Se il tuo gestionale PHP è ancora su FTP, il costo di non migrare è enormemente superiore al costo di farlo. Contattami e facciamo il passaggio.