Easily extract commits from a messed up branch

Once in a while you encounter branches that are have been over-used, i.e. multiple persons added commits there for unrelated issues.

How to get around/solve that? I’m glad you ask :-)

Today I was facing something similar at work, where the messed up branch in question had some commits already merged into master but there were some important other parts to be extracted from it.

So I used three tools:

  • git log --graph --decorate --pretty=oneline --abbrev-commit --all (with an alias git fulllog)
  • a git graphical visualizer (gitg for instance)
  • a simple plain text editor (gedit for instance)

Workflow

Fire up git fulllog in a terminal and copy & paste as much information as you need into the text editor.

Fire up the git graphical visualizer and check each relevant commit what’s doing.

Once you know what it is about annotate each commit so you know which commits relate together, i.e. from

ae0ee04 My commit message

to

ae0ee04 11111 My commit message

This way once everything is annotated is really simple to just grab all the 11111 commits and git cherry-pick them in a new branch :-)

Pro tip: as you are editing a plain text file you can keep removing lines and adjusting the indentation, suddenly you realize how things keep fitting together!

Done!

Testing multiple pull requests at once

It probably happened to you, dear reader, every now an then: the new feature you are working on has changes across more than one git repository, so how can this be tested to make sure nothing is broken before merging those nth separate pull requests?

That’s what #126 was about and finally, thanks to WPOD and the company I work for to allowing me take part of it, it’s finally fixed.

Let us know if it does not work as expected!

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 decidit ((De fet jo ho vaig decidir i ningú s’hi ha oposat de moment)) canviar del monolític Subversion de lafarga.cat a git. De moment ho enviarem a gitorious.org ((En concret al projecte guifi de gitorious.org)), 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 git ((Les diapositives que vaig utilitzar l’últim cop que en vaig parlar)) ja no teniu excusa que no hi ha codi real.

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 resumir (( Hi ha moltíssima lectura )):

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.

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 master ((Així és com es diu la branca principal a git.)) ?

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 frase ((Com tot en el git es pot canviar)) “Merge 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

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.