# Android/Control de versions VCS amb Android Studio
## Introducció

Android Studio permet integrar diferents sistemes de control de versions (VCS en anglès) tals com Git, GitHub, CVS i Mercurial entre altres. Donat que l'Android Studio ha estat desenvolupat en part per l'empresa JetBrains, la gestió d'aquests sistemes és pràcticament idèntica a altres entorns de desenvolupament (IDE) de la companyia. En aquest capítol, trobarem una descripció de com gestionar a partir de la interfície de l'Android Studio, els procediments més comuns relacionats amb els diferents sistemes de control de versions.

### Què són els VCS?

En l'àmbit de l'enginyeria del software, els sistemes de control de versions són una eina que ajuda al desenvolupador o a un equip de desenvolupadors a gestionar els canvis que es produeixen en el seu codi font al llarg del temps. Aquests sistemes permeten fer un seguiment i enregistrar en una espècie de base de dades, les modificacions que es va fent del codi. D'aquesta manera, en el cas que hi hagi algun problema, els programadors poden comparar les diferents versions o fins i tot restaurar-ne alguna en el cas que fos necessari.
A banda del seguiment de les pròpies modificacions, on més es noten els beneficis del control de versions és en el desenvolupament en equip on diferents programadors reescriuen el codi contínuament. Normalment, en desenvolupar un projecte el codi s'organitza en una estructura de carpetes o "arbre de fitxers". De tal manera que un desenvolupador de l'equip pot estar treballant amb el codi d'un d'aquests fitxers i un altre fer-ho en un altre, cosa que ens permet distriubuir i alhora centralitzar el nostre desenvolupament. Per evitar els conflictes derivats de desenvolupar de forma concurrent (modificacions del mateix fitxer per diversos desenvolupadors), el VCS rastreja en tot moment cada canvi individual de cada desenvolupador.

### Tipus de VCS

Podem distingir els sistemes de control de versions amb els tipus següents:
* Locals. Es caracteritzen per mantenir una base de dades on es registren tots els canvis realitzats sobre un mateix fitxer. Per tant, aquest sistema no permet mantenir un registre de les contribucions d'altres desenvolupadors.
* Centralitzats (Centralized Version Control Systems o CVCS en anglès). Aquests sistemes es caracteritzen per tenir tot el registre de versions bolcades en un únic servidor. A diferència dels locals, aquest sistema si permet la col·laboració de diferents desenvolupadors. Són més fàcils d'administrar ja que no s'han de gestionar les bases de dades locals de cada client. Tot i així, l'inconvenient principal d'aquests sistemes és, com és obvi, que si el servidor cau o no és accessible les diferents parts ja no poden col·laborar ni guardar els canvis realitzats.
* Distribuits (Distributed Version Control Systems o DVCS en anglès). A diferència dels centralitzats, els clients no solament descarreguen una instantània dels fitxers sinó que repliquen completament el repositori. D'aquesta manera, es garanteix que si un servidor cau, qualsevol dels repositoris dels clients que hi col·laboraven poden restaurar el repositori en el servidor.

### Taula de Terminologia freqüent

Tot i que la terminologia pot variar en funció del tipus de sistema de control de versions que s'utilitzi, la majoria dels termes següents descriuen processos o operacions comunes.
| Terme | Descripció |
| Repositori | El repositori és el lloc on es guarden els fitxers de les diferents versions d'un projecte. Normalment, aquests fitxers són emmagatzemats en un servidor o en el propi disc dur. |
| Mòdul | Conjunt de directoris o fitxers d'un repositori que formen part del mateix projecte. |
| Revision o version | Una revisió és una determinada versió del nostre repositori. En la majoria de sistemes de control de versions, cada revisió té associat un identificador únic. Per exemple, git identifica les revisions mitjançant un codi SHA1. |
| HEAD | Terme que s'utilitza per identificar l'última versió. És a dir, a l'últim commit realitzat. Cada branca d'un projecte té el seu propi head. |
| Tag o Label | El tag serveix per identificar una determinada versió amb un nom en concret per tal de diferenciar-la i accedir-hi posteriorment amb aquest nom. A diferència del HEAD, el tag no s'actualitza a mesura que anem fent commits. |
| Master | Terme que acostuma a utilitzar-se per referir-se a la branca per omissió d'un repositori. Per exemple, en sistemes de control de versions com el Git, en crear un repositori es crea una branca activa amb aquest nom de forma automàtica. |
| Commit | Un commit és quan es copien al repositori els canvis realitzats localment. |
| Baseline | Correspon a una versió que s'agafa com a punt de partida per tal de realitzar modificacions posteriors. |
| Branch | Una branca representa una línia de desenvolupament diferent que sorgeix a partir d'una mateixa base. D'aquesta manera, cada branca evoluciona de forma independent. |
| Merge | Un merge és una operació d'integració en el que dos conjunts de canvis s'apliquen sobre un fitxer o un conjunt de fitxers. Això pot passar en els escenaris següents: Un usuari actualitza o sincronitza la seva còpia de treball amb els canvis realitzats i registrats al repositori per part d'altres usuaris. Quan es fusionen dues línies de desenvolupament independents. És a dir, s'ajunten dues branques del repositori. |
| Checkout (Desplegar) | Correspon al procés d'importació en un entorn local dels fitxers d'una versió del repositori, normalment la HEAD. |
| Update o Sync | Actualitza els canvis que s'hagin realitzat al repositori en la nostra còpia local del repositori. |
| Pull, Push | Correspon al procés de copiar versions d'un repositori a un altre. Push s'utilitza per descriure el fet de carregar un repositori local a un repositori remot. Mentre que pull s'utilitza per descriure el procés invers. |
| Clone | Com el seu nom indica, la clonació descriu el fet de crear un nou repositori que és una còpia d'un altre. |

### Beneficis d'utilitzar VCS

Els principals beneficis que s'obtenen a l'hora d'utilitzar sistemes de control de versions són els següents:
* Facilita la distribució del codi. El software és més accessible, el que permet l'aprofitament i contribució d'altres usuaris.
* Permet mantenir una còpia de seguretat del software sense cap cost.
* Ramificació i fusió. La creació de fluxos de treball independents impedeix que els canvis de cada branca causin algun tipus de conflicte.
* Traçabilitat. En tot moment podem visualitzar l'evolució del nostre projecte.

## VCS compatibles

L'Android Studio ens permet la integració de diferents sistemes de control de versions. La seva gestió i configuració a través de la interfície és similar però poden variar algunes coses en funció del sistema que s'utilitzi. La llista de sistemes compatibles és la següent:

### VCS local

* Local History

### VCS remot

* CVS
* Basats en Git. Com per exemple, GitHub o BitBucket.
* Mercurial
* Subversion

## Opcions de configuració VCS

En l'apartat de Settings podem accedir a la configuració de tots els paràmetres que estan relacionats amb el sistema de control de versions. Podem accedir-hi realitzant els passos següents:
* Amb un projecte obert: File | Settings | Version Control
* Abans d'obrir o crear un projecte: Configure | Settings | Versions Control

### Configuració d'opcions generals

Corresponen a tots aquells paràmetres que s'apliquen a tots els sistemes de control de versions compatibles amb Android Studio. Aquests paràmetres són els següents:
* Confirmation. Permet especificar quines accions relacionades al VCS requereixen la nostra confirmació. Per especificar-ho realitzem els passos següents:
* En l'apartat Versions Control, seleccionem l'opció Confirmation.
* En l'àrea Display options dialog when these commands are invoked, s'especifica per quines ordres es mostrarà el quadre de diàleg d'opcions. Les opcions disponibles són: Add, Remove, Checkout, Update, Status i Edit.
* En l'àrea When files are created/deleted, es defineix si s'han d'afegir o treure els fitxers del VCS en el cas que s'elimini o es creï un fitxer. Les opcions disponibles que tenim són:
       - Show options before adding/removing to version control. Ens permet triar l'opció en el moment en què es produeixi la situació.
       - Add silently. Afegir/Eliminar directament.
       - Do not add. No afegir/eliminar.
* Ignored files. Aquesta opció és accessible quan tenim un projecte vinculat al VCS. Permet crear un llistat de fitxers que seran ignorats pel VCS. Aquesta funció és útil per deixar fora del sistema de versions aquells fitxers que no són rellevants per un projecte, com poden ser fitxers de configuració personal, còpies de seguretat, etc. Cal tenir en compte que un cop s'ha afegit un fitxer al sistema de control de versions, ignorar-lo no tindrà cap efecte. En aquest cas, per poder-lo ignorar primer caldria eliminar-lo del VCS.
Per definir un llistat d'arxius ignorats fem el següent:
* En l'apartat Versions Control, seleccionem l'opció Ignored files.
* Per crear una nova entrada, cliquem sobre l'icona (+) o la combinació de tecles (Alt+Insert). També podem eliminar (Alt+Supr) o editar (Enter) una entrada existent.
* En crear una nova entrada,apareixerà un nou quadre de diàleg en el qual podrem marcar les següents opcions:
       -Ignore specific file. Aquesta opció ens permet ignorar un fitxer en concret.
       -Ignore all files under. Ens permet especificar un directori per tal d'ignorar tots els fitxers que hi estiguin dins.
       -Ignore all files matching. Aquesta opció ens permet definir un patró que defineixi els noms dels fitxers que cal excloure.
* Background. Permet especificar quines accions es poden realitzar en segon pla.
* Changelist Conficts. Igual que l'opció anterior, aquesta opció sols és accessible un cop tenim un projecte vinculat al VCS. Permet definir les accions que es durant a terme amb els fitxers en el cas de trobar conflictes entre diferents revisions.
* File status color. Permet definir colors per tal de definir l'estat de cada fitxer del projecte segons les accions VCS que s'hi hagin dut a terme.

### Configuració d'opcions específiques

Alguns dels paràmetres de les opcions de configuració del control de versions estan relacionats amb els diferents VCS que pot integrar l'Android Studio. Això ens permet configurar opcions concretes de cadascun d'aquests sistemes. Per configurar aquestes opcions, realitzem els passos següents:
* En l'apartat Versions Control, seleccionem l'opció que correspongui al sistema VCS que estiguem utilitzant.
* Configurar les opcions segons sigui necessari.

## Activació del VCS

Per habilitar la integració de control de versions amb l'Android Studio, cal complir les condicions seguents:
* A nivell d'IDE, és necessari tenir instal·lats i activats un conjunt de plugins. Aquests plugins s'activen i instal·len per omissió en instal·lar l'Android Studio. Tot i així, si no ho estan es poden activar en l'apartat plugins del quadre d'opcions.
* A nivell de projecte, la intregració VCS s'habilita associant carpetes del projecte a un o diversos sistemes de control de versions.

### Associar l'arrel d'un projecte a un VCS

Un cop creat un nou projecte, des de l'editor podem activar ràpidament la integració d'un projecte a un VCS realitzant els passos següents:
* Clicar l'opció VCS de la barra d'opcions superior de l'editor, i seleccionar Enable Version Control Integration.
* En el quadre de diàleg que apareix en activar la integració, seleccionar el sistema de control de versions que volem associar a l'arrel del nostre projecte.

### Associar un directori a un VCS

L'Android Studio també admet un model de versió basat en directoris, el que significa que cada directori del projecte es pot associar a un sistema de control de versions diferent. Per fer-ho cal seguir els passos seguents:
* Obrim el quadre d'opcions del control de versió (File | Settings | Version Control). En aquest quadre d'opcions podem observar una llistat de directoris del nostre projecte i amb quin VCS estan associats (si no se n'ha associat cap, la llista només conté l'arrel del projecte).
* Cliquem sobre el botó (+) o introduïm la combinació de tecles (Alt+Insert).
* En el quadre de diàleg que ens apareix, escollim el directori del nostre projecte i seleccionem el VCS desitjat. En aquest apartat també podem associar l'arrel del nostre projecte.
* Apliquem els resultats clicant en el botó Ok | Apply.
Aquest mètode ens permet també canviar a posteriori el VCS associat a un directori o a l'arrel del nostre projecte.

## Administració de fitxers sota el VCS
### Comprovació de l'estat dels fitxers

L'Android Studio ens proporciona una finestra que ens permet comprovar de forma ràpida l'estat de la nostra còpia de treball local respecte l'última versió del nostre repositori. D'aquesta manera, podem visualitzar quins fitxers han estat modificats, quins fitxers s'han afegit al VCS, i quins fitxers no estan sent versionats.
Per visualitzar aquesta informació, obrim la finestra Version Control (Alt+9) i seleccionem la pestanya Local Changes:
    - En el llistat de canvis Default mostra tots els fitxers que s'han modificat des de l'última sincronització amb el repositori remot (ressaltats en blau) i tots els fitxers nous que s'han afegit al VCS però que encara no s'ha fet cap commit (ressaltats de color verd).
    - En el llistat Unversioned Files, es mostren aquells fitxers que formen part del nostre projecte però que no n'estem fent un seguiment. És a dir, que no hem afegit al nostre repositori local.
    - Per altra banda, a la part esquerra d'aquesta finestra tenim una barra d'opcions on podem dur a terme accions associades al VCS a nivell de fitxer.
Entre les més útils, tenim:
   * - Aquesta opció ens permet fer un commit de tots els fitxers de la llista Default o d'un fitxer en concret si el seleccionem.
   * - Aquesta opció ens permet visualitzar a nivell de fitxer les parts diferents respecte al fitxer del repositori.
   * - Amb aquesta opció podem revertir els canvis realitzats al repositori local i tornar a l'última versió del repositori remot.

#### Taula de colors i l'estat que representen

| Color | Estat del fitxer | Descripció |
| Negre | Actualitzat | El fitxer no ha canviat. |
| Gris | Eliminat | El fitxer està programat per a l'eliminació del repositori. |
| Blau | Modificat | L'arxiu ha canviat des de l'última sincronització. |
| Verd | S'ha afegit | El fitxer està programat per ser afegit al repositori. |
| Violeta | Merged | El fitxer ha estat fusionat pel VCS com a resultat d'una actualització. |
| Oliva | Ignorat | El fitxer serà ignorat en qualsevol operació del VCS. |
| Vermell | Merged amb conflictes | Durant l'última actualització, el fitxer ha estat fusionat amb algun conflicte. |
| Marró | Unversioned (No versionat) | El fitxer existeix localment, però no existeix en el repositori ni tampoc s'ha afegit per a la seva addició. |
| Lila | Esborrat externament | El fitxer ha estat eliminat localment, però no s'ha programat la seva eliminació, i existeix encara al repositori CVS. |
| Cian | Switched | S'ha agafat el fitxer d'una branca diferent al del projecte sencer. Aquest estat només és aplicable per sistemes CVS. |

### Addició de fitxers

Un cop tinguem activada i associada la integració VCS al nostre projecte, cada cop que es creï un nou fitxer en el projecte, l'Android Studio ens demanarà si el volem afegir automàticament (Aquest comportament es pot canviar en l'apartat d'opcions Confirmation). Tot i així, per afegir fitxers que no han estat versionats al nostre repositori local oh podem fer de diverses maneres seguint aquests passos:
* Obrim la finestra Control Version ( Alt+9 ) i seleccionem la pestanya Local Changes.
* A continuació, seleccionem el fitxer o els fitxers dins de la llista Unversioned Files i per afegir-los, cliquem amb el botó dret del ratolí i seleccionem l'opció Add to VCS o teclegem la combinació de tecles Ctrl+Alt+S.
Per altra banda, si volem mantenir certs fitxers no versionats, podem configurar el nostre VCS per tal d'ignorar-los.

### Eliminació de fitxers

Si eliminem un fitxer que està sota un VCS local, el fitxer encara existeix en el nostre repositori remot fins que es realitza un commit. En aquest cas, el fitxer esborrat apareixerà dins la llista Default ressaltat de color gris. Per tant, el procés per eliminar un fitxer ,tant del nostre repositori local com en l'extern, és el següent:
* Seleccionem el fitxer des de la finestra on es mostra l'arbre de directoris del nostre projecte, i premem la tecla (Del).
* En la nova finestra que ens apareix, podem triar si volem esborrar el fitxer sense cercar possibles dependències, o realitzar una "eliminació segura" marcant l'opció de Safe Delete. Amb aquesta opció, en el cas que es detecti una dependència es mostrarà una nova finestra on podrem visualitzar aquestes dependències i d'aquesta manera, eliminar-les abans d'esborrar el fitxer.
* Finalment, realitzem un commit per fer efectiva l'eliminació del fitxer en el nostre repositori.

## Comparació de Versions

A part de comparar un fitxer modificat respecte al que tenim en el repositori, també podem comparar fitxers d'una versió a una altra o de branques diferents. Aquestes diferències es poden visualitzar en la finestra Differences Viewer. Per obrir aquesta finestra ho podem fer de les formes següents:

### Comparació de la versió actual d'un fitxer amb una versió seleccionada de la mateixa branca.

* Seleccionar el fitxer en la finestra on es mostra l'arbre de directoris del nostre projecte, seleccionar les opcions VCS | <nom_vcs_utilitzat>;; | Compare with del menú d'opcions de l'Android Studio.
* Escollir en la nova finestra que apareix, la versió amb la qual volem comparar la nostra versió actual.

### Comparació de la versió actual d'un fitxer amb una altra branca.

* Seleccionar el fitxer en la finestra on es mostra l'arbre de directoris del nostre projecte, seleccionar les opcions VCS | <nom_vcs_utilitzat>;; | Compare with Branch del menú d'opcions de l'Android Studio.
* Escollir en la nova finestra que apareix la branca amb la qual volem comparar la nostra versió actual.

## Resolució de conflictes

Segons el sistema de control de versions que estiguem utilitzant, es poden produir conflictes en diverses situacions.
Quan es treballa amb un projecte que implica diferents persones, ens podem trobar en la situació en què algú realitzi canvis en un fitxer en el qual estem treballant. Si aquests canvis no se superposen (és a dir, s'han realitzat canvis en línies diferents del codi), es produeix un merge dels fitxers conflictius automàticament. Tanmateix, si les mateixes línies es veuen afectades, el VCS sota el que estem treballant no pot escollir aleatòriament un sobre l'altre i es demanarà la nostra intervenció per resoldre aquest conflicte.
Els conflictes també poden aparèixer durant un merge o rebase d'alguna branca.

### Sistemes de Control de versions no Distribuïdes

Quan s'edita localment un fitxer que té una nova versió en el servidor del repositori del nostre VCS, l'Android Studio ens informarà d'això mostrant-nos el següent missatge en la part superior de l'editor.
En aquest cas, el més recomanable seria actualitzar la nostra versió local abans de realitzar qualsevol canvi en el fitxer.
En el cas d'intentar fer un commit d'un fitxer que té una versió més recent en el repositori, el commit fallarà i es mostrarà un missatge d'error en la part inferior de l'editor on s'indicarà que el fitxer del nostre commit està desactualitzat. Si intentem actualitzar un arxiu que ja té canvis locals amb el d'una versió més recent del nostre repositori, es produirà també un conflicte. En aquest cas, l'arxiu obtindrà l'estat de merged with conflicts.

### Sistemes de Control de Versions Distribuïdes

En els sistemes de control de versions distribuïdes, com Git i Mercurial, els conflictes es produeixen quan hem fet un commit en el repositori local d'un fitxer que té canvis en les mateixes línies de codi que la versió més recent del repositori extern, i intentem dur a terme algunes d'aquestes operacions: pull, merge, rebase, etc.
En aquest cas, les operacions fallaran i haurem de decidir entre acceptar la nostra versió, la del repositori extern o fer un merge manual dels canvis.
L'Android Studio ens proporciona una eina que ens permet resoldre conflictes manualment de forma ràpida. Aquesta eina és similar a la finestra Differences Viewer, però en aquest cas la finestra es divideix en tres parts. A l'esquerra se'ns mostren els canvis realitzats localment al fitxer i a la dreta, el fitxer de la versió del servidor. En la part central, tenim un editor en el qual podem definir la resolució d'aquests conflictes i visualitzar-ne el resultat.
Per obrir aquesta eina, fem el següent:
* Cliquem l'opció Merge... en la finestra Files Merged with Conflicts, o seleccionant el fitxer conflictiu i seleccionar les opcions VCS | <nomVCS_escollit>;;; | Resolve Conflicts del menú d'opcions de l'Android Studio.
* Ressolem els conflictes manualment escollint en cada cas, l'acció a realitzar.
* Revisar els resultats en el panell central i aplicar els canvis clicant Apply.

## Gestió de Changelists

Una Changelist és un conjunt de canvis locals que encara no s'han afegit al repositori VCS.
Tots els canvis realitzats als fitxers del nostre projecte es col·loquen automàticament a la changelist activa. Normalment aquesta changelist es crea de forma automàtica, però podem crear-ne de noves i marcar-les com a changelist activa.

### Creació d'una Changelist

Per crear una nova Changelist realitzem els passos següents:
* En la pestanya Local Changes de la finestra Version Control (Alt+9) clicar sobre la icona (+).
* En la nova finestra New Changelist que apareix, especificar-ne el nom, i opcionalment una descripció o marcar-la com a Changelist activa.

### Establir una Changelist activa

Per marcar com activa una Changelist, fem el següent:
* Seleccionem la Changelist en la pestanya Local Changes de la finestra Version Control i cliquem sobre la icona que apareix al menú d'opcions de la finestra. Automàticament, tots els fitxers modificats se situaran en la nova Changelist.

### Moure fitxers entre Changelists

Per moure fitxers entre diferents Changelists ho farem de la forma següent:
* Seleccionem els fitxers que volem moure en la pestanya Local Changes de la finestra Control Version.
* Cliquem sobre la icona que apareix a la barra d'accions de la finestra.
* En la nova finestra que apareix, seleccionem una Changelist existent o escrivim el nom d'una de nova. De forma opcional, també podem marcar-la com activa.

## Actualització

L'ordre d'actualització permet sincronitzar el contingut dels fitxers locals amb el repositori. Per actualitzar el projecte actual:
* Cliquem sobre la icona que apareix en la barra d'accions de la part superior de l'Android Studio o prémer la combinació de tecles (Ctrl+T).
* Especifiquem les opcions d'actualització, que poden variar en funció del VCS utilitzat, i cliquen en OK.

## Utilització dels Patches

En comptes de fer commits dels canvis realitzats del nostre espai de treball local, podem posar aquests canvis en un fitxer de tipus .patch per tal d'aplicar-los al nostre projecte posteriorment, enviar-los per correu, etc.

### Creació d'un Patch

Per crear un nou Patch fem els passos següents:
* Obrim la finestra Version Control (Alt+9) i seleccionem la pestanya Local Changes.
* Seleccionem un fitxer o una Changelist sota la qual volem crear un Patch.
* A la nova finestra que apareix, ens assegurem de tenir seleccionats tots els fitxers que tenen els canvis que volem guardar. Introduïm opcionalment una descripció i cliquem sobre el botó Creat Patch per crear el Patch amb els canvis.
* En la nova finestra que apareix Patch file Settings, modifiquem la ruta de destinació del fitxer .patch en cas de ser necessari i per generar el fitxer cliquem en el botó Accept.

### Aplicar un Patch

Per aplicar els canvis que han estat guardats en un fitxer .patch al nostre codi, fem els passos següents:
* Seleccionem les opcions VCS | Apply Patch en el menú de l'Android Studio.
* A la nova finestra que apareix, especifiquem la ruta del fitxer .patch que volem aplicar.
* En el cas que s'hagin realitzat canvis sobre el fitxer al qual s'aplicarà el Patch, apareixeran conflictes que caldrà resoldre prèviament abans d'aplicar el Patch.

## Referències

* Android Studio guia d'usuari
* IntelliJ Guia d'usuari
* Git
* Control de versions. Wikipedia