Commits parcials amb git

No us ha passat alguna vegada que mentre esteu escrivint alguna funció nova us adoneu que en una altra funció li falla alguna cosa? Llavors què feu? Un git stash abans de fer cap canvi a l’altre mètode i un cop el teniu arreglat un git stash pop?

Ja no cal!

Sabia que es podia fer però mai m’havia aturat a mirar com es feia:

git add -p

Amb aquesta ordre (i si voleu el fitxer o fitxers) afegireu a l’índex les parts del fitxer que vulgueu. D’aquesta manera si teniu dues parts modificades del codi en un mateix fitxer (la funció que estàveu fent i les quatre línies per arreglar un altre funció) no us cal fer cap cosa estranya per afegir només una part del fitxer, res de fitxers temporals, ni branques, ni deixar coses al porta-retalls, etc etc, senzillament fer una addició de pedaços (d’aquí ve el -p) .

Senzill i MOLT útil. Més de dues, tres i quatre vegades m’hagués estalviat una bona estona d’anar creant fitxers, deixant coses sense desar, etc etc si hagués sabut aquesta opció del git add :)

Script de migració de Subversion a git

Hi ha moltíssimes maneres de passar un repositori Subversion a git.

Ni molt menys és que sigui una tasca complexa, tot depèn de les bones pràctiques que s’hagin dut a terme en el Subversion.

A guifi.net hem decidit1 canviar del monolític Subversion de lafarga.cat a git. De moment ho enviarem a gitorious.org2, però això és el de menys. Al moment en que canvies a git, pots allotjar el codi allà on vulguis i canviar-ho els dies senars dels mesos parells si vols :)

Com que a lafarga.cat només teníem un sol repositori per el codi hi havia múltiples, fins a 15!, repositoris dins del mateix repositori i barrejats en diverses carpetes i demés.

Total, per sort l’historial en aquest cas no era crucial i amb un script que he creat ja s’està pujant el codi a gitorious.org :)

NOTA: encara no s’ha decidit una data oficial per abandonar lafarga.cat i abraçar de totes totes el git, serà aviat, esperem.

Els que tingueu ganes de jugar amb el git3 ja no teniu excusa que no hi ha codi real.

  1. De fet jo ho vaig decidir i ningú s’hi ha oposat de moment []
  2. En concret al projecte guifi de gitorious.org []
  3. Les diapositives que vaig utilitzar l’últim cop que en vaig parlar []

git show -3

L’opció show del git serveix per, tal com indica el nom, mostrar diverses coses, entre elles, i en el 99% dels casos, serà veure els commits ja fets.

Per exemple amb “git show” es mostrarà el diff de l’últim commit.

Per sort, com totes les ordres de git tenen moltíssimes variants, de manera que per exemple amb el títol de l’entrada “git show -3” el que farem es veure els tres últims commits per ordre cronològic invers (l’últim primer).

També podem afegir-hi el paràmetre –stat que permet mostrar un llistat de quins fitxers s’han canviat, de manera que es te una visió molt més ràpida del que s’ha fet en el canvi sense entrar en els detalls del diff com a tal.

Amb git show –help teniu tota la resta d’informació per si necessiteu fer altres coses :)

Llibre sobre git: Pro Git

Ahir mirant com fer el rebase del que vaig parlar em vaig trobar amb una web fantàstica: Pro Git.

Resulta que és la web del llibre homònim, on a més a més del llibre sencer també hi van publicant actualitzacions, consells i demés.

Sens dubte una pàgina de referència per a qualsevol que treballi a diari amb aquest fantàstic control de versions distribuït!

Com a mostra en el capítol 7 secció 2 ens ensenyen com combinar dos programes imprescindibles per mi: el git i el Meld.

git rebase: la història sencera

Introducció

Si treballeu amb git ja haureu sentit a parlar de l’ordre rebase. Per intentar-ho resumir1:

Suposem que has començat una branca de desenvolupament paral·lela a la branca principal, has fet uns quants commits i al mateix temps la branca principal també evoluciona amb uns quants commits.

En aquell moment les dues branques han divergit (tenen commits diferents) de manera que no pots enviar els canvis d’un  a l’altre de manera automàtica que sinó es perdrien els canvis que ja hi ha fets en l’altre branca.

Si vols integrar els canvis d’una branca a l’altre tens dues sol·lucions:

  • merge: combinar en un sol commit tots els canvis d’una branca per integrar-los en l’altra.
    • problema: s’ajunta en un sol commit tots els canvis de la branca, de manera que si els canvis són molt invasius és perjudicial a la llarga ja que no tens l’historial real dels commits que van portar a aquest super-commit.
  • rebase: actualitzar tots els commits de la teva branca perquè utilitzin la nova base de l’altra branca de manera que llavors sí que es puguin aplicar els canvis de forma directe
    • problema: es reescriu la història dels commits, ja que si els canvis que comporten la nova base a partir de la qual aplicar els commits toca els mateixos fitxers que els que un ha canviat en la seva branca es modifiquen els commits automàticament.

Una mica enrevessat oi? Mireu la documentació oficial del git sobre el rebase amb tots els dibuixets.

L’important, el codi

Ara bé, m’he trobat moltíssima documentació explicant el què, però no el com, així que aquí va una guia ràpida de les ordres per tal de fer un rebase:

git checkout BRANCH # anem a la branca que volem passar a master
git rebase MASTER # fem el rebase (si trobem conflictes els anem sol·lucionant)
git push -f # envies els canvis al servidor (el -f és degut a que forces el push)
git checkout MASTER # tornem a la branca master
git pull origin BRANCH # ara ja podem agafar els canvis de la branca BRANCH sense cap problema
git push # enviem al servidor la branca master amb tots els canvis de la branc BRANCH aplicats

I amb això ja teniu tot el necessari per poder treballar amb branques i fer-ne després rebase d’aquestes.

Tingueu en compte el fet aquest de la reescriptura de la història. De per si no és dolent, el principal problema és que si la branca en la que estàs treballant també l’utilitza algú altre, aquest altre tindrà problemes quan torni a fer una actualització del codi.

Si pel contrari treballeu amb aquesta branca únicament vosaltres no tindreu absolutament cap problema i, sens dubte, serà la millor manera de preservar tot els commits i per tant molt més senzill de navegar per l’historial.

  1. Hi ha moltíssima lectura []

Sincronització de branques a git

És box-populi que treballar amb branques amb git és una delícia ja que ho facilita moltíssim: és molt ràpid i les eines que et posa a disposició per treballar-hi fan que sigui molt recomanable fer-ho per a qualsevol canvi que es vulgui fer en el codi d’una aplicació.

Ara bé, quan ja has fet els canvis que volies fer-hi com els sincronitzes cap a la branca master1 ?

Tens dues opcions, la que utilitzava jo fins ara:

git checkout master
git diff –stat master..BRANCA_DEV
git merge master..BRANCA_DEV
git push

Amb això el que obtenim és que agafem tots els canvis que hi ha a BRANCA_DEV respecte de master i els mescla. A més a més per deixar-ne constància en fa un commit final amb la típica frase2Merge branch ‘BRANCA_DEV’ into master“.

Ara bé, hi ha una manera més bonica i més elegant de fer-ho, rebase:

git checkout master
git rebase BRANCA_DEV
git pull
git push

Amb això el que estem fent és agafar els canvis de la branca BRANCA_DEV i els col·loca, en bloc, abans dels canvis que tinguem fets a la branca master. Això vol dir que si partim d’un commit X i fem tres canvis a la branca BRANCA_DEV i dos canvis a la branca master, quan executem les ordres de sobre el farà el git és reiniciar els commits fins al commit X, aplicar consecutivament els 3 commits de BRANCA_DEV i finalment un cop fet això aplicarà els nostres dos canvis a la pròpia branca master.

D’aquesta manera, sigui quin sigui el mètode utilitzat per sincronitzar les branques ja tindreu una manera molt fàcil de treballar amb diverses branques alhora, etc etc

  1. Així és com es diu la branca principal a git. []
  2. Com tot en el git es pot canviar []

git show(1)

No us heu trobat mai amb la necessitat de veure els canvis que s’han fet en un commit? Res més senzill que fer un git log per agafar el SHA1 del commit en qüestió i després fer un git show SHA1.

Evidentment com qualsevol altre ordre de git pot fer molt més que només mostrar els canvis fets en un commit, ja que la descripció que se’n dóna en fer un git help show és: Mostra diversos tipus d’objectes.

administració de servidors i git

Fins que no proves les coses no te n’adones de lo difícil, o fàcil, que és fer-les…

Avui havia de fer uns canvis a un dels servidors de la feina i com que eren temes de configuració … cd /etc

Però abans de prémer cap més tecla m’ho he pensat dues vegades i he teclejat unes quantes ordres ben senzilles i  molt útils de cara al futur:

Control de versions de la configuració d’un servidor

Sembla que pugui ser una cosa difícil, que requereixi molt de temps i que sigui complex de mantenir oi? Doncs res més senzill que fer:

cd /etc
git init
(opcionalment vim .gitignore per excloure els fitxers que no volem versionar)
git add -A
git commit -m"Configuració inicial que funciona del servidor"

Només amb aquestes senzilles ordres ja tenim tot el directori /etc versionat amb git. A partir d’ara qualsevol canvi a qualsevol fitxer que estigui dintre de /etc ens sortirà amb un git status i quan haguem fet les proves necessàries per assegurar que els canvis són correctes ja podrem fer un git commit FITXER1 FITXER2 -m”Missatge” per tenir controlada una nova revisió dels fitxers.

Ara ja no hi ha excusa per dir que s’ha perdut alguna configuració o que s’ha espatllat algun servei del servidor, sempre tindràs un git checkout o un git reset –hard HEAD per tornar a una versió dels fitxers de configuració correcta :)

git stash

Una de les primeres coses que descobreixes quan utilitzes git és que de la mateixa manera que un mediawiki, per posar un exemple, hi ha mil i una maneres de treballar-hi:

Tot amb branques, arbres remots a github, via pedaços (com se solia anar amb subversion i cvs) …

De manera que igual com amb un mediawiki el més important és definir una bona guia d’estil, les plantilles i el sistema de categorització, treballant amb el git, el més important és definir dintre de l’equip de treball un bon cicle de treball per tal que no hi hagi diverges

I és aquí on entra l’ordre git stash.

Un exemple ben fàcil: tens canvis a 5 fitxers diferents, fas un commit per a tres d’ells perquè els altres dos encara no estan llestos per enviar.  Si en aquell moment vols fer un git pull –rebase perquè el servidor de git és un servidor central i vols agafar els últims canvis i aplicar-hi els teus commits locals a sobre de les últimes actualitzacions, el git no et deixarà fer-ho, ja que hi ha canvis sense estar en un commit.

No pots fer-ne un commit perquè no estan acabats, de manera que el que pots fer és un git stash, que senzillament desa els canvis que no estan a cap commit i et deixa l’arbre sense cap fitxer que no estigui en un commit, de manera que ja pots fer un git pull –rebase i si tot va bé un git push per enviar els teus commits locals.

Ja només et queda fer un git stash pop per recuperar els canvis que tens que no estan a cap commit i continuar treballant tranquilament :)

Evidentment, com tota eina de git, el git stash et permet fer moltíssimes coses més, de fet per tal com es recupera la sessió desada (git stash pop) ja podeu veure que el git stash funciona com una pila, de manera que pots tenir tants stash com necessiteu1 i aplicar-los a altres branques, o crear branques a partir dels stash, etc etc …

  1. No exempt de perill que després no funcionin sobre el commit en el que esteu treballant []