30
Introducci ´ on a Con explicaci ´ on de un modelo de ramificaci ´ on Autor: Jorge L´ opez Fern´ andez [email protected] [email protected] Neda, 9 de noviembre de 2010

Introducción a Git

Embed Size (px)

DESCRIPTION

En este documento se recogen los conocimientos básicos para el manejo de un repositorio git, incluyendo un modelo de ramificación como ejemplo.

Citation preview

Page 1: Introducción a Git

Introduccion a

Con explicacion de un modelo de ramificacion

Autor: Jorge Lopez [email protected]

[email protected]

Neda, 9 de noviembre de 2010

Page 2: Introducción a Git

RESUMEN

En este documento se recogen los conocimientos basicos para el manejo de unrepositorio git.

En primer lugar se abordan los conceptos tecnicos, es decir, los comandos nece-sarios para la mayorıa de las operaciones y el funcionamiento y filosofıa del sistemade control de versiones git.

En la segunda parte se explican un conjunto de buenas practicas en lo relativoal manejo de ramas y flujo de trabajo entre miembros de un equipo, tomando paraello como base un modelo que ha demostrado su exito a lo largo de diversos proyectos.

Page 3: Introducción a Git

Indice general

Indice general I

Indice de figuras II

1. Tutorial 11.1. Descripcion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.2. Importar un proyecto nuevo . . . . . . . . . . . . . . . . . . . . . . 11.3. Realizando cambios . . . . . . . . . . . . . . . . . . . . . . . . . . 21.4. Git controla contenidos, no ficheros . . . . . . . . . . . . . . . . . . 31.5. Consultando la evolucion del proyecto . . . . . . . . . . . . . . . . . 31.6. Gestionando ramas . . . . . . . . . . . . . . . . . . . . . . . . . . . 41.7. Git como herramienta de colaboracion . . . . . . . . . . . . . . . . 61.8. Explorando el historico . . . . . . . . . . . . . . . . . . . . . . . . . 91.9. Siguientes pasos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

2. Un modelo de ramificacion exitoso 132.1. Introduccion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132.2. ¿Por que git? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142.3. Descentralizado pero centralizado . . . . . . . . . . . . . . . . . . . 142.4. Las ramas principales . . . . . . . . . . . . . . . . . . . . . . . . . 152.5. Soportando ramas . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

2.5.1. Feature branches . . . . . . . . . . . . . . . . . . . . . . . . 172.5.2. Release branches . . . . . . . . . . . . . . . . . . . . . . . . 192.5.3. Hotfix branches . . . . . . . . . . . . . . . . . . . . . . . . 21

2.6. Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

3. Comenzando a trabajar con Git en Windows 243.1. Instalacion de la herramienta . . . . . . . . . . . . . . . . . . . . . 243.2. Inicializacion del repositorio para NetBeans . . . . . . . . . . . . . . 24

Referencias 26

i

Page 4: Introducción a Git

Indice de figuras

2.1. Esquema del modelo de ramificacion . . . . . . . . . . . . . . . . . 132.2. Esquema de coordinacion entre repositorios . . . . . . . . . . . . . . 152.3. Flujo entre las ramas master y develop . . . . . . . . . . . . . . . 162.4. Flujo de las ramas de caracterısticas (feature branches) . . . . . . . . 172.5. Comparacion de “merge” con fast-forward y sin el . . . . . . . . . . 182.6. Flujo de las ramas de arreglos rapidos (hotfix branches) . . . . . . . 22

ii

Page 5: Introducción a Git

Capıtulo 1

Tutorial

1.1. Descripcion

Git es un software de control de versiones disenado por Linus Torvalds, pensandoen la eficiencia y la confiabilidad del mantenimiento de versiones de aplicacionescuando estas tienen un gran numero archivos de codigo fuente.

En este tutorial sobre git [1] se explicara como importar un proyecto, hacer cambiosen el y compartir esos cambios con otros desarrolladores.

Antes de nada senalaremos que se puede conseguir documentacion para cualquiercomando de git en una lınea de comando tipo UNIX con un comando del estilo de

$ man git -log

sustituyendo log por el comando de git que nos interese.Al comenzar es una buena idea introducir los datos personales, nombre y direccion

de e-mail, antes de hacer cualquier operacion. La manera mas sencilla es:

$ git config --global user.name "Tu nombre"

$ git config --global user.email [email protected]

1.2. Importar un proyecto nuevo

Si asumimos que tenemos un proyecto dentro de un directorio, simplemente nossituaremos en la lınea de comando en dicho directorio y ejecutaremos

$ git init

y git nos respondera

1

Page 6: Introducción a Git

1.3. Realizando cambios 2

Initialized empty Git repository in .git/

Ya hemos inicializado el directorio de trabajo, y ahora podremos ver que se hacreado un directorio nuevo, “.git”.

Lo siguiente sera indicarle a git que anote el contenido de todos los ficheros bajoel directorio actual, con g it add:

$ git add .

La informacion sobre el estado de los archivos esta almacenada en un area de alma-cenamiento temporal que git llama “ındice”. Podemos almacenar permanentementelos contenidos del ındice en el repositorio con el comando commit:

$ git commit

Con esto te pedira un mensaje que describa el commit, y ya habras almacenadola primera version de tu proyecto en git.

1.3. Realizando cambios

Modifica algunos archivos, entonces anade sus contenidos actualizados al ındice:

$ git add file1 file2 file3

Ahora ya estas listo para hacer un commit. Puedes ver los cambios que vas aconfirmar usando git diff con la opcion --cached:

$ git diff --cached

(Sin --cached, git diff te mostrarıa cualquier cambio que hayas hecho perono hayas anadido al ındice.) Tambien puedes obtener un resumen del estado delrepositorio con git status:

$ git status

# On branch master

# Changes to be committed:

# (use "git reset HEAD <file >..." to unstage)

#

# modified: file1

# modified: file2

Page 7: Introducción a Git

1.4. Git controla contenidos, no ficheros 3

# modified: file3

#

Si necesitas hacer algun ajuste adicional, hazlo ahora, y entonces anade cualquierarchivo nuevamente modificado al ındice. Finalmente, confirma tus cambios con:

$ git commit

Se te pedira de nuevo un mensaje descriptivo sobre los cambios, y entonces alma-cenara una nueva version del proyecto.

Alternativamente, en lugar de git add puedes emplear

$ git commit -a

que automaticamente detectara cualquier archivo modificado (pero no nuevo), loanadira al ındice y lo confirmara en un solo paso.

Una nota sobre los mensajes de los “commits”: aunque no es obligatorio, se reco-mienda comenzar el mensaje con una lınea corta (menos de 50 caracteres) resumiendoel cambio, seguida de una lınea en blanco y luego una descripcion mas detallada. Lasherramientas que convierten “commits” en mails, por ejemplo, emplean la primeralınea para el asunto del mensaje, y el resto para el cuerpo.

1.4. Git controla contenidos, no ficheros

Muchos sistemas de control de versiones proporcionan un comando add que ledice al sistema que comience a controlar los cambios en un fichero nuevo. El comandoadd en Git hace algo mas sencillo y mas potente: git add se usa tanto para ficherosnuevos como para aquellos que han sido modificados, y en ambos casos toma unacopia de los ficheros y envıa su contenido al ındice, listo para ser incluido en el siguiente“commit”.

1.5. Consultando la evolucion del proyecto

En cualquier momento se puede consultar el historico de los cambios empleando

$ git log

Si tambien quieres consultar la lista completa de cambios en cada etapa, usa

Page 8: Introducción a Git

1.6. Gestionando ramas 4

$ git log -p

En muchas ocasiones un resumen de los cambios es util para tener una idea sobrecada etapa:

$ git log --stat --summary

1.6. Gestionando ramas

Un unico repositorio git puede tener multiples ramas para desarrollo. Para crearuna nueva rama llamada “experimental”, usa

$ git branch experimental

Si ahora ejecutas

$ git branch

veras una lista de todas las ramas existentes:

experimental

* master

La rama “experimental” es la que acabas de crear, mientras que la rama “master”es una rama por defecto que se crea automaticamente. El asterisco marca la rama enla que estas actualmente; ahora ejecuta

$ git checkout experimental

para cambiar a la rama “experimental”. Ahora edita un fichero, confirma el cambioen un “commit”, y cambia de nuevo a la rama “master”:

(editar fichero)

$ git commit -a

$ git checkout master

Comprueba que el cambio que hiciste ya no es visible, ya que se realizo en la rama“experimental” y estas de nuevo en la rama “master”.

Page 9: Introducción a Git

1.6. Gestionando ramas 5

Puedes hacer un cambio distinto en la rama “master”:

(editar fichero)

$ git commit -a

en este momento las dos ramas son divergentes, con diferentes cambios realizadosen cada una. Para juntar los cambios de la rama “experimental” en “master”, ejecuta

$ git merge experimental

Si no existen conflictos en los cambios, ya esta. En caso contrario, se dejaranmarcadores en los ficheros problematicos indicando el conflicto;

$ git diff

nos mostrara esto. Una vez que hayas editado el fichero para resolver los conflictos,

$ git commit -a

confirmara el resultado de la mezcla. Finalmente,

$ gitk

mostrara una representacion grafica del historico resultante.En este punto podrıas eliminar la rama “experimental” con

$ git branch -d experimental

Este comando asegura que cambios en la rama “experimental” ya estan en larama actual.

Si desarrollas en una rama alguna idea que luego quieres desechar, simplementeborrala con

$ git branch -D estupidez

Las ramas con sencillas y rapidas, por lo que probarlas es una buena practica.

Page 10: Introducción a Git

1.7. Git como herramienta de colaboracion 6

1.7. Git como herramienta de colaboracion

Supongamos que Alicia ha comenzado un proyecto nuevo con un repositorio giten /home/alicia/proyecto, y que Roberto, que tiene un directorio home en la mismamaquina, quiere contribuir.

Roberto comienza con:

rober$ git clone /home/alicia/proyecto mirepo

Esto crea un nuevo directorio “mirepo” con una copia del repositorio de Alicia. Lacopia es exactamente igual al proyecto original, teniendo su propia copia del historicodel original.

Roberto entonces hace algunos cambios y los confirma:

(editar ficheros)

rober$ git commit -a

(repetir si es necesario)

Cuando este listo, le dice a Alicia que traiga sus cambios desde el repositorio en/home/rober/mirepo. Para ello hace:

alicia$ cd /home/alicia/project

alicia$ git pull /home/rober/mirepo master

Esto mezcla los cambios de la rama “master” de Roberto en la rama actual deAlicia. Si Alicia tenıa cambios en los mismos ficheros, entonces probablemente necesitesolucionar manualmente los conflictos.

El comando “pull” realiza dos operaciones: recoge los cambios de una rama remotay luego los aplica en la rama actual.

Tengase en cuenta que en general Alicia querrıa confirmar sus cambios localesantes de realizar el “pull”. Si el trabajo de Roberto tiene conflictos con el de Alicia,esta usara su arbol de trabajo y el ındice para resolver los conflictos, y cambios localesexistentes podrıan interferir con el proceso de resolucion del conflicto (git realizarıala operacion de recogida de los cambios, pero no los mezclarıa — Alicia tendra quede algun modo librarse de sus cambios locales y luego traer los cambios de Robertode nuevo cuando esto ocurre).

Alicia puede echar una ojeada a lo que hizo Bobo sin necesidad de mezclar primero,usando el comando “fetch”; esto permite a Alicia inspeccionar lo que Roberto hizo,usando un sımbolo “FETCH HEAD” para determinar si tiene algo que merezca lapena actualizar, de este modo:

Page 11: Introducción a Git

1.7. Git como herramienta de colaboracion 7

alicia$ git fetch /home/bob/myrepo master

alicia$ git log -p HEAD.. FETCH_HEAD

Esta operacion es segura incluso si Alicia tiene cambios locales sin confirmar. Lanotacion de rango “HEAD..FETCH HEAD” significa “muestra todo lo que es alcan-zable desde FETCH HEAD pero excluye todo lo que sea alcanzable desde HEAD”.Alicia ya conoce todo lo que conduce a su estado actual (HEAD), y comprueba loque Roberto tiene en su estado (FETCH HEAD) que ella no ha podido ver con estecomando.

Si Alicia quiere visualizar lo que hizo Roberto desde que sus trabajos divergieronpuede hacerlo con el siguiente comando:

$ gitk HEAD.. FETCH_HEAD

Esto emplea la misma notacion de rangos con dos puntos que vimos antes en gitlog.

Alicia puede querer ver que hicieron exactamente los dos desde que divergieron.Puede usar lo notacion de tres puntos en lugar de la de dos:

$ gitk HEAD ... FETCH_HEAD

Esto significa “muestra todo lo que es alcanzable desde cualquiera de ellos, peroexclude lo que sea alcanzable desde ambos”.

Toma nota de que esta notacion para el rango se puede emplear tanto para gitkcomo para git log.

Tras inspeccionar lo que Roberto hizo, si no hay nada urgente, Alicia decidecontinuar trabajando sin aplicar los cambios de Roberto. Si el trabajo de Robertotuviera algo urgente para Alicia, ella decidirıa apartar sus cambios, descargar lo querealizo Roberto y luego aplicar su trabajo en los ficheros resultantes.

Cuando se trabaja en un grupo pequeno y cercano, no es habitual interactuar conel repositorio una y otra vez. Definiendo un repositorio remoto se simplifica:

alicia$ git remote add rober /home/rober/mirepo

Con esto, Alicia puede realizar la primera parte de la operacion de “pull” porseparado usando el comando git fetch sin tener que mezclar los cambios con supropia rama, usando:

alicia$ git fetch rober

Page 12: Introducción a Git

1.7. Git como herramienta de colaboracion 8

Al contrario que la forma mas larga, cuando Alicia realiza “fetch” desde Robertousando el atajo con un repositorio remoto preparado con git remote, los cambios quefueron descargados de almacenan en una rama con informacion remota, en este casorober/master. Ası que despues de esto:

alicia$ git log -p master .. rober/master

ensena una lista de todos los cambios que Roberto ha hecho desde que creo surama a partir de la rama “master” de Alicia.

Tras examinar esos cambios, Alicia puede mezclarlos en su rama “master”:

alicia$ git merge rober/master

Este merge puede hacerse tambien actualizando desde su propia rama de segui-miento remoto, de este modo:

alicia$ git pull . remotes/rober/master

Notese que “git pull” siempre mezcla en la rama actual, sin importar ninguna otracosa en la lınea de comando.

Mas tarde, Roberto puede actualizar su repo con los ultimos cambios de Aliciaempleando

rober$ git pull

Notese que no necesita dar la ruta al repositorio de Alicia; cuando Roberto clono elrepositorio de Alicia, git almaceno la localizacion de su repositorio en la configuraciondel repositorio, y esa localizacion es la usada para el “pull”:

rober$ git config --get remote.origin.url

/home/alicia/

(La configuracion completa creada por git clone es visible usando git config

-l, y git-config explica el significado de cada opcion.)Git tambien mantiene una copia limpia de la rama “master” de Alicia bajo el

nombre “origin/master”:

rober$ git branch -r

origin/master

Page 13: Introducción a Git

1.8. Explorando el historico 9

Si Roberto decide mas adelante trabajar desde un host diferente, todavıa puederealizar operaciones “clone” y “pull” con ssh:

rober$ git clone alicia.org:/home/alicia/proyecto mirepo

De manera alternativa, git tiene un protocolo nativo, o puede emplear rsync ohttp; mirar git-pull para mas detalles.

Git tambien se puede emplear en un modo similar a CVS, con un repositoriocentral al que varios usuarios envıan sus cambios; mirar git-push y gitcvs-migration.

1.8. Explorando el historico

El historico en git esta representado como una serie de commits inter-relacionados.Ya hemos visto que el comando git log puede listar todos esos commits. Notese quela primera lınea de cada entrada del log tambien da un nombre para el commit:

$ git logcommit c82a22c39cbc32576f64f5c6b3f24b99ea8149c7

Author: Junio C Hamano <[email protected] >

Date: Tue May 16 17:18:22 2006 -0700

merge -base: Clarify the comments on post processing.

Podemos pasar este nombre a git show para ver detalles sobre ese commit.

$git show c82a22c39cbc32576f64f5c6b3f24b99ea8149c7

Pero hay otros modos de referenciar commits. Puedes emplear cualquier trozoinicial del nombre que sea suficientemente largo como para identificar de manerainequıvoca al commit:

$ git show c82a22c39c # los primeros caracteres del nombre

suelen ser suficiente

$ git show HEAD # el atajo de la rama actual

$ git show experimental # el atajo de la rama ‘‘experimental ’’

Todos los commits tienen habitualmente un commit “padre” que apunta al estadoprevio del proyecto:

$ git show HEAD^ # para mirar el padre de HEAD

$ git show HEAD^^ # para mirar el abuelo de HEAD

$ git show HEAD~4 # para mirar el tatarabuelo de HEAD

Page 14: Introducción a Git

1.8. Explorando el historico 10

Notese que los commits de mezcla (operaciones “merge”) pueden tener mas deun padre:

$ git show HEAD^1 # muestra el primer padre de HEAD (igual que

HEAD^)

$ git show HEAD^2 # muestra el segundo padre de HEAD

Tambien puedes dar tus propios nombres a los commits; tras ejecutar

$ git tag v2.5 1b2e1d63ff

puedes referenciar a 1b2e1d63ff con el nombre “v2.5”. Si tienes intencion decompartir este nombre con otra gente (e.g. para identificar una version de release),deberıas crear un objeto “tag”, y quizas firmarlo; mirar git-tag para mas detalles.

Cualquier comando de git necesita conocer un commit acepta cualquiera de estosnombres. Por ejemplo:

$ git diff v2.5 HEAD # comparar el HEAD actual con v2.5

$ git branch stable v2.5 # comenzar una nueva rama ‘‘stable ’’

a partir de v2.5

$ git reset --hard HEAD^ # resetear tu rama actual y

directorio de trabajo a HEAD^

Ten cuidado con este ultimo comando: ademas de perder cualquier cambio enel directorio de trabajo, eliminara los commits mas recientes de esta rama. Si estarama es la unica que contiene esos commits, se perderan. Tampoco debemos usar gitreset en una rama visible publicamente de la que otros desarrolladores actualizan, yaque obligara a realizar operaciones “merge” innecesarias para limpiar los historicos.Si necesitas deshacer cambios que has confirmado, emplea git revert en su lugar.

El comando git grep puede buscar cadenas en cualquier version de tu proyecto,ası que

$ git grep ‘‘hello ’’ v2.5

busca todas las apariciones de “hello” en v2.5.Si no se le indica un nombre de commit, git grep buscara en cualquiera de los

ficheros que administra en el directorio actual. Por lo que

$ git grep ‘‘hello ’’

Page 15: Introducción a Git

1.8. Explorando el historico 11

es una manera rapida de buscar simplemente en todos los ficheros administradospor git.

Muchos comandos de git aceptan conjuntos de commits, que se pueden especificarde numerosas maneras. Aquı hay algunos ejemplos con git log :

$ git log v2.5..v2.6 # commits entre v2.5 y v2.6

$ git log v2.5.. # commits desde v2.5

$ git log --since="2 weeks ago" # commits de las ultimas 2

semanas

$ git log v2.5.. Makefile # commits desde v2.5 que

afectaron a Makefile

Tambien se le puede proporcionar a git log un “rango” de commits donde elprimero no es necesariamente ancestro del segundo; por ejemplo, si los extremos delas ramas “stable” y “master” divergieron de un commit comun hace tiempo, entonces

$git log stable .. master

listara los commits realizados en la rama “master” pero no en “stable”, mientrasque

$git log master .. stable

realizara a la inversa.El comando git log tiene un contra: debe presentar los commits en una lista.

Cuando un historico tiene lıneas de desarrollo que divergieron y se juntaron de nuevo,el orden en el que git log presenta esos commits no tiene sentido.

La mayorıa de los proyectos con multiples colaboradores (como el kernel de Linuxo el propio git) tienen operaciones “merge” frecuentes, y gitk realiza un mejor trabajopara visualizar su historico. Por ejemplo,

$ gitk --since=‘‘2 weeks ago ’’ drivers/

permite navegar por cualquiera de los commits de las ultimas 2 semanas quemodificaron cualquier fichero bajo el directorio “driver” (Nota: la fuente de gitk sepuede ajustar presionando la tecla Ctrl y “-” o “+”.)

Finalmente, la mayorıa de los comandos que toman nombres de ficheros opcional-mente permitiran preceder cualquier nombre de fichero con un commit, para especi-ficar una version concreta del fichero:

$ git diff v2.5: Makefile HEAD:Makefile.in

Page 16: Introducción a Git

1.9. Siguientes pasos 12

Tambien se puede usar git show para ver dicho fichero:

$ git show v2.5: Makefile

1.9. Siguientes pasos

Este tutorial deberıa ser suficiente para llevar un control de versiones distribuidobasico sobre tus proyectos. Pero, para comprender realmente la potencia y profundidadde git debes entender las dos ideas basicas en que se basa:

La base de datos de objetos es un sistema elegante empleado para almacenarel historico de tu proyecto–ficheros, directorios y commits.

El fichero de ındice es una cache del estado del arbol de directorio, usado paracrear commits, confirmar cambios en directorios de trabajo y almacenar losdiversos arboles vinculados en una operacion “merge”.

La segunda parte de este tutorial explica la base de datos de objetos, el ficherode ındice y algunos otros conceptos que te permitiran sacar todo el partido a git. Sepuede encontrar en gittutorial-2.

Algunos comandos interesantes relacionados con git que te pueden resultar utilesen este momento son:

git-format-patch, git-am: convierten series de commits de git en parches quese pueden enviar por mail, y viceversa, util para proyectos como el Kernel deLinux que se apoyan fuertemente en parches enviados de ese modo.

git-bisect: cuando hay una regresion en tu proyecto, un modo de seguir el buges buscar a traves del historico el commit responsable. “Git bisect” te puedeayudar a realizar una busqueda binaria por ese commit. Este tipo de busquedaes una buena opcion incluso en el caso de complejos historicos no lineales connumerosas ramas mezcladas.

gitworkflows: da una vision general sobre flujos de trabajo recomendados.

Trabajar dıa a dıa con 20 comandos de git

gitcvs-migration: git para usuarios de CVS.

Page 17: Introducción a Git

Capıtulo 2

Un modelo de ramificacionexitoso

2.1. Introduccion

En este apartado se recoge el modelo de trabajo propuesto por Vincent Driesseny explicado en su blog [2].

Figura 2.1: esquema del modelo de ramificacion de Vincent Driessen

13

Page 18: Introducción a Git

2.2. ¿Por que git? 14

Aplicado tanto en sus proyectos privados como publicos, ha demostrado ser unmodelo exitoso del empleo de git como herramienta de control de versiones para todoel codigo. A partir de este punto todo el texto viene de boca de Vincent Driessen.

2.2. ¿Por que git?

Para una discusion mas profunda sobre los pros y contras de Git comparado consistemas centralizados de control de versiones de codigo, podemos mirar por la web.Hay numerosas discusiones sobre el tema. Como desarrollador, prefiero Git sobre todaslas demas herramientas existentes. Git realmente ha cambiado el modo en que losdesarrolladores piensan sobre ramificar y mezclar codigo. Desde el clasico mundo deCVS/SVN del que vengo, mezclar y ramificar siempre se han considerado peligrosos(“¡Cuidado con los conflictos, te destrozaran!”) y algo que solo se deberıa hacer muyde vez en cuando.

Pero con Git estas acciones son extremadamente sencillas y rapidas, y estan consi-deradas parte del trabajo diario, de verdad. Por ejemplo, en los libros de CVS/SVN, laramificacion y la mezcla se explican en los ultimos capıtulos (para usuarios avanzados),mientras que todos los libros de Git lo cubren entre los conceptos basicos.

Como consecuencia de su simplicidad y naturaleza repetitiva, no se debe seguirteniendo miedo de ramificar o mezclar. Las herramientas de control de versiones debensupuestamente asistir en las tareas de ramificado y mezcla mas que cualquier otracosa.

Ya hemos hablado suficiente sobre las herramientas, entremos en el modelo dedesarrollo. El modelo que vamos a detallar es esencialmente un conjunto de procedi-mientos que todo miembro del equipo debe seguir con el fin de conseguir un procesode desarrollo de software bien administrado.

2.3. Descentralizado pero centralizado

El modelo de repositorio que ha demostrado funcionar bien con este modelo deramificacion y que empleamos es el de un repositorio central “verdadero”. Notese queeste repositorio solo es considerado el central (ya que Git es DVCS, por lo que noexiste un repositorio central desde un punto de vista tecnico). Si nos referimos a esterepositorio como origin, ya que este nombre es familiar para todos los usuarios deGit.

Todos los desarrolladores descargan y suben las modificaciones a origin. Peroaparte de las relaciones centralizadas de “push”-“pull”, cada desarrollador podra des-cargar cambios de otras personas para formar sub-equipos. Por ejemplo, esto puedeser util para trabajar junto a otros desarrolladores en una caracterıstica nueva, antesde enviar los cambios en progreso a origin prematuramente. En la figura 2.2 en lapagina siguiente, hay subequipos de Alice y Bob, Alice y David, y Clair y David.

Page 19: Introducción a Git

2.4. Las ramas principales 15

Figura 2.2: esquema de coordinacion entre repositorios

Tecnicamente, esto simplemente significa que Alice ha definido un Git remoto,llamado bob, apuntando al repositorio de Bob, y viceversa.

2.4. Las ramas principales

En su esencia, este modelo esta enormemente inspirado en otros modelos existen-tes. El repositorio central almacena dos ramas principales con una lınea de vida enprincipio infinita:

master

develop

La rama master en origin sera familiar para todo usuario de Git. De forma para-lela a la rama master, existe otra llamada develop. Consideramos origin/mastercomo la rama principal donde el codigo fuente de HEAD siempre esta en un estadode version de produccion estable.

Consideramos origin/develop la rama principal donde el codigo fuente deHEAD siempre refleja el estado de los ultimos cambios realizados pendientes de aplicara la siguiente release. Algunos llamarıan a esto “rama de integracion”.

Cuando el codigo dentro de la rama develop alcanza un punto estable y esta listopara ser liberado, todos los cambios deberıan ser aplicados en la rama master ymarcados con un tag con el numero de version. Mas adelante discutiremos en detalleeste proceso.

Page 20: Introducción a Git

2.5. Soportando ramas 16

Figura 2.3: flujo entre las ramas master y develop

Por lo tanto, cada vez que se aplican cambios en master, es una nueva versionde produccion por definicion. Siendo muy estrictos en este aspecto, teoricamentepodrıamos usar un script para automaticamente compilar y desplegar nuestro softwareen nuestros servidores cada vez que hay un commit en master.

2.5. Soportando ramas

Ademas de las ramas master y develop, nuestro modelo de desarrollo usa unavariedad de ramas auxiliares para ayudar al desarrollo paralelo entre miembros de losequipos, facilitar el seguimiento de las caracterısticas, preparar las liberacion de nuevasversiones y asistir en la solucion rapida de problemas de produccion. Al contrario quelas ramas principales, estas siempre tienen una vida limitada, ya que en algun momentose eliminaran.

Los tipos de ramas que podemos emplear son:

Ramas de caracterısticas del software (feature branches).

Ramas para releases (release branches).

Ramas para arreglos rapidos (hotfix branches).

Cada una de estas ramas tendra un proposito especıfico y estara sometida a reglasestrictas como de que ramas pueden nacir y con cuales se pueden mezclar. Hablaremosde ellas en un minuto.

Page 21: Introducción a Git

2.5. Soportando ramas 17

De ningun modo estas ramas son especiales desde un punto de vista tecnico. Lasramas las categorizamos segun como las empleamos. Todas son por supuesto simplesramas de Git.

2.5.1. Feature branches

� Pueden nacer de: develop

� Deben mezclarse con: develop

� Convencion de nombrado: cualquier cosa excepto master, develop, release-*o hotfix-*

Las ramas de caracterısticas del software (algunas veces llamadas ramas de topi-cos) se usan para desarrollar nuevas caracterısticas para futuras releases. Cuandocomenzamos el desarrollo de una caracterıstica, la release en la que planeamos incor-porarla puede ser desconocida en ese momento. La esencia de esta rama es existirmientras la caracterıstica esta en desarrollo, para en algun momento volver a mez-clarse con develop (para anadir definitivamente la caracterıstica a la release) o serdescartada (en caso de ser un experimento fallido).

Estas ramas suelen existir solo en los repositorios de los desarrolladores, no enorigin.

Figura 2.4: flujo de las ramas de caracterısticas (feature branches)

Creando una feature branch

Cuando comenzamos a trabajar en una caracterıstica nueva, ramificamos desde larama develop.

Page 22: Introducción a Git

2.5. Soportando ramas 18

$ git checkout -b myfeature develop

Switched to a new branch ‘‘myfeature ’’

Incorporando una caracterıstica terminada en develop

Las caracterısticas terminadas pueden ser mezcladas en la rama develop paraanadirlas definitivamente a la siguiente version de release:

$ git checkout develop

Switched to branch ’develop ’

$ git merge --no -ff myfeature

Updating ea1b82a ..05 e9557

(Summary of changes)

$ git branch -d myfeature

Deleted branch myfeature (was 05 e9557).

$ git push origin develop

El flag --no-ff hace que el “merge” siempre cree un nuevo objeto commit, inclusosi la operacion fue realizada con “fast-forward”. Esto evita la perdida de informacionsobre la existencia historica de la rama y agrupa todos los commits que conforman lacaracterıstica nueva. Compara:

Figura 2.5: comparacion de “merge” con fast-forward y sin el

Page 23: Introducción a Git

2.5. Soportando ramas 19

En el ultimo caso es imposible saber del historico de Git cuales de los objetoscommit juntos conforman la caracterıstica - habrıa que leer manualmente el log.Revertir una caracterıstica completa (i.e. un grupo de commits), es un quebradero decabeza en este caso, mientras que es mucho mas facil si se utilizo el flag --no-ff.

Sı, creara unos pocos mas objetos commit (vacıos), pero la ganancia supera concreces a las perdidas.

Desafortunadamente, aun no conozco ningun modo de hacer que --no-ff sea elcomportamiento por defecto de git merge, pero deberıa ser ası.

2.5.2. Release branches

� Pueden nacer de: develop

� Deben mezclarse con: develop y master

� Convencion de nombrado: release-*

Las ramas de releases soportan la preparacion de una nueva release. Permitenretoques de ultima hora, ademas de servir para la solucion de pequenos bugs y lapreparacion de los meta-datos (numero de version, fechas, etc.). Haciendo todo estoen la rama de release, la rama develop esta libre para recibir nuevas caracterısticaspara la siguiente release.

El momento clave para crear una nueva rama de release desde develop es cuandodevelop (casi) refleja el estado deseado para la nueva release. Al menos todas lasnuevas caracterısticas que estan enfocadas a release objetivo deben haber sido aplica-das sobre develop en este momento. Todas las caracterısticas para futuras releasesdeberan esperar a que esta rama release haya sido creada.

Es justo despues del comienzo de la rama release cuando a la release se le asignaun numero nunca antes. Hasta ese momento, la rama develop reflejo los cambiospara la siguiente release, pero no esta claro si la release sera la 0.3 o la 1.0 hasta quecomienza la rama. Esa decision se toma al principio de la rama release y se lleva acabo segun las reglas de versionado del proyecto.

Creando una rama release

Las ramas release se crean a partir de la rama develop. Por ejemplo, supongamosque la version actual es la 1.1.5 y que proximamente se liberara otra. La rama develop

esta lista para la siguiente release, y hemos decidido que sera la version 1.2 (en lugarde la 1.1.6 o 2.0). Ası que ramificamos y le damos a la rama un nombre reflejandosu version:

$ git checkout -b release -1.2 develop

Switched to a new branch "release -1.2"

$ ./bump -version.sh 1.2

Page 24: Introducción a Git

2.5. Soportando ramas 20

Files modified successfully , version bumped to 1.2.

$ git commit -a -m "Bumped version number to 1.2"

[release -1.2 74 d9424] Bumped version number to 1.2

1 files changed , 1 insertions (+), 1 deletions (-)

Despues de crear la rama y cambiarnos a ella, le asignamos el numero de version.Aquı, bump-version.sh es un script imaginario que realiza cambios en algunos fi-cheros de la copia de trabajo para reflejar la nueva version. (Esto puede ser cambiadoa mano, obviamente - lo importante es que algunos ficheros cambian) Entonces serealiza el commit de la version con el numero asignado.

Esta nueva rama podra existir por un tiempo, hasta que la release haya sido libera-da definitivamente. Durante ese tiempo, arreglos a bugs seran aplicados en esta rama(en lugar de en develop). Anadir caracterısticas nuevas importantes esta totalmenteprohibido. Deben ser aplicadas en develop, y por tanto, esperar a la siguiente release.

Acabando con una rama release

Cuando una rama release esta lista para convertirse en una release real, debemosseguir algunos pasos. En primer lugar, la rama release debe ser aplicada sobre master

(ya que todos los commits en master son una nueva release, por definicion). Acontinuacion, a ese commit en master se le debe poner un tag para referenciarlo enel futuro en el historico de versiones. Finalmente, los cambios realizados en la ramade release deben ser mezclados de nuevo en develop, para que futuras releases siganconteniendo los cambios.

Los dos primeros pasos en Git:

$ git checkout master

Switched to branch ’master ’

$ git merge --no -ff release -1.2

Merge made by recursive.

(Summary of changes)

$ git tag -a 1.2

La release ya ha sido realizada, y se le ha puesto un tag para futuras referencias.Quizas quieras usar los flags -s o -u <clave> para firmar el tag criptografica-

mente.Pero para mantener los cambios realizados en la rama de release, tenemos que

mezclarlos de vuelta en develop. En Git:

$ git checkout develop

Switched to branch ’develop ’

$ git merge --no -ff release -1.2

Merge made by recursive.

(Summary of changes)

Page 25: Introducción a Git

2.5. Soportando ramas 21

Este paso puede llevar facilmente a un conflicto, y en tal caso deberıamos solu-cionarlo y hacer commit.

Ahora ya hemos acabado realmente y la rama de release debe ser eliminar, ya queno la necesitamos mas:

$ git branch -d release -1.2

Deleted branch release -1.2 (was ff452fe).

2.5.3. Hotfix branches

� Pueden nacer de: master

� Deben mezclarse con: develop y master

� Convencion de nombrado: hotfix-*

Las ramas para arreglos rapidos se parecen mucho a las ramas de release en quetambien estan pensadas para preparar una nueva version de release, pero en estecaso no planeada. Nacen de la necesidad de actuar inmediatamente ante un estadono deseado en la version actual en produccion. Cuando un bug crıtico de la versionactual debe ser solucionado inmediatamente, una rama de arreglo rapido puede nacerdel tag correspondiente de la rama master que marca la version en produccion.

La esencia es que el trabajo de miembros de equipo (en la rama develop) puedecontinuar, mientras otra persona esta preparando una solucion rapida.

Creando una rama de arreglo rapido

Las ramas para arreglos rapidos se crean a partir de la rama master. Por ejemplo,digamos que la version 1.2 es la release actual y que esta causando problemas debidoa un bug grave. Pero los cambios en develop son todavıa inestables. Entonces loaconsejable es crear una rama para arreglar dicho bug:

$ git checkout -b hotfix -1.2.1 master

Switched to a new branch "hotfix -1.2.1"

$ ./bump -version.sh 1.2.1

Files modified successfully , version bumped to 1.2.1.

$ git commit -a -m "Bumped version number to 1.2.1"

[hotfix -1.2.1 41 e61bb] Bumped version number to 1.2.1

1 files changed , 1 insertions (+), 1 deletions (-)

Page 26: Introducción a Git

2.5. Soportando ramas 22

Figura 2.6: flujo de las ramas de arreglos rapidos (hotfix branches)

No nos debemos olvidar de cambiar el numero de la version en el momento enque ramifiquemos.

Entonces, arreglamos el bug y hacemos uno o mas commits con su solucion.

$ git commit -m "Fixed severe production problem"

[hotfix -1.2.1 abbe5d6] Fixed severe production problem

5 files changed , 32 insertions (+), 17 deletions (-)

Acabando con una rama de arreglo rapido

Cuando se termina, la solucion al bug debe ser mezclada en la rama master, perotambien necesita mezclarse de vuelta en develop, para asegurarnos de que el bug noocurrira de nuevo en la siguiente release. Es un proceso analogo al realizado cuandolas ramas de release se terminan.

Primero, actualizamos master y ponemos el tag a la release.

$ git checkout master

Switched to branch ’master ’

$ git merge --no -ff hotfix -1.2.1

Merge made by recursive.

(Summary of changes)

$ git tag -a 1.2.1

Page 27: Introducción a Git

2.6. Resumen 23

De nuevo, quizas quieras usar los flags -s o -u <clave> para firmar el tag crip-tograficamente.

Luego incluimos el arreglo tambien en develop:

$ git checkout develop

Switched to branch ’develop ’

$ git merge --no -ff hotfix -1.2.1

Merge made by recursive.

(Summary of changes)

La excepcion a esta regla es que, cuando actualmente existe una rama de release,la solucion al bug sera mezclada en esa rama de release en lugar de en develop.Aplicar la solucion en la rama de release conduce a que en algun momento seatambien aplicado a la rama develop, cuando la rama de release se termine. (Si eltrabajo en develop requiere la solucion al bug inmediatamente y no podemos esperara que la rama de release se termine, tambien podemos aplicar la solucion en develop

sin problemas.)Finalmente, eliminamos la rama temporal:

$ git branch -d hotfix -1.2.1

Deleted branch hotfix -1.2.1 (was abbe5d6).

2.6. Resumen

Aunque realmente no hay nada nuevo en este modelo de ramificacion, la imagengeneral en la que se basa ha demostrado ser tremendamente util en nuestros proyectos.Conforma un modelo mental muy elegante que es facil de comprender y permitea miembros de equipos compartir una unica vision del proceso de ramificacion yliberacion del software.

Page 28: Introducción a Git

Capıtulo 3

Comenzando a trabajar conGit en Windows

En este apartado abordaremos el proceso de creacion del repositorio para su poste-rior funcionamiento en NetBeans. Dado que el repositorio no contiene un proyecto deNetBeans completo1 son necesarios algunos pasos adicionales para lograr su correctofuncionamiento.

3.1. Instalacion de la herramienta

Descargaremos el entorno Git para Windows de la pagina del proyecto sysgit:

1. Nos descargamos la version mas reciente del entorno (los archivos con formatoGit-x.x.x.x) de su web oficial.

2. Durante la instalacion se aconseja instalar las dos entradas del menu de contextoen lugar del git-cheetah.

Podemos comprobar la correcta instalacion del plugin si en el navegador de Win-dows al hacer click derechon sobre una carpeta existen las opciones Git GUI Here y GitBash Here, a las cuales tambien se puede acceder por el menu de inicio a traves de Git.

3.2. Inicializacion del repositorio para NetBeans

A la hora de inicializar el repositorio para trabajar en NetBeans, la forma massencilla es disponiendo de una copia local de DeporXest como proyecto de NetBeans.En tal caso se hara lo siguiente:

1al no ser un repositorio exclusivo para desarrollo no es aconsejable incluir archivos de-pendientes del IDE, ya que ensuciarıan el repositorio con archivos innecesarios para muchosusuarios que no empleen ese entorno.

24

Page 29: Introducción a Git

3.2. Inicializacion del repositorio para NetBeans 25

1. Iniciaremos la interfaz grafica de Git (es indiferente si con el click derecho sobreuna carpeta cualquiera o por el menu de inicio), y seleccionamos Clone ExistingRepository.

2. Introducimos la URL del repositorio,ssh://<user>@deporxest.git.sourceforge.net/gitroot/deporxest/deporxest,sustituyendo ‘<user>’por el nombre de usuario en SourceForge.

3. Elegimos el directorio donde guardarlo (indiferente, ya que sera temporal).

4. Antes de descargar nos pedira la clave ssh de nuestra cuenta en SourceForge.

5. Copiamos todo el contenido de la carpeta que acaba de crear (incluyendo lacarpeta oculta .git) dentro de la carpeta del proyecto DeporXest de NetBeansque ya tenıamos anteriormente, sobreescribiendo todo.

Una vez completado, podemos comprobar que es correcto si al hacer click dere-cho sobre la carpeta del proyecto y pulsar en Git GUI Here nos abre directamente elrepositorio y no la ventana inicial para crear, clonar y abrir repositorios.

En caso de no disponer del proyecto completo en local, serıa necesario tomarlos siguientes pasos tras descargar el contenido del repositorio de manera similar ala anterior, necesitando a pesar de todo una carpeta de un proyecto DeporXest deNetBeans:

� Creamos un proyecto con el nombre que deseemos, y copiamos dentro los con-tenidos descargados del repositorio.

� Copiaremos la carpeta nbproject de un proyecto NetBeans de DeporXest den-tro del proyecto recientemente creado.

� Muy probablemente debamos copiar tambien las librerıas que necesita el pro-yecto, manteniendo la misma ruta que en la configuracion original del proyecto(podemos comprobar la ruta con Click derecho sobre el proyecto -> Properties-> Libraries).

Una vez que la configuracion de las librerıas esta lista, de nuevo podemos com-probar que todo es correcto si Git GUI nos abre el repositorio en lugar de la pantallainicial.

Page 30: Introducción a Git

Referencias

[1] Tutorial oficial de Git: http://www.kernel.org/pub/software/

scm/git/docs/gittutorial.html

[2] Blog de Vincent Driessen: http://nvie.com

[3] Tutorial de Git por Ben Lynn: http://www-cs-students.stanford.edu/~blynn/gitmagic/intl/es/index.html

[4] Pagina del proyecto Sysgit en Google Code: http://code.google.com/p/msysgit/

26