Al desarrollar software nos encontramos con la necesidad de gestionar los cambios que se van haciendo en el código y que, al trabajar en equipo, todos los miembros del equipo dispongan siempre de una copia de este código en la que poder trabajar y, más adelante, integrar estos cambios. Para facilitar este trabajo tenemos los sistemas de control de versiones, como Git, que nos permiten seguir y gestionar los cambios que se producen en el código a lo largo del tiempo: para ello vamos a ver el uso de Git y el flujo de trabajo con GitFlow.

Qué es Git

Git es un software de control de versiones que desarrolló Linus Torvarlds (el creador de Linux) , para conseguir coordinar el trabajo con sus colaboradores.

Hay que tener en cuenta que Git presenta una arquitectura distribuida, por lo que en vez de que el código esté en un único lugar, cuando un desarrollador hace una copia de trabajo de este código, genera a su vez un repositorio que puede contener el historial completo los cambios que se han ido realizando en ese código.

Repository, revision, commit… Algo de vocabulario

Al trabajar con Git y el control de versiones te nos encontramos con una serie de términos que es necesarios conocer para saber que se está haciendo:

  • Branch (rama). Una rama es una bifurcación en el código en un determinado punto que permite desarrollar el código sin que afecte a las otras ramas. Por ejemplo, podemos hacer una rama para añadir una nueva funcionalidad a nuestro código.
  • Checkout (verificar). En Git este comando nos permite tanto crear ramas como movernos entre ellas.
  • Clone (clonar). Nos permite obtener una copia del repositorio de forma local para poder trabajar con ella.
  • Commit (cometer). Se trata de una confirmación de un grupo de cambios que se ha realizado en el código. Esta confirmación contiene, tanto estos cambios como un mensaje descriptivo y cierta información adicional (autor, fecha…).
  • Conflict (conflicto). Se trata de un problema en la integración de los cambios que, provenientes de fuentes, se quieren hacer en el mismo documento y el sistema es incapaz de resolverlo. En este caso es el propio desarrollador quien debe solucionar el conflicto.
  • Diff (cambio). Un cambio o diff corresponde a una variación específica del código. El control de las versiones se realiza mediante el seguimiento de estas diferencias entre las versiones de los archivos.
  • Head (cabeza). Head se refiere al commit en el que está el repositorio en cada momento (y que suele coincidir con el último commit de la rama de trabajo).
  • Merge (fusionar). Merge es la fusión de dos ramas, es decir cuando queremos integrar los cambios realizados en el código de una rama a otra. Por ejemplo, integrar los cambios de una rama en la que hemos añadido una nueva funcionalidad a la rama principal.
  • Pull (bajar). Es el proceso inverso a push, lo que se consigue es bajar el código del repositorio central al local para actualizarlo.
  • Pull request (solicitud de cambios). Se trata de una petición que se hace al propietario del código para actualizarlo con nuestros cambios.
  • Push (subir). Nos permite subir los cambios de código que tenemos en nuestro repositorio local al repositorio central para actualizarlo, de forma que el resto de desarrolladores se lo puedan descargar.
  • Repository (repositorio). Es el lugar en que se almacena tanto el código como el historial de cambios que se han realizado.
  • Tag (etiqueta). Tal como su nombre indica, nos permite etiquetar diferentes revisiones de un proyecto para poder identificarlas más fácilmente (se suelen usar, por ejemplo, con las versiones de un proyecto liberadas a producción).

Manos a la obra

Una vez visto algo de vocabulario, vamos a ver cómo empezar a usar git en nuestros proyectos de forma básica.

En primer lugar creamos un directorio para nuestro proyecto:

A continuación inicializamos el repositorio con git init:

Ahora vamos a crear un fichero y a añadirlo al repositorio con git add:

git add nos permite preparar los cambios para poder confirmarlos posteriormente. Las opciones más usadas son git add {file}, git add {directory} o git add . , que añade todos los ficheros.

Lo que vamos a hacer ahora es usar git commit para fijar las modificaciones realizadas:

El parámetro (flag) -m nos permite confirmar los cambios con la adición de un mensaje (lo que nos permite más adelante en el proyecto tener una idea de qué cambios se introdujeron en cada punto).

Ahora ya hemos hecho algunos cambios en nuestro repositorio. Para conocer en qué estado está utilizamos git status:

Que nos indica que estamos en la rama master (que es la principal y la que se crea al iniciar el repositorio) y que todos los cambios están verificados.

Ahora vamos a ver cómo crear una rama y posicionarnos en esta. Por ejemplo, vamos a crear la rama develop:

Con esto creamos la rama develop y nos movemos a ella. Todo esto se puede hacer en un único paso con el siguiente comando:

Ahora vamos a suponer que hacemos un cambio en el fichero readme.md.

Si ahora hacemos git status, nos devuelve la siguiente información:

Es decir, que estamos en la rama develop y que tenemos cambios no verificados (y que hay que hacerlo).

Por tanto, hacemos:

Bien, ahora ya tenemos la rama develop con código nuevo, verificado, y queremos que también esté en la rama master. Lo que tendremos que hacer es ir a la rama master y hacer merge de la rama develop sobre la rama master:

Al hacer esto nos aparece el editor de texto que nos pide añadir un mensaje al merge.

Una vez añadido el mensaje obtenemos en pantalla:

Al utilizar el comando –no-ff (no fast-forward), hemos hecho un merge de develop a master manteniendo develop.

GitFlow: organización de los repositorios

Cuando trabajamos en un proyecto, sobre todo si lo hacemos con más desarrolladores, se hace necesario establecer algún sistema de organización del repositorio de control de versiones, que nos permita de una manera ágil ir creando las nuevas funcionalidades, corrigiendo los errores que aparecen e integrarlo todo para sacar el código a producción.

Para ello utilizaremos un sistema de ramas y de trabajo desarrollado por Vincent Driessen y que conocemos por GitFlow. Según este sistema, deberíamos tener un par de ramas principales y otras secundarias o de apoyo.

master (principal)

Esta rama contiene el código de cada una de las versiones que se ha ido subiendo a producción. Además, cualquier código que se suba a esta rama debe estar preparado para ser lanzado a producción.

develop (principal)

Esta rama incluye el código de la siguiente iteración o versión del proyecto, y en ella se integran las nuevas funcionalidades que se van desarrollando para esa versión.

release (secundaria)

Esta rama sale de develop, y contiene el código de la versión que se va a liberar en breve a producción. En esta rama también puede corregirse algún error antes de publicarla. Tras publicar la versión, esta rama deberá integrarse tanto en develop como en master.

Para nombrar esta rama, se suele usar la siguiente convención: release-{número de la versión}. Por ejemplo, para crear una rama release para la versión 2.3.5 desde develop haríamos lo siguiente:

feature (secundaria)

Se trata de ramas que, al igual que la rama release, derivan de la rama develop y contienen el código correspondiente a nuevas funcionalidades. Normalmente son ramas que solo existen en el repositorio local de cada desarrollador. Cada vez que se finaliza y aprueba una funcionalidad, su rama se integra en develop.

Por convención este tipo de ramas se nombra como feature/{nombre de la funcionalidad}. Por ejemplo, para crear una rama que contuviera la funcionalidad de sincronizar la información de un usuario podríamos hacer lo siguiente:

hotfix (secundaria)

Una rama hotfix se crea para corregir un error que hay que arreglar de forma urgente en el código que hay en producción. Por eso deriva de la rama master y, una vez corregido, se integra tanto en la rama master como en la rama develop.

La nomenclatura de estas ramas sigue una patrón parecido al de las ramas release: hotfix-{número de la nueva versión}. Así, si tenemos que hacer un hotfix en la versión 2.3, la rama hotfix la crearíamos de la siguiente forma:

Es decir, desde master creamos una rama hotfix con el valor de la nueva versión que se subirá a producción (la antigua es la 2.3 y la corregida será la 2.3.1).

Etiquetado de la rama master

Cada vez que lanzamos una versión a producción e integramos el código en la rama master, es muy recomendable etiquetar esa integración, de forma que podamos tener identificado el códifo final de cada versión.

Para ello utilizaremos en comando git tag. Por ejemplo, si queremos etiquetar en master el código de la versión 2.3.1 haremos los siguiente:

Con -a hemos etiquetado la versión y con -m hemos añadido un mensaje.

Extensiones git para la implementación de GitFlow

Acabamos de ver una serie de comandos que nos permiten gestionar los repositorios de nuestro código: crear ramas, movernos entre ellas, integrarlas… Pero gracias a una serie de extensiones git, podemos realizar todo esto de una manera más sencilla. Para ello simplemente deberemos instalar git-flow en nuestro ordenador.

En la documentación de git-flow se explica como instalar estas extensiones en diferentes entornos. En el caso de macOS, lo podemos hacer con Homebrew:

Una vez instalado, podemos inicializar un repositorio, con una estructura básica de ramas, mediante el siguiente comando:

Y responder a las preguntas que se nos formulen:

Gestión de las diferentes ramas con git-flow

Feature

Nos muestra un listado de todas las ramas tipo feature.

Con esta instrucción creamos una nueva rama llamada {feature_name} que deriva de develop y nos posiciona en dicha rama.

Este comando integra (merge) la rama {feature_name} en la rama develop, nos posiciona en la rama develop y borra la rama {feature_name}.

Este comando sirve para publicar la rama {feature_name} en un repositorio remoto.

Con este comando nos descargamos la rama {feature_name} del repositorio remoto.

Release

Nos muestra un listado de todas las ramas tipo release.

Con esta instrucción creamos una nueva rama llamada {release_name} que deriva de develop y nos posiciona en dicha rama. [BASE] es un valor opcional que corresponde al hash sha1 de la integración (commit) a partir de la cual queremos que derive esta rama.

Este comando realiza diferentes tareas: etiqueta la rama con {release_name}, integra (merge) la rama {release_name} en la rama develop y en la rama master, y acaba borrando la rama release (recuerda publicar las etiquetas con git push origin –tags).

Este comando sirve para publicar la rama {release_name} en un repositorio remoto.

Hotfix

Nos muestra un listado de todas las ramas tipo hotfix.

Con esta instrucción creamos una nueva rama llamada {version} que deriva de master y nos posiciona en dicha rama.

Este comando realiza diferentes tareas: etiqueta la rama con {version}, integra (merge) la rama {version} en la rama develop y en la rama master. También etiqueta la rama master con la versión de hotfix.


0 comentarios

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Sígueme en Feedly