Trabajando con GIT

Git es un sistema de control de versión distribuido free y open source que fue diseñado para manejar proyectos que van de muy pequeños hasta inmensos proyectos, como por ejemplo Linux. Git nos permite el manejo de estos de una manera rápida y eficiente.

Según el sitio oficial de git (https://git-scm.com/), Git es una herramienta facil de apreder. No sé qué tan de acuerdo estoy con esa frase. Ya que Git tiene una curva de aprendizaje no despreciable. Según este mismo sitio supera ampliamente otras herramientas de control de versión tales como Subervision, CVS, Perforce y ClearCase.

Como cualquier control de versión permite llevar a cabo un seguimiento de archivos que van cambiando. Esto facilita el trabajo de muchas personas en un mismo proyecto, incluso en un mismo archivo. Git se usa ampliamente en la gestión de software open source aunque también es utilizado en empresas privadas, obviamente. Recordemos que el autor de Git fue el gran Linus Torvalds. Linus creó Git en 2005 para llevar el control de versión de Linux. Dos meses después de su desarrollo es mantenido por Junio Hamano.

En mi caso, comencé a utilizar Git hace menos de 3 años. La primera impresión que me dio Git fue: “Estoy es complicado”. Vamos, no voy a negar que apenas lo conocí, o mejor dicho, que sentí la necesidad de usarlo, no me gustó y lo veía muy complejo de usar. Luego, después de varios dolores de cabeza, de leer, de buscar en foro pude decir: “Es una herramienta poderosa”. Si bien existe un muchos blogs, mucha información sobre cómo utilizar esta herramienta, el problema principal es que tienes que pensar, no solo la gestión del software, si no también el desarrollo de una manera diferente. Debes aprender qué es un branch, para qué sirve; qué es un merge; por qué me aparecen conflictos cuando hago un merge; etc.

En esta entrada no tengo como intención realizar un tutorial de Git, ni explicar los conceptos que este maneja. Más bien, me interesa escribir una guía de buenas prácticas para llevar a cabo una buena gestión del software y del trabajo colaborativo. Lo más completo que pude encontrar hasta el momento es la guía de Vincent Driessen. Él muestra cual es un flujo de trabajo con Git, las ramas que se deben crear y en qué momento se debe hacer, y obviamente cuando una rama debe ser eliminada.

Así que comencemos.

Versionando software

Antes de comenzar quisiera hablar un poco sobre el versionado del software. No existe una regla estricta de cómo hacer esto. Cada organización decide su forma de versionar el código y de cómo llamarlo.

Por ejemplo, Linux utiliza un sistema sencillo de versionado. Generalmente, la versión está compuesta por 4 números (separados por punto). El primer número hace referencia a la versión del kernel. Por lo general, la primera versión de un software o paquete suele ser el cero. El segundo grupo del número hace referencia a un major revision, esto es un release estable. Por ejemplo, supongamos que tienes un proyecto en las fase inicial, digamos un paquete que cumple con lo mínimo para empezar a ser usado o testeado. Aquí es dónde puedes decir tengo la versión 0.1 de mi paquete. A medida que vayas agregando nuevas funcionalidades, corrigiendo bugs mayores o críticos, y ya tienes tu nueva “versión”, a esta se la puede llamar 0.2. Si consideras que esta cambió demasiado, con respecto al original, ya debes pensar en crear una versión 1.x de tu software.

El tercer grupo de número, suelen ser de revisiones menores. Este es cuando se corrigen bugs menores o cuando se agregan features. Este grupo es más “veloz” que los demás. Cuando por ejemplo, desarrollar tu software, lo mandas a testing, y estos encuentran bugs, que consideras que son rápidos de corregir y que no representan grandes cambios en tú código tranquilamente, puedes incrementar el tercer grupo.

El cuarto grupo, ya comienza a ofuscarse. A mi parecer este tendría sentido llevarse a cabo en proyectos a gran escala, digamos un Linux, un CPython, etc. y es más utilizando entre equipos de desarrollo, o cuando los tiempo apremian. Este grupo suele ser utilizado acompañados por letras. Por ejemplo rc1, indica un Release Candidate 1. Este vendría a ser un release no oficial, que un grupo de desarrollo lo libera para que otros lo prueben o para ser utilizado en otro equipo, pero con la conciencia de que no es la versión final. Por ejemplo, una organización que tiene varios sistemas de software, desarrollados por diferentes equipos, y que estos sistemas se deben relacionar, muchas veces se produce un cuello de botella en cual un equipo debe esperar a que liberen un versión del Software A para comenzar a desarrollar o testear el Software B. Si existiera una buena Ingeniería de Sistemas, este problema no ocurriría, ya que se tiene muy claro, cual es comportamiento del producto A y como afecta esto al producto B.

Este no es el único sistema de versionado. Por ejemplo, metodologías ágiles, dónde se liberan paquetes digamos una vez por mes (o menos) se suele utilizar el sistema:

año.mes.minor

Por ejemplo Ubuntu usa este sistema.

Otra forma de versionado que me parece interesante es el de Python, este agrega más detalle y más formas de versionado. Agrega los conceptos de pre release, post release y development release.

El versionado que propone Python es muy interesante, pero escapa al objetivo de este post. Recomiendo leer el PEP440

Comenzando un proyecto

Bueno, aquí estamos. Tenemos la idea. Tenemos el nombre (por lo menos). Ya con esto es suficiente por ahora. Lo primero, obviamente es crear el repositorio. Ya sea, usando algún servicio (Github, Gitlab, Bitbucket, etc) o en un repositorio en tu máquina. Una vez que está iniciado (git init) y/o clonado (git clone) se crea por defecto una rama master.

Lo ideal es por defecto tener dos ramas:

  1. master

  2. develop

La rama master es la que mantiene la última versión de nuestra sistema, que es descargable y “usable” por los usuarios. Es decir, si yo entro a un repositorio, debería poder clonar la rama master, compilar si es necesario y ya podría comenzar a utilizar el sistema sin ningún problema. Sin problema, tomado entre pinzas. Siempre van a salir bugs, pero la idea es que el master sea, en el mayor grado posible, libre de bugs (conocidos).

Ahora, ese sistema va a crecer (sino no haría falta usar un sistema de versionado). Pero es imposible comenzar a trabajar en la rama master. Ya que, al menos que se hagan commits solo y exclusivamente después de haber finalizado y testeado una versión, la rama master iría creciendo día a día, y con él se irán introduciendo bugs, también día a día. No nos podemos dar el lujo de que cuando un usuario quiera descargar nuestro sistema, se encuentre con una versión inestable. Por ello, se suele utilizar una rama develop.

Por ello, se recomienda una vez creado la rama master, realizar un checkout -b develop con el fin de tener una copia del original. A partir de este momento todos los commits se deben realizar en la rama develop. Cuando ya estamos seguros de que esta rama es lo suficientemente estable, y estamos convencidos de que es momento de generar una nueva versión, simplemente realizamos un merge de la rama master y la develop.

Versioning Branch o release branch

En aquellos proyectos en lo que pueden coexistir, o se mantienen varias versiones de software, es importante mantener a cada uno de estas versiones en una rama diferente.

Es decir, estamos trabajando en la rama develop. Vamos realizando commits por cada resolución de bugs, y/o nuevos features. Luego llegamos al punto en el que hay que crear una nueva versión. Para ello el flujo es el siguiente:

  1. Hacemos un merge entre la rama master y develop.

  2. De la rama develop creamos una rama con el nombre de la nueva versión, supongamos v1.0.0.

  3. Creamos un tag en la rama master con la versión v1.0.0. Esto como para tener un historial de dónde se realizó la bifurcación.

A partir de este momento, para aquel equipo que da soporte a esa versión, pasaría a ser una rama master.

Ojo!, no se debería trabajar en rama develop y hacer merge en las ramas versión. Develop es exclusivo de la rama master.

Supporting branches

Las ramas de soporte tienen un corto periodo de vida. Son creados para cosas puntuales. Estas se dan sobre todo en proyectos de software con varios equipos, resolviendo bugs y/o agregando features. Las ramas de soporte son las siguientes:

  • Feature branch

  • hotfix branch

Feature branch

Este branch es utilizado para agregar features. Debe ser creado a partir de la rama develop. Supongamos que estamos trabajando en lo que vendría a ser una nueva versión de nuestro proyecto. La nueva versión (casi de manera obvia) tendrá nuevas features. Ahora, en un proyecto con varios equipos trabajando en las features, sería una mala decisión que todos trabajen sobre la misma rama (develop), por ello se recomienda crear una rama feature (feature branch) para trabajar. Así cada equipo “trabaja en lo suyo” y no se estorban entre sí.

La feature branch sólo debería ser creada a partir de la rama develop. Como ya vimos no se debería trabajar en la rama master, y tampoco es posible trabajar en las ramas release, ya que no sería una buena práctica (o no es costumbre) agregar nuevas features a un release.

Una vez que se crean los features de debe realizar un merge con la rama develop (Con mucha mucha mucha suerte, no se tendrá conflictos al realizar el merge).

Dentro de las ramas de soporte, esta rama es la que mayor tiempo de vida tiene.

Hotfix branch

Tal como lo indica su nombre, estas ramas se utilizan para corregir bugs. De nuevo, supongamos un equipo que está trabajando en una nueva release, o está manteniendo una release, se recomienda crear una rama “hotfix” haciendo referencia al número del issue o nombre del issue.

Las ramas hotfix deberían ser creadas a partir de la rama develop o las ramas release. Una vez que el issue es resuelto, esta rama debería morir.

Conclusión

El flujo de trabajo puede costar en un principio, creo que la mayoría de los que recién se inician (igual pasa en todo) lo verán difícil, sin sentido. Con el tiempo, a medida que lo vas utilizando, y sobre todo, si en algún momento les toca gestión un proyecto, verán que es muy importante tener un “step-by-step” sobre cómo trabajar en estos tipos de proyectos.

Ojalá alguien lea este post, y espero sus comentarios, y opiniones que aporten al desarrollo de un “step-by-step” más o menos general, de cómo gestionar un proyecto de software colaborativo usando Git.