Está en la página 1de 30
Introduccion´ a Con explicacion´ de un modelo de ramificacion´ Autor: lopez.fernandez.jorge@gmail.com jorge@egalcom.com

Introduccion´

a

Introduccion´ a Con explicacion´ de un modelo de ramificacion´ Autor: lopez.fernandez.jorge@gmail.com jorge@egalcom.com

Con explicacion´

de un modelo de ramificacion´

Autor:

Jorge Lopez´

Fernandez´

Neda, 9 de noviembre de 2010

Autor: lopez.fernandez.jorge@gmail.com jorge@egalcom.com Jorge Lopez´ Fernandez´ Neda, 9 de noviembre de 2010

RESUMEN

En este documento se recogen los conocimientos b´asicos para el manejo de un repositorio git.

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

En la segunda parte se explican un conjunto de buenas pr´acticas en lo relativo al manejo de ramas y flujo de trabajo entre miembros de un equipo, tomando para ello como base un modelo que ha demostrado su ´exito a lo largo de diversos proyectos.

´

 

Indice general

´

Indice general

I

´

Indice de figuras

II

1.

Tutorial

1

1.1. Descripci´on

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

1

1.2. Importar un proyecto nuevo

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

1

1.3. Realizando cambios

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

2

1.4. Git controla contenidos, no ficheros

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

3

1.5. Consultando la evoluci´on del proyecto .

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

3

1.6. Gestionando ramas .

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

4

1.7. Git como herramienta de colaboraci´on

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

6

1.8. Explorando el hist´orico

 

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

9

1.9. Siguientes pasos

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

12

2. Un modelo de ramificaci´on exitoso

 

13

2.1. Introducci´on

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

13

2.2. ¿Por qu´e git? .

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

14

2.3. Descentralizado pero centralizado

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

14

2.4. Las ramas principales

 

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

15

2.5. Soportando ramas

. 2.5.1. Feature branches

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

16

17

2.5.2. Release branches

 

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

19

   

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

21

2.5.3. Hotfix branches .

.

.

.

.

.

.

2.6. Resumen

.

.

.

.

.

.

.

.

.

.

.

3. Comenzando a trabajar con Git en Windows

.

.

.

.

.

.

.

.

.

.

.

.

.

.

23

24

3.1. Instalaci´on de la herramienta

 

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

24

3.2. Inicializaci´on del repositorio para NetBeans

.

.

.

.

.

.

.

.

.

.

.

.

.

.

24

Referencias

26

i

´

Indice de figuras

2.1. Esquema del modelo de ramificaci´on

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

13

2.2. Esquema de coordinaci´on entre repositorios .

.

.

.

.

.

.

.

.

.

.

.

.

.

15

2.3. Flujo entre las ramas master y develop

 

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

16

2.4. Flujo de las ramas de caracter´ısticas (feature branches) .

.

.

.

.

.

.

.

17

2.5. Comparaci´on de “merge” con fast-forward y sin ´el

 

.

.

.

.

.

.

.

.

.

.

18

2.6. Flujo de las ramas de arreglos r´apidos (hotfix branches)

.

.

.

.

.

.

.

22

ii

Cap´ıtulo 1

Tutorial

1.1. Descripci´on

Git es un software de control de versiones dise˜nado por Linus Torvalds, pensando en la eficiencia y la confiabilidad del mantenimiento de versiones de aplicaciones cuando ´estas tienen un gran n´umero archivos de c´odigo fuente. En este tutorial sobre git [1] se explicar´a c´omo importar un proyecto, hacer cambios en ´el y compartir esos cambios con otros desarrolladores. Antes de nada se˜nalaremos que se puede conseguir documentaci´on para cualquier comando 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 direcci´on de e-mail, antes de hacer cualquier operaci´on. La manera m´as sencilla es:

$ git

config

-- global

user . name

" Tu nombre "

$ git

config

-- global

user . email

tu@tudominio . ejemplo . com

1.2. Importar un proyecto nuevo

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

$ git

init

y git nos responder´a

nos situaremos en la l´ınea de comando en dicho directorio y ejecutaremos $ git init y
nos situaremos en la l´ınea de comando en dicho directorio y ejecutaremos $ git init y
nos situaremos en la l´ınea de comando en dicho directorio y ejecutaremos $ git init y

1

1.3. Realizando cambios

2

Initialized

empty

Git

repository

in

. git /

Ya hemos inicializado el directorio de trabajo, y ahora podremos ver que se ha creado un directorio nuevo, “.git”. Lo siguiente ser´a indicarle a git que anote el contenido de todos los ficheros bajo el directorio actual, con g it add:

$ git

add

.

La informaci´on sobre el estado de los archivos est´a almacenada en un ´area de alma- cenamiento temporal que git llama “´ındice”. Podemos almacenar permanentemente los contenidos del ´ındice en el repositorio con el comando commit:

$ git

commit

Con esto te pedir´a un mensaje que describa el commit, y ya habr´as almacenado la primera versi´on de tu proyecto en git.

1.3. Realizando cambios

Modifica algunos archivos, entonces a˜nade sus contenidos actualizados al ´ındice:

$ git

add

file1

file2

file3

Ahora ya est´as listo para hacer un commit. Puedes ver los cambios que vas a confirmar usando git diff con la opci´on --cached:

$ git

diff

-- cached

te mostrar´ıa cualquier cambio que hayas hecho pero

no hayas a˜nadido al ´ındice.) Tambi´en puedes obtener un resumen del estado del repositorio con git status:

(Sin --cached, git diff

$

git

status

#

On

branch

master

#

Changes to be committed :

 

#

( use

" git

reset

HEAD

< file >

"

to

unstage )

#

#

modified :

file1

#

modified :

file2

1.4. Git controla contenidos, no ficheros

3

#

modified :

file3

#

Si necesitas hacer alg´un ajuste adicional, hazlo ahora, y entonces a˜nade cualquier archivo nuevamente modificado al ´ındice. Finalmente, confirma tus cambios con:

$ git

commit

Se te pedir´a de nuevo un mensaje descriptivo sobre los cambios, y entonces alma- cenar´a una nueva versi´on del proyecto. Alternativamente, en lugar de git add puedes emplear

$ git

commit

-a

que autom´aticamente detectar´a cualquier archivo modificado (pero no nuevo), lo a˜nadir´a al ´ındice y lo confirmar´a 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) resumiendo el cambio, seguida de una l´ınea en blanco y luego una descripci´on m´as detallada. Las herramientas que convierten “commits” en mails, por ejemplo, emplean la primera l´ı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 le dice al sistema que comience a controlar los cambios en un fichero nuevo. El comando add en Git hace algo m´as sencillo y m´as potente: git add se usa tanto para ficheros nuevos como para aquellos que han sido modificados, y en ambos casos toma una copia de los ficheros y env´ıa su contenido al´ındice, listo para ser incluido en el siguiente “commit”.

1.5. Consultando la evoluci´on del proyecto

En cualquier momento se puede consultar el hist´orico de los cambios empleando

$ git

log

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

de los cambios empleando $ git log Si tambi´en quieres consultar la lista completa de cambios
de los cambios empleando $ git log Si tambi´en quieres consultar la lista completa de cambios
de los cambios empleando $ git log Si tambi´en quieres consultar la lista completa de cambios

1.6. Gestionando ramas

4

$ git

log

-p

En muchas ocasiones un resumen de los cambios es util´ cada etapa:

para tener una idea sobre

$ git

log

-- stat

-- summary

1.6. Gestionando ramas

Un unico´

repositorio git puede tener m´ultiples ramas para desarrollo. Para crear

una nueva rama llamada “experimental”, usa

$ git

branch

experimental

Si ahora ejecutas

$ git

branch

ver´as 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 autom´aticamente. El asterisco marca la rama en la que est´as actualmente; ahora ejecuta

$ git

checkout

experimental

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

( editar

fichero )

$ commit

git

-a

$ checkout

git

master

Comprueba que el cambio que hiciste ya no es visible, ya que se realiz´o en la rama “experimental” y est´as de nuevo en la rama “master”.

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 realizados en cada una. Para juntar los cambios de la rama “experimental” en “master”, ejecuta

$ git

merge

experimental

Si no existen conflictos en los cambios, ya est´a. En caso contrario, se dejar´an marcadores en los ficheros problem´aticos indicando el conflicto;

$ git

diff

nos mostrar´a esto. Una vez que hayas editado el fichero para resolver los conflictos,

$ git

commit

-a

confirmar´a el resultado de la mezcla. Finalmente,

$ gitk

mostrar´a una representaci´on gr´afica del hist´orico 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 est´an en la rama actual. Si desarrollas en una rama alguna idea que luego quieres desechar, simplemente b´orrala con

$ git

branch

-D

estupidez

Las ramas con sencillas y r´apidas, por lo que probarlas es una buena pr´actica.

1.7. Git como herramienta de colaboraci´on

6

1.7. Git como herramienta de colaboraci´on

Supongamos que Alicia ha comenzado un proyecto nuevo con un repositorio git en /home/alicia/proyecto, y que Roberto, que tiene un directorio home en la misma m´aquina, 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. La copia es exactamente igual al proyecto original, teniendo su propia copia del hist´orico del original. Roberto entonces hace algunos cambios y los confirma:

( editar

rober$

ficheros )

commit

git

-a

( repetir

si

es

necesario )

Cuando est´e 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 de Alicia. Si Alicia ten´ıa cambios en los mismos ficheros, entonces probablemente necesite solucionar manualmente los conflictos. El comando “pull” realiza dos operaciones: recoge los cambios de una rama remota y luego los aplica en la rama actual. T´engase en cuenta que en general Alicia querr´ıa confirmar sus cambios locales antes de realizar el “pull”. Si el trabajo de Roberto tiene conflictos con el de Alicia, ´esta usar´a su ´arbol de trabajo y el ´ındice para resolver los conflictos, y cambios locales existentes podr´ıan interferir con el proceso de resoluci´on del conflicto (git realizar´ıa la operaci´on de recogida de los cambios, pero no los mezclar´ıa — Alicia tendr´a que de alg´un modo librarse de sus cambios locales y luego traer los cambios de Roberto de 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 la pena actualizar, de este modo:

hizo, usando un s´ımbolo “FETCH HEAD” para determinar si tiene algo que merezca la pena actualizar,
hizo, usando un s´ımbolo “FETCH HEAD” para determinar si tiene algo que merezca la pena actualizar,
hizo, usando un s´ımbolo “FETCH HEAD” para determinar si tiene algo que merezca la pena actualizar,

1.7. Git como herramienta de colaboraci´on

7

alicia$

git

fetch

/ home / bob / myrepo

master

alicia$

git

log

-p

HEAD

FETCH_HEAD

Esta operaci´on es segura incluso si Alicia tiene cambios locales sin confirmar. La

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 lo que Roberto tiene en su estado (FETCH HEAD) que ella no ha podido ver con este comando. Si Alicia quiere visualizar lo que hizo Roberto desde que sus trabajos divergieron puede hacerlo con el siguiente comando:

notaci´on de rango “HEAD

FETCH

$ gitk

HEAD

FETCH_HEAD

Esto emplea la misma notaci´on de rangos con dos puntos que vimos antes en git

log.

Alicia puede querer ver qu´e hicieron exactamente los dos desde que divergieron. Puede usar lo notaci´on 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, pero exclude lo que sea alcanzable desde ambos”. Toma nota de que esta notaci´on para el rango se puede emplear tanto para gitk como para git log. Tras inspeccionar lo que Roberto hizo, si no hay nada urgente, Alicia decide continuar trabajando sin aplicar los cambios de Roberto. Si el trabajo de Roberto tuviera algo urgente para Alicia, ella decidir´ıa apartar sus cambios, descargar lo que realiz´o Roberto y luego aplicar su trabajo en los ficheros resultantes. Cuando se trabaja en un grupo peque˜no y cercano, no es habitual interactuar con el 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 operaci´on de “pull” por separado usando el comando git fetch sin tener que mezclar los cambios con su propia rama, usando:

alicia$

git

fetch

rober

1.7. Git como herramienta de colaboraci´on

8

Al contrario que la forma m´as larga, cuando Alicia realiza “fetch” desde Roberto usando el atajo con un repositorio remoto preparado con git remote, los cambios que fueron descargados de almacenan en una rama con informaci´on remota, en este caso rober/master. As´ı que despu´es de esto:

alicia$

git

log

-p

master

rober / master

ense˜na una lista de todos los cambios que Roberto ha hecho desde que cre´o su rama 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 tambi´en actualizando desde su propia rama de segui- miento remoto, de este modo:

alicia$

git

pull

.

remotes / rober / master

N´otese que “git pull” siempre mezcla en la rama actual, sin importar ninguna otra cosa en la l´ınea de comando. M´as tarde, Roberto puede actualizar su repo con los ultimos´ cambios de Alicia empleando

rober$

git

pull

N´otese que no necesita dar la ruta al repositorio de Alicia; cuando Roberto clon´o el repositorio de Alicia, git almacen´o la localizaci´on de su repositorio en la configuraci´on del repositorio, y esa localizaci´on es la usada para el “pull”:

rober$

/ home / alicia /

git

config

-- get

remote . origin . url

(La configuraci´on completa creada por git clone es visible usando git config -l, y git-config explica el significado de cada opci´on.) Git tambi´en mantiene una copia limpia de la rama “master” de Alicia bajo el nombre “origin/master”:

rober$

git

origin / master

branch

-r

1.8. Explorando el hist´orico

9

Si Roberto decide m´as adelante trabajar desde un host diferente, todav´ıa puede realizar 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 o http; mirar git-pull para m´as detalles. Git tambi´en se puede emplear en un modo similar a CVS, con un repositorio central al que varios usuarios env´ıan sus cambios; mirar git-push y gitcvs-migration.

1.8. Explorando el hist´orico

El hist´orico en git est´a representado como una serie de commits inter-relacionados. Ya hemos visto que el comando git log puede listar todos esos commits. N´otese que la primera l´ınea de cada entrada del log tambi´en da un nombre para el commit:

$ git logcommit c82a22c39cbc32576f64f5c6b3f24b99ea8149c7 Author : Junio C Hamano < junkio@cox . net > Date
$ git
logcommit
c82a22c39cbc32576f64f5c6b3f24b99ea8149c7
Author :
Junio
C
Hamano
< junkio@cox . net >
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 trozo inicial del nombre que sea suficientemente largo como para identificar de manera inequ´ı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 estado previo 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

1.8. Explorando el hist´orico

10

N´otese que los commits de mezcla (operaciones “merge”) pueden tener m´as de un padre:

$ git

show

HEAD ^1

#

muestra

el

primer

padre

de

HEAD

( igual

que

HEAD ^)

 

$ git

show

HEAD ^2

#

muestra

el

segundo

padre

de

HEAD

Tambi´en puedes dar tus propios nombres a los commits; tras ejecutar

$ git

tag

v2 .5

1 b2e1d63ff

puedes referenciar a 1b2e1d63ff con el nombre “v2.5”. Si tienes intenci´on de compartir este nombre con otra gente (e.g. para identificar una versi´on de release), deber´ıas crear un objeto “tag”, y quiz´as firmarlo; mirar git-tag para m´as detalles. Cualquier comando de git necesita conocer un commit acepta cualquiera de estos nombres. Por ejemplo:

$ diff

git

v2 .5

HEAD

$ stable

git

branch

v2 .5

#

#

comparar

comenzar

el

una

HEAD

actual

rama

nueva

v2 .5

con ‘‘ stable ’ ’

a

partir

de

v2 .5

$ -- hard

git

reset

HEAD ^

#

resetear

tu

rama

actual

y

directorio

de

trabajo

a

HEAD ^

Ten cuidado con este ultimo´ comando: adem´as de perder cualquier cambio en el directorio de trabajo, eliminar´a los commits m´as recientes de esta rama. Si esta rama es la unica´ que contiene esos commits, se perder´an. Tampoco debemos usar git reset en una rama visible p´ublicamente de la que otros desarrolladores actualizan, ya que obligar´a a realizar operaciones “merge” innecesarias para limpiar los hist´oricos. Si necesitas deshacer cambios que has confirmado, emplea git revert en su lugar. El comando git grep puede buscar cadenas en cualquier versi´on 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 buscar´a en cualquiera de los ficheros que administra en el directorio actual. Por lo que

$ git

grep

‘‘ hello ’ ’

1.8. Explorando el hist´orico

11

es una manera r´apida de buscar simplemente en todos los ficheros administrados por git. Muchos comandos de git aceptan conjuntos de commits, que se pueden especificar de 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

$ -- since = " 2 weeks ago "

git

log

#

commits

de

las

´ultimas

2

semanas

 

$ git

log

v2 .5

Makefile

#

commits

desde

v2 .5

que

afectaron

a

Makefile

Tambi´en se le puede proporcionar a git log un “rango” de commits donde el primero no es necesariamente ancestro del segundo; por ejemplo, si los extremos de las ramas “stable” y “master” divergieron de un commit com´un hace tiempo, entonces

$git

log

stable

master

listar´a los commits realizados en la rama “master” pero no en “stable”, mientras

que

$git

log

master

stable

realizar´a a la inversa. El comando git log tiene un contra: debe presentar los commits en una lista. Cuando un hist´orico 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 m´ultiples colaboradores (como el kernel de Linux o el propio git) tienen operaciones “merge” frecuentes, y gitk realiza un mejor trabajo para visualizar su hist´orico. Por ejemplo,

$ gitk

-- since = ‘ ‘2

weeks

ago ’ ’

drivers /

permite navegar por cualquiera de los commits de las ultimas´ 2 semanas que modificaron cualquier fichero bajo el directorio “driver” (Nota: la fuente de gitk se puede ajustar presionando la tecla Ctrl y “-” o “+”.) Finalmente, la mayor´ıa de los comandos que toman nombres de ficheros opcional- mente permitir´an preceder cualquier nombre de fichero con un commit, para especi- ficar una versi´on concreta del fichero:

$ git

diff

v2 .5: Makefile

HEAD : Makefile . in

1.9. Siguientes pasos

12

Tambi´en 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 distribuido b´asico sobre tus proyectos. Pero, para comprender realmente la potencia y profundidad de git debes entender las dos ideas b´asicas en que se basa:

La base de datos de objetos es un sistema elegante empleado para almacenar el hist´orico de tu proyecto–ficheros, directorios y commits.git debes entender las dos ideas b´asicas en que se basa: El fichero de ´ındice es

El fichero de ´ındice es una cach´e del estado del ´arbol de directorio, usado para crear commits, confirmar cambios en directorios de trabajo y almacenar los diversos ´arboles vinculados en una operaci´on “merge”.de tu proyecto–ficheros, directorios y commits. La segunda parte de este tutorial explica la base de

La segunda parte de este tutorial explica la base de datos de objetos, el fichero de ´ındice y algunos otros conceptos que te permitir´an sacar todo el partido a git. Se puede encontrar en gittutorial-2. Algunos comandos interesantes relacionados con git que te pueden resultar utiles´ en este momento son:

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

git-bisect : cuando hay una regresi´on en tu proyecto, un modo de seguir el bug git-bisect: cuando hay una regresi´on en tu proyecto, un modo de seguir el bug es buscar a trav´es del hist´orico el commit responsable. “Git bisect” te puede ayudar a realizar una b´usqueda binaria por ese commit. Este tipo de b´usqueda es una buena opci´on incluso en el caso de complejos hist´oricos no lineales con numerosas ramas mezcladas.

gitworkflows : da una visi´on general sobre flujos de trabajo recomendados. gitworkflows: da una visi´on general sobre flujos de trabajo recomendados.

gitcvs-migration : git para usuarios de CVS. gitcvs-migration: git para usuarios de CVS.

Cap´ıtulo 2

Un modelo de ramificacion´ exitoso

2.1.

Introducci´on

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

por Vincent Driessen y explicado en su blog [ 2 ]. Figura 2.1: esquema del modelo

Figura 2.1: esquema del modelo de ramificaci´on de Vincent Driessen

13

2.2. ¿Por qu´e git?

14

Aplicado tanto en sus proyectos privados como p´ublicos, ha demostrado ser un modelo exitoso del empleo de git como herramienta de control de versiones para todo el c´odigo. A partir de este punto todo el texto viene de boca de Vincent Driessen.

2.2. ¿Por qu´e git?

Para una discusi´on m´as profunda sobre los pros y contras de Git comparado con sistemas centralizados de control de versiones de c´odigo, podemos mirar por la web. Hay numerosas discusiones sobre el tema. Como desarrollador, prefiero Git sobre todas las dem´as herramientas existentes. Git realmente ha cambiado el modo en que los desarrolladores piensan sobre ramificar y mezclar c´odigo. Desde el cl´asico mundo de CVS/SVN del que vengo, mezclar y ramificar siempre se han considerado peligrosos (“¡Cuidado con los conflictos, te destrozar´an!”) y algo que s´olo se deber´ıa hacer muy de vez en cuando. Pero con Git estas acciones son extremadamente sencillas y r´apidas, y est´an consi- deradas parte del trabajo diario, de verdad. Por ejemplo, en los libros de CVS/SVN, la ramificaci´on 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 b´asicos. Como consecuencia de su simplicidad y naturaleza repetitiva, no se debe seguir teniendo miedo de ramificar o mezclar. Las herramientas de control de versiones deben supuestamente asistir en las tareas de ramificado y mezcla m´as que cualquier otra cosa. Ya hemos hablado suficiente sobre las herramientas, entremos en el modelo de desarrollo. 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 proceso de desarrollo de software bien administrado.

2.3. Descentralizado pero centralizado

El modelo de repositorio que ha demostrado funcionar bien con este modelo de ramificaci´on y que empleamos es el de un repositorio central “verdadero”. N´otese que este repositorio s´olo es considerado el central (ya que Git es DVCS, por lo que no existe un repositorio central desde un punto de vista t´ecnico). Si nos referimos a este repositorio como origin, ya que este nombre es familiar para todos los usuarios de Git.

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

2.4. Las ramas principales

15

2.4. Las ramas principales 15 Figura 2.2: esquema de coordinaci´on entre repositorios T´ecnicamente, esto simplemente

Figura 2.2: esquema de coordinaci´on entre repositorios

T´ecnicamente, 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 est´a enormemente inspirado en otros modelos existen- tes. El repositorio central almacena dos ramas principales con una l´ınea de vida en principio infinita:

masterprincipales con una l´ınea de vida en principio infinita: develop La rama master en origin ser´a

developcon una l´ınea de vida en principio infinita: master La rama master en origin ser´a familiar

La rama master en origin ser´a familiar para todo usuario de Git. De forma para- lela a la rama master, existe otra llamada develop. Consideramos origin/master como la rama principal donde el c´odigo fuente de HEAD siempre est´a en un estado de versi´on de producci´on estable. Consideramos origin/develop la rama principal donde el c´odigo fuente de HEAD siempre refleja el estado de los ultimos´ cambios realizados pendientes de aplicar a la siguiente release. Algunos llamar´ıan a esto “rama de integraci´on”. Cuando el c´odigo dentro de la rama develop alcanza un punto estable y est´a listo para ser liberado, todos los cambios deber´ıan ser aplicados en la rama master y marcados con un tag con el n´umero de versi´on. M´as adelante discutiremos en detalle este proceso.

2.5. Soportando ramas

16

2.5. Soportando ramas 16 Figura 2.3: flujo entre las ramas master y develop Por lo tanto,

Figura 2.3: flujo entre las ramas master y develop

Por lo tanto, cada vez que se aplican cambios en master, es una nueva versi´on de producci´on por definici´on. Siendo muy estrictos en este aspecto, te´oricamente podr´ıamos usar un script para autom´aticamente compilar y desplegar nuestro software en nuestros servidores cada vez que hay un commit en master.

2.5. Soportando ramas

Adem´as de las ramas master y develop, nuestro modelo de desarrollo usa una variedad de ramas auxiliares para ayudar al desarrollo paralelo entre miembros de los equipos, facilitar el seguimiento de las caracter´ısticas, preparar las liberaci´on de nuevas versiones y asistir en la soluci´on r´apida de problemas de producci´on. Al contrario que las ramas principales, ´estas siempre tienen una vida limitada, ya que en alg´un momento se eliminar´an. Los tipos de ramas que podemos emplear son:

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

Ramas para releases (release branches ). release branches).

Ramas para arreglos r´apidos (hotfix branches ). hotfix branches).

Cada una de estas ramas tendr´a un prop´osito espec´ıfico y estar´a sometida a reglas estrictas como de qu´e ramas pueden nacir y con cu´ales se pueden mezclar. Hablaremos de ellas en un minuto.

2.5. Soportando ramas

17

De ning´un modo estas ramas son especiales desde un punto de vista t´ecnico. Las ramas las categorizamos seg´un c´omo las empleamos. Todas son por supuesto simples ramas de Git.

2.5.1. Feature branches

Pueden nacer de: develop

Deben mezclarse con: develop

Convenci´on de nombrado: cualquier cosa excepto master, develop, release-* o hotfix-*

Las ramas de caracter´ısticas del software (algunas veces llamadas ramas de t´opi- cos) se usan para desarrollar nuevas caracter´ısticas para futuras releases. Cuando comenzamos 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 existir mientras la caracter´ıstica est´a en desarrollo, para en alg´un momento volver a mez- clarse con develop (para a˜nadir definitivamente la caracter´ıstica a la release) o ser descartada (en caso de ser un experimento fallido). Estas ramas suelen existir s´olo en los repositorios de los desarrolladores, no en origin.

en los repositorios de los desarrolladores, no en origin . Figura 2.4: flujo de las ramas

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 la rama develop.

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 para a˜nadirlas definitivamente a la siguiente versi´on de release:

$ git checkout develop Switched to branch ’ develop ’ $ git merge --no -
$ 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, incluso si la operaci´on fue realizada con “fast-forward”. Esto evita la p´erdida de informaci´on sobre la existencia hist´orica de la rama y agrupa todos los commits que conforman la caracter´ıstica nueva. Compara:

commits que conforman la caracter´ıstica nueva. Compara: Figura 2.5: comparaci´on de “merge” con fast-forward y

Figura 2.5: comparaci´on de “merge” con fast-forward y sin ´el

2.5. Soportando ramas

19

En el ultimo´ caso es imposible saber del hist´orico de Git cu´ales de los objetos commit 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 de cabeza en este caso, mientras que es mucho m´as f´acil si se utiliz´o el flag --no-ff. S´ı, crear´a unos pocos m´as objetos commit (vac´ıos), pero la ganancia supera con creces a las p´erdidas. Desafortunadamente, a´un no conozco ning´un modo de hacer que --no-ff sea el comportamiento 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

Convenci´on de nombrado: release-*

Las ramas de releases soportan la preparaci´on de una nueva release. Permiten retoques de ultima´ hora, adem´as de servir para la soluci´on de peque˜nos bugs y la preparaci´on de los meta-datos (n´umero de versi´on, fechas, etc.). Haciendo todo esto en la rama de release, la rama develop est´a libre para recibir nuevas caracter´ısticas para la siguiente release. El momento clave para crear una nueva rama de release desde develop es cuando develop (casi) refleja el estado deseado para la nueva release. Al menos todas las nuevas caracter´ısticas que est´an enfocadas a release objetivo deben haber sido aplica- das sobre develop en este momento. Todas las caracter´ısticas para futuras releases deber´an esperar a que esta rama release haya sido creada. Es justo despu´es del comienzo de la rama release cuando a la release se le asigna un n´umero nunca antes. Hasta ese momento, la rama develop reflej´o los cambios para la siguiente release, pero no est´a claro si la release ser´a la 0.3 o la 1.0 hasta que comienza la rama. Esa decisi´on se toma al principio de la rama release y se lleva a cabo seg´un las reglas de versionado del proyecto.

Creando una rama release

Las ramas release se crean a partir de la rama develop. Por ejemplo, supongamos que la versi´on actual es la 1.1.5 y que pr´oximamente se liberar´a otra. La rama develop est´a lista para la siguiente release, y hemos decidido que ser´a la versi´on 1.2 (en lugar de la 1.1.6 o 2.0). As´ı que ramificamos y le damos a la rama un nombre reflejando su versi´on:

$

git

checkout

-b

release -1.2

develop

Switched

to

a

new

branch

" release -1.2 "

$ ./ bump - version . sh

1.2

2.5. Soportando ramas

20

Files modified successfully , version bumped to 1.2. $ git commit -a -m " Bumped
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 ( -)

Despu´es de crear la rama y cambiarnos a ella, le asignamos el n´umero de versi´on. Aqu´ı, bump-version.sh es un script imaginario que realiza cambios en algunos fi-

cheros de la copia de trabajo para reflejar la nueva versi´on. (Esto puede ser cambiado

a mano, obviamente - lo importante es que algunos ficheros cambian) Entonces se

realiza el commit de la versi´on con el n´umero asignado. Esta nueva rama podr´a existir por un tiempo, hasta que la release haya sido libera- da definitivamente. Durante ese tiempo, arreglos a bugs ser´an aplicados en esta rama (en lugar de en develop). A˜nadir caracter´ısticas nuevas importantes est´a totalmente prohibido. Deben ser aplicadas en develop, y por tanto, esperar a la siguiente release.

Acabando con una rama release

Cuando una rama release est´a lista para convertirse en una release real, debemos

seguir 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 definici´on). A continuaci´on, a ese commit en master se le debe poner un tag para referenciarlo en

el futuro en el hist´orico de versiones. Finalmente, los cambios realizados en la rama

de release deben ser mezclados de nuevo en develop, para que futuras releases sigan conteniendo los cambios. Los dos primeros pasos en Git:

$ git checkout master Switched to branch ’ master ’ $ git merge --no -
$ 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. Quiz´as quieras usar los flags -s o -u <clave> para firmar el tag criptogr´afica- 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 -
$ git
checkout
develop
Switched
to
branch
’ develop ’
$ git merge --no - ff release -1.2
Merge
made
by
recursive .
( Summary
of
changes )

2.5. Soportando ramas

21

2.5. Soportando ramas 21 Este paso puede llevar f´acilmente a un conflicto, y en tal caso
2.5. Soportando ramas 21 Este paso puede llevar f´acilmente a un conflicto, y en tal caso
2.5. Soportando ramas 21 Este paso puede llevar f´acilmente a un conflicto, y en tal caso

Este paso puede llevar f´acilmente 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 que no la necesitamos m´as:

$ git

Deleted

branch

-d

branch

release -1.2

release -1.2

( was

ff452fe ) .

2.5.3. Hotfix branches

Pueden nacer de: master

Deben mezclarse con: develop y master

Convenci´on de nombrado: hotfix-*

Las ramas para arreglos r´apidos se parecen mucho a las ramas de release en que tambi´en est´an pensadas para preparar una nueva versi´on de release, pero en este caso no planeada. Nacen de la necesidad de actuar inmediatamente ante un estado no deseado en la versi´on actual en producci´on. Cuando un bug cr´ıtico de la versi´on actual debe ser solucionado inmediatamente, una rama de arreglo r´apido puede nacer del tag correspondiente de la rama master que marca la versi´on en producci´on. La esencia es que el trabajo de miembros de equipo (en la rama develop) puede continuar, mientras otra persona est´a preparando una soluci´on r´apida.

Creando una rama de arreglo r´apido

Las ramas para arreglos r´apidos se crean a partir de la rama master. Por ejemplo, digamos que la versi´on 1.2 es la release actual y que est´a causando problemas debido a un bug grave. Pero los cambios en develop son todav´ıa inestables. Entonces lo aconsejable 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
$
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 ( -)

2.5. Soportando ramas

22

2.5. Soportando ramas 22 Figura 2.6: flujo de las ramas de arreglos r´apidos (hotfix branches) No

Figura 2.6: flujo de las ramas de arreglos r´apidos (hotfix branches)

No nos debemos olvidar de cambiar el n´umero de la versi´on en el momento en que ramifiquemos. Entonces, arreglamos el bug y hacemos uno o m´as commits con su soluci´on.

$ git commit -m " Fixed severe production problem " [ hotfix -1.2.1 abbe5d6 ]
$ 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 r´apido

Cuando se termina, la soluci´on al bug debe ser mezclada en la rama master, pero tambi´en necesita mezclarse de vuelta en develop, para asegurarnos de que el bug no ocurrir´a de nuevo en la siguiente release. Es un proceso an´alogo al realizado cuando las 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 -
$ 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

2.6. Resumen

23

2.6. Resumen 23 De nuevo, quiz´as quieras usar los flags -s o -u <clave> para firmar
2.6. Resumen 23 De nuevo, quiz´as quieras usar los flags -s o -u <clave> para firmar
2.6. Resumen 23 De nuevo, quiz´as quieras usar los flags -s o -u <clave> para firmar

De nuevo, quiz´as quieras usar los flags -s o -u <clave> para firmar el tag crip- togr´aficamente. Luego incluimos el arreglo tambi´en en develop:

$ git checkout develop Switched to branch ’ develop ’ $ git merge --no -
$ git
checkout
develop
Switched
to
branch
’ develop ’
$ git merge --no - ff hotfix -1.2.1
Merge
made
by
recursive .
( Summary
of
changes )

La excepci´on a esta regla es que, cuando actualmente existe una rama de release,

la soluci´on al bug ser´a mezclada en esa rama de release en lugar de en develop.

Aplicar la soluci´on en la rama de release conduce a que en alg´un momento sea tambi´en aplicado a la rama develop, cuando la rama de release se termine. (Si el trabajo en develop requiere la soluci´on al bug inmediatamente y no podemos esperar a que la rama de release se termine, tambi´en podemos aplicar la soluci´on en develop sin problemas.) Finalmente, eliminamos la rama temporal:

$ git

Deleted

branch

-d

branch

hotfix -1.2.1

hotfix -1.2.1

( was

abbe5d6 ) .

2.6.

Resumen

Aunque realmente no hay nada nuevo en este modelo de ramificaci´on, la imagen

general en la que se basa ha demostrado ser tremendamente util´ en nuestros proyectos. Conforma un modelo mental muy elegante que es f´acil de comprender y permite

a miembros de equipos compartir una unica´ visi´on del proceso de ramificaci´on y liberaci´on del software.

Cap´ıtulo 3

Comenzando a trabajar con Git en Windows

En este apartado abordaremos el proceso de creaci´on del repositorio para su poste- rior funcionamiento en NetBeans. Dado que el repositorio no contiene un proyecto de NetBeans completo 1 son necesarios algunos pasos adicionales para lograr su correcto funcionamiento.

3.1. Instalaci´on de la herramienta

Descargaremos el entorno Git para Windows de la p´agina del proyecto sysgit:

1. Nos descargamos la versi´on m´as reciente del entorno (los archivos con formato Git-x.x.x.x) de su web oficial.

2. Durante la instalaci´on se aconseja instalar las dos entradas del men´u de contexto en lugar del git-cheetah.

Podemos comprobar la correcta instalaci´on del plugin si en el navegador de Win- dows al hacer click derechon sobre una carpeta existen las opciones Git GUI Here y Git Bash Here, a las cuales tambi´en se puede acceder por el men´u de inicio a trav´es de Git.

3.2. Inicializaci´on del repositorio para NetBeans

A la hora de inicializar el repositorio para trabajar en NetBeans, la forma m´as sencilla es disponiendo de una copia local de DeporXest como proyecto de NetBeans. En tal caso se har´a lo siguiente:

1 al 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 muchos usuarios que no empleen ese entorno.

24

3.2. Inicializaci´on del repositorio para NetBeans

25

1. Iniciaremos la interfaz gr´afica de Git (es indiferente si con el click derecho sobre una carpeta cualquiera o por el men´u de inicio), y seleccionamos Clone Existing Repository.

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 ser´a temporal).

4. Antes de descargar nos pedir´a la clave ssh de nuestra cuenta en SourceForge.

5. Copiamos todo el contenido de la carpeta que acaba de crear (incluyendo la carpeta oculta .git) dentro de la carpeta del proyecto DeporXest de NetBeans que 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 el repositorio y no la ventana inicial para crear, clonar y abrir repositorios.

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

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 tambi´en las librer´ıas que necesita el pro- yecto, manteniendo la misma ruta que en la configuraci´on original del proyecto (podemos comprobar la ruta con Click derecho sobre el proyecto -> Properties -> Libraries).

Una vez que la configuraci´on de las librer´ıas est´a lista, de nuevo podemos com- probar que todo es correcto si Git GUI nos abre el repositorio en lugar de la pantalla inicial.

Referencias

[1] Tutorial oficial de Git:

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

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

[3]

26