Sunt pus in urmatoarea situatie si as dori sa aflu o solutie eficienta si rapida in folosirea git-ului:
Am proiectul X ce este pe live.com, accelasi proiect este si pe test.com dar si pe local.
Se doreste sa se adauge/modifice sectiuni din proiect intai pe test.com, iar dupa aprobari sa fie mutat pe live.com
Cum ar trebuii procedat cu Git-ul in acest caz? (trebuie de tinut cont, ca altcineva poate modifica fisiere pe serverul live.com)
Ce se intampla cu baza de date? (Daca cineva insereaza o noua postare pe live.com, iar eu o alta postare pe test.com - si printr-o conincidenta acea postare sa primeasca accelasi ID)
Exista vreun VCS pentru baza de date? Si daca da, cum ar trebuii folosit in situatia de fata?
Nu stiu daca are vreo importanta, proiectul este pe platforma de wordpress si are destul de multe pluginuri installate. Iarasi, trebuie tinut cont: acele modificari pot dura si 30 min si nu cred ca este eficient sa tot mut fisierele de pe local pe test apoi pe live.
modificarile de db le tin in fisiere in proiect si le rulez inainte de merge/pull. e complexa treaba cu VCS-ul la db. iti poate manca ficatii ca hepatita.
sa zicem ca ai un feature nou, faci branch separat, il dezvolti, faci pull pe serverul de test la branch-ul respectiv, daca totul merge smooth, merge in master si deploy in productie.
D.p.d.v. al VCS pe baza de date, am făcut un git hook care salvează intr-un fișier structura bazei de date, și dacă ceva se modifică mai fac un commit care înregistrează modificarile din fișierul respectiv (gist cu hook-ul aici).
Poți face tot felul de hookuri când faci push pe serverul de dev să se execute un set de comenzi iar când faci push pe serverul live să se execute alte comenzi. Ca să te organizezi mai bine poți face si branchuri evident.
Da, ai branch master si branch test. Ideea e ca vei lucra pt fiecare task pe branch-uri separate.
Un flow ar fi - primesti task sa adaugi un buton (sa-i zicem butonul de Fericire).
din master creezi branch buton_fericire
lucrezi pe branch-ul nou creat (buton_fericire) unde adaugi modificarile tale pe cod
faci merge la branch-ul buton_fericire cu branch-ul test
pe serverul de test updatezi branch-ul test, care acum contine si modificarile din branch-ul buton_fericire si testezi
daca totul a fost ok la pasul 4, faci merge la branch-ul buton_fericire cu branch-ul master
testezi (in limitele posibile) si pe live sa fie totul ok
Ca si comenzi de git:
git checkout master
git pull origin master
git checkout -b buton_fericire
git add (lista cu fiecare fisier nou modificat)
git commit -m “Task buton fericire” (lista cu fiecare fisier modificat)
git push origin buton_fericire [optional]
git checkout test
git pull origin test
git merge buton_fericire
git push origin test
Pe serverul de test ai: git pull origin test
git checkout master
git pull origin master
git merge buton_fericire
git push origin master
Pe serverul de productie ai: git pull origin master
In ceea ce priveste update-ul bazei de date, asta cred ca in functie de fiecare platforma. Vor exista mereu diferente in privinta continutului generat de utilizatori.
Niște chestii care cred că scapă multora care sunt la început cu un VCS:
dacă folosești VCS nu mai editezi fișiere direct pe server (ftp, ssh sau orice altă metodă pică; singura metodă de a pune fișiere pe server va rămâne prin git)
sunt extrem de rare cazurile în care ai nevoie de aceleași date în DB atât în producție cât și în dev; dar pentru momentele în care este nevoie, îți recomand wp-db-migrate (au și o variantă pro care oferă chestii extra)
ce spune @andreitelteu este OK doar dacă ai un site micuț; la un site cu un DB de câteva sute de MB s-ar putea să dureze ceva toate operațiunile, iar la un eventual conflict ești un pic halit…
majoritatea (toate, dacă se poate!) dependințelor externe (plugin-uri, biblioteci php sau js) nu au ce căuta în repo și nu se instalează prin UI WP (vorbesc de plugin-uri). Folosește Composer, Bower, TGMPA.
Cum procedez eu:
plugin-urile sunt instalate exclusiv prin TGMPA. Deps de PHP prin Composer, cele de JS prin Bower.
un branch master pentru producție (push pe master ajunge live). Pe acest branch nu se face niciodată commit;
un branch dev pentru … development. Push aici și ajunge în stage;
lucrăm doar unul-doi oameni/proiect, deci șansele de a ne călca pe degete sunt destul de mici.
la mai mult de doi oameni aș folosi branch-uri pentru fiecare feature (iar commit pe dev ar fi interzis)
în mod curent fac commit pe dev, indiferent că-i bug sau feature¹.
dacă apar modificări la codul existent înainte de a termina un bug/feature, fac un branch nou din HEAD, git reset la ce este deja pe server, trimit hotfix, trec pe branch-ul nou. Când termin, îi fac merge în dev.
dacă e nevoie de sincronizarea datelor, folosesc db-migrate și copiez manual uploads (zip la wp-content/uploads e mai rapid decât transferul din db-migrate pro).
Combinația Stage - Producție
Aici e bine să vă decideți de la început cum procedați: stage-ul va fi o oglindă 1:1 a producției? Ori va fi doar un env de test? Dacă va fi o oglindă 1:1, recomand ca serverul live să fie extrem de limitat (i.e. orice modificare ce urmează a ajunge în producție va fi făcut exclusiv în stage, după care se migrează datele). După părerea mea, asta e o soluție greoaie, dar aplicabilă site-urilor foarte sensibile la greșeli/downtime.
Evident, serverul de staging va avea exact aceeași configurație ca producția: distro linux, pachete instalate, actualizări etc. Pentru asta poti folosi Ansible (sau orice alt utilitar de provisioning; nu mă ocup eu cu astfel de configurări, deci nu-ți pot da prea multe detalii)
Zilele trecute am avut un caz cu un plugin ce folosea imagemagick, care era instalat pe stage, dar nu în producție. Clientul se jura că ambele servere au aceeași configurație, eu insistam să verifice, a fost un ping-pong tare interesant
Modificarea fișierelor pe server
Una din metehnele de care am scăpat cel mai greu a fost editarea fișierelor direct pe server. În momentul în care folosești VCS renunți la acest obicei. (da, știu că am precizat asta mai sus, dar e una din chestiile care trebuiesc repetate)
¹Am încercat să folosesc git-flow, dar mi se pare un pic prea mult pentru ce am nevoie.
Sa incercam creionarea unui exemplu concret mai intai. Sa zicem ca aplicatia este una de blogging (similar wordpress.com) in care userii se autentifica, scriu articole care pot apartine de categorii, se pot adauga comentarii. Toate acestea sunt deja deployate pe www.live.com
Sa presupunem ca se doreste adaugarea facilitatii de taguire a articolelor. Dupa implementarea functionalitatii, se doreste furnizarea accesului unui anumit numar de utilizatori la ea, pentru a primi feedback. Asadar se doreste ca pe beta.live.com anumiti useri sa poata adauga articole in continuare, sa le poata eticheta, dar sa nu fie nevoiti sa introduca articolele si pe www.live.com inca o data.
Eu as propune sa abordam acest “tag blogposts” ca un feature mai mare, pe care sa il putem activa/dezactiva dupa necesitati. Asadar, ar trebui mai intai sa spargem functionalitatea pe pasi:
implementare feature tagging
deploy pe beta.live.com
implementare acces grup useri selectati (de ex trimitere newsletter si cei care doresc sa testeze aplicatia din beta sa trebuiasca sa dea click undeva in acel newsletter)
dezactivare feature tagging daca el nu este suficient de performant
Astfel vom putea folosi aceeasi baza de date:
------------------ ----------------
| db original | <------ | www.live.com |
| tabele pt tags | | server 1 |
------------------ ----------------
^
|
|____________________-----------------
| beta.live.com |
| server 2 |
-----------------
Abordarea pe care o propun eu se poate vedea de ex la compilarea PHP cu diverse flaguri (@see details) in care, atunci cand se face enable de ex la --with-pear se obtine o aplicatie care se comporta diferit decat cea compilata --without-pear (sau poate va place exemplul --disable-short-tags) si e vorba de acelasi PHP pe acelasi server
Asadar avem nevoie de
un flag in aplicatie care sa ne spuna daca e activat sau nu acest feature; de ex Wordpress permite definirea de constante pentru a indica alte tabele de user management decat ale sale proprii
Avantaje:
simplificam managementul de branchuri pentru ca deployem pe ambele servere (1 si 2) acelasi cod, doar cu setari de configurare diferite (pe unul activam noul feature, pe celalalt nu)
nu este necesara migrarea datelor de pe un server pe altul, pt ca folosim aceeasi baza de date
Dezavantaje:
timp mai mare de codare, pentru ca trebuie sa prevedem si dezactivarea facilitatii, precum si elimiarea ei din cod daca e nevoie
Nu am reusit sa gasesc in timp util linkul din documentatia de Symfony in care se detaliaza aceeasi abordare. Ei de obicei o explica mai bine ca mine. Revin.
Am gasit in sfarsit ce cautam. Se numeste “feature flagging”. Adicatelea se pune tot codul cu noul feature live, si se face enable/disable la el din configuratia aplicatiei. Desi codebase-ul e discontinued, e bun readme-ul de la acest repo github al Etsy pentru a intelege tehnica.