Guía rápida de GIT – Parte II

Siguiendo con la introducción a GIT que se publicó hace unos días, hoy vamos a ver como realizar unas cuantas operaciones más.

Si en la primera parte de esta guía introductoria vimos como configurar nuestro usuario, crear un repositorio y enviar nuestras modificaciones a un repositorio remoto en esta vamos a ver cómo descargar todo el contenido de un repositorio remoto, actualizar la copia local y cómo realizar branches y tags.

Manos a la obra!

Trabajando con un repositorio remoto

Los sistemas de control de versiones centralizados, como Subversion, tienen en su diseño una gran vocación de trabajar en red y así poder organizar el trabajo en equipo. Justamente por la facilidad a la hora de poner en marcha un repositorio a través de la red, a veces se abusa de estos sistemas y se decide (erroneamente) utilizar este tipo de sistemas para la gestión documental de los proyectos.

GIT provee, al igual que Subversion, una gestión de la descarga inicial y actualización desde repositorios remotos, pero al ofrecer un abanico más amplio de posibilidades es necesario aprender un grupo de comandos adicional. Siguiendo la comparación en paralelao con Subversion, podríamos empezar la revisión de estas funcionalidades de GIT con el equivalente a la operación checkout del hermano “centralizado”.

Cuando queremos descargar todo el contenido de un repositorio GIT, hace falta disponer del método de acceso (recordemos que generalmente se utiliza el protocolo HTTP o conexiones seguras como SSH pero puede haber otros métodos) y ejecutar el comando clone

git clone http://usuari@servidor/repositorio.git

Este comando nos va a generar una copia con lo que en ese momento podamos encontrar en el repositorio alojado en el servidor remoto y debemos tener en cuenta que puede tardar unos minutos.

Si, por el contrario, ya tenemos una copia de un proyecto y queremos actualizar sus contenidos el comando que deberemos usar es el siguiente:

git pull

En este comando podemos observar que, aunque GIT nos obligue a realizar ciertas operaciones de forma explícita (que en otros sistemas de control de versiones quizá son prescindibles), a veces tiene implementadas pequeñas funcionalidades que nos facilitan la vida cuando tenemos que lidiar con él (como en este caso, que recuerda el servidor remoto del que se descargó el repositorio).

Tags

El significado que puede tener la palabra “tag” en un sistema de control de versiones es muy diferente del que puede tener en nuestras redes sociales preferidas :-). El concepto de tag, utilizado desde hace tiempo en los sistemas de control de versiones, sirve para marcar un estado concreto del desarrollo que nos interese marcar para facilitar el acceso al mismo. Estos estados normalmente se asocian a hitos de proyectos o a versiones estables que se quieren poner a disposición de los compañeros de desarrollo o público en general.

La creación de tags en Subversión es un proceso prácticamente manual. Para definir uno de estos estados “destacados” se copia todo el código del repositorio en una carpeta destinada a albergar ese tag y se deja ahí hasta el fin de los días. GIT gestiona de forma mucho más eficiente este tipo de operaciones y nos permite definir un tag simplemente con unla ejecución de un comando -y sin una copia masiva de ficheros-.

git tag nombretag
git push --tags

Estrictamente la creación del tag únicamente requiere la ejecución del primer comando, pero nosotros hemos añadido un segundo comando para enviar el tag al servidor remoto. Hemos añadido este comando porqué este es el funcionamiento habitual de los tags, pero es verdad que usuarios más habituados al uso de sistemas de control de versiones pueden ver en los tags “locales” una oportunidad de mejorar la gestión del desarrollo a nivel personal.

Branches

El uso que principalmente se da a los branches es el de separar el desarrollo de componentes o funcionalidades de la rama principal del proyecto. Para esto se crea un branch, se desarrolla el componente o funcionalidad correspondiente y posteriormente se juntan las modificaciones del branch con el código en la rama principal. Esta última operación normalmente implica la correción de conflictos surgidos de la evolución del software en paralelo y puede tomar más tiempo de lo esperado.

Siguiendo con la comparación que estamos haciendo con Subversion, encontraremos que con GIT es mucho más sencillo generar branches que los que resultaba hacerlo con SVN. Las diferencias són muy parecidas a las que nos hemos encontrado en el caso de los tags, mientras que en Subversion es necesario copiar todo el código a un directorio destinado a ese branch, en GIT podemos generar uno en el acto y cambiar nuestro árbol de ficheros al nuevo branch en cuestión de segundos.

Vamos a ver un ejemplo de la creación de un branch en GIT:

git branch nombrebranch
git checkout nombrebranch

Igual que con los tags, el único comando obligatorio es el primero. Pero, hay que tener en cuenta que la creación del branch, en GIT, no implica un cambio del actual árbol de directorios al nuevo branch, simplemente lo crea. Para realizar ese cambio tenemos el comando checkout (no confundir con la operación checkout de SVN!).

Hasta aquí ningún problema, los branches son fáciles de crear y GIT permite estar trabajando en uno nuevo en cuestión de segundos pero… que fácil seria la vida del desarrollador si no tuviesemos que hacer nunca la operación maldita, EL MERGE.

La operación merge (enemiga natural de los equipos de desarrolladores :-D ) consiste en traspasar los cambios de un branch a otro. Habitualmente esto se hace para enviar los canvios realizados para implementar un nuevo componente a la rama principal y para realizar esta tarea (de forma automática) ejecutamos el comando siguiente:

git merge nombrebranch

NOTA: Para realizar esta operación con este número de parámetros, debemos estar trabajando en un branch diferente a “nombrebranch”. Si no es así, hay otras formas de llamar el comando merge pero requieren un poco más de conocimiento de GIT.

Si no existen conflictos entre un branch y otro (yes! I had a dream… A dream where two branches do not have to conflict with each other!! :-D ) la operación merge habría acabado aquí; pero en el caso de existir (9 de cada 10 desarrolladores se encuentran conflictos cuando hacen un merge, el restante simplemente no ha desarrollado nada), GIT nos marcaría los archivos con conflictos y seríamos nosotros los encargados de editar esos archivos, añadir los cambios al repositorio y confirmarlos.

Añadir los cambios al repositorio y, posteriormente, confirmarlos requiere la ejecución de un par de comandos que ya vimos anteriormente pero que no está de más recordarlos:

git add fichero-con-conflictos-resueltos
git commit -m “he resuelto los conflictos”

Bueno, y hasta aquí hemos llegado. Pensad que el 90% o más de las funcionalidades que se usan de los sistemas de controles de versiones han sido explicadas con más o menos detalle en esta guía básica repartida en dos partes. Y como creo que he cumplido con el título de la guía (Guía básica), vamos a cerrar aquí esta introducción a GIT. En caso de describir funcionalidades más avanzadas os las comunicaré bajo otros títulos más acordes al nivel de las explicaciones :-).

Espero que esta guía os sirva y controlad (vuestras versiones!)