Introducción a Git: repaso a los conceptos generales

Algo que como desarrolladores debemos conocer muy bien y saber manejar es el uso de repositorios de control de código fuente, garantizando que los desarrollos realizados están debidamente versionados, teniendo una trazabilidad de los cambios y del estado de la aplicación en los distintos ambientes. A día de hoy una gran parte de los repositorios de control de código fuente está usado Git, y cada vez son más los que están migrando a dicha plataforma.

Microsoft por ejemplo anunció hace unos días que Windows está sobre Git (una versión customizada por ellos mismos debido al gran tamaño de los archivos fuentes). Incluso Visual Studio Team Services ofrece Git como alternativa por defecto por sobre TFS (siendo que originalmente era la versión online de TFS). Esto son sólo algunos ejemplos, pero en líneas generales vemos que muchísimos proyectos (tanto OpenSource como no) usan Git como plataforma de versionado de código fuente.

Esto implica que en líneas generales debamos conocer los distintos conceptos asociados para poder hacer un uso correcto de la herramienta, ya que tiene mucha más potencia que las demás alternativas, pero también es más simple cometer ciertos errores con menores/mayores consecuencias en el trabajo propio y en el de los demás si no hacemos las cosas de la forma adecuada.

Lo primero que debemos saber de Git es que es un repositorio distribuido, lo que implica que tengamos dos partes involucradas: el repositorio local y el repositorio remoto. Esto es una diferencia significativa con respecto a otros sistemas de control de código fuente, como TFS por ejemplo, donde solamente existe el repositorio centralizado (el servidor) y todas las operaciones se realizan allí.

IntroGit - Distribuido.png
Esquema de las dos partes que componen un repositorio Git

Repositorio local: Este repositorio es el que está en nuestra máquina local, y es sobre el cual haremos la mayor cantidad de operaciones. Además de que es el que siempre deberá existir de forma obligatoria, ya que puedo tener un repositorio Git solamente en mi PC sin uno remoto (por ende nunca podré compartir el código asociado).

Repositorio remoto: Este repositorio es el que está en el servidor, permitiendo sincronizar los cambios de los distintos repositorios locales asociados al mismo.

Este esquema implica que todos los cambios y modificaciones que hagamos en el repositorio local no tendrán impacto en el servidor remoto hasta que ejecutemos los comandos de sincronización.

 

Otro punto importante para entender Git es que el repositorio es un grafo dirigido: está compuesto por nodos, los cuales pueden tener de 0 hasta 2 padres:

  • 0 padres: nodo cabecera o un nodo que ha quedado suelto porque modificamos la historia del repositorio
  • 1 padre: commit normal
  • 2 padres: commit de merge entre dos ramas, por lo cual las une

Esto implica que toda la historia del repositorio y las acciones que podemos hacer se basarán sobre los mismos, creando nodos y modificando las relaciones entre los mismos.

Git tampoco está asociado de forma directa a ningún IDE particular, motivo por el cual podemos usar el que queramos y de forma simultánea sobre el mismo repositorio, ya que la información está almacenada en la carpeta .git del mismo.

Lo primero que deberemos hacer es tener instalado Git en nuestro equipo, el cual podremos descargar desde este enlace. Ese será el único requisito para comenzar.

Luego tendremos que inicializar un repositorio, para lo cual hay dos formas:

  • Clonar un repositorio remoto ya creado: esto será lo normal si nos sumamos a un repositorio que ya se venía usando, o bien la creación inicial se hace en cualquier sitio para ello, como GitHub o BitBucket.
  • Crear un repositorio local: como decíamos anteriormente, no necesariamente debo tener un servidor remoto. Directamente puedo crear el repositorio localmente (mediante el comando git init) sobre la carpeta donde quiero trabajar.

Lo siguiente que debemos reconocer son los estados que pueden tener los archivos en el repositorio local:

IntroGit - EstadoLocal.png

  • untracked: son los archivos nuevos sobre los que Git no está haciendo ningún seguimiento. Esto puede ser tanto porque es un archivo que agregamos o bien porque son archivos excluidos de nuestro repositorio (binarios, dependencias, etc.)
  • unmodified: en este estado estarán todos los archivos cuyo estado no ha cambiado con respecto a lo que está confirmado en el repositorio local
  • modified: se da por la modificación del contenido de archivos trackeados por Git
  • staged: en este estado podremos colocar los archivos locales que estén listos para confirmar. Lo interesante de este estado es que una vez que colocamos un archivo en el mismo, lo podremos seguir modificando posteriormente pero dichos cambios no estarán en staged sino en modified. Esto implica que la copia en el estado staged no es necesariamente el estado de dicho archivo en disco, sino el contenido del mismo que nosotros llevamos a este estado

Otro punto importante asociado al estado staged es que no necesariamente es a nivel archivos. Podremos aplicar dicho estado a una línea (o conjunto de líneas) para dejarlas listas para realizar un commit.

Ahora bien, estas acciones las realizaremos sobre una de las unidades claves en Git: las ramas o branches. Una rama básicamente es un puntero a un determinado commit, indicando cuál es el estado de la misma. Esto es una diferencia significativa con respecto a TFS, ya que en este último cada rama es una copia separada con una relación particular entre las mismas, pero no dejan de ser dos carpetas físicas distintas. En Git cuando cambiamos de rama, se actualiza el estado de la carpeta donde tenemos nuestro repositorio local. Esto implicará también que en Git no podamos tener dos ramas distintas al mismo tiempo (lo podremos hacer, pero deberemos tener dos repositorios locales independientes asociados al mismo repositorio remoto).

Esto implica que podamos crear ramas para organizar realmente el trabajo que estamos haciendo, las distintas partes del mismo y los distintos ambientes de nuestra aplicación. Como suele decir @camboris, es barato hacer ramas en Git.

Es sobre las ramas donde realizaremos los distintos commits, es decir proteger nuestros cambios locales. dicha operación se realizará con los cambios que tengan el estado staged.

La combinación entre las distintas ramas es similar a lo que venimos haciendo por ejemplo en TFS, a través del merge o combinación. La misma la podremos realizar entre cualquier rama de origen contra cualquiera de destino, siempre y cuando no tengamos cambios locales pendientes. Una particularidad a tener en cuenta es que la operación se realizará en el repositorio local, por lo tanto deberemos tener ambos branchs actualizados con los últimos cambios.

Los vistos hasta ahora son todos comandos y acciones con el repositorio local. En casos de pruebas podremos usar solo el mismo, pero en cualquier otro caso real tendremos que usar también un servidor remoto. Para ello tendremos tres comandos disponibles:

  • fetch: nos actualizará el estado de las distintas ramas a partir del repositorio remoto, pero no los aplica localmente (chequea los cambios que hay en el servidor remoto)
  • pull: actualiza el estado de una rama de nuestro repositorio local a partir del estado de la misma en el repositorio remoto (bajamos los cambios)
  • push: actualiza el estado del repositorio remoto a partir del estado del repositorio local (subimos los cambios)

Estos son los comandos con los que realmente interactuamos compartiendo el contenido en el repositorio remoto, y por ende con los demás integrantes del equipo de trabajo. Esto implica que todo lo anterior que hagamos existe solo en nuestro equipo local, pudiendo a su vez hacer modificaciones sobre el mismo. Si algún commit está de más lo podemos quitar, podemos combinar varios en uno, hasta si algo salió mal y no nos es posible arreglarlo, directamente borramos la carpeta, lo clonamos nuevamente y es como si nada hubiera pasado.

Recomendaciones generales

Para finalizar este post les dejo una serie de recomendaciones generales que les servirán para trabajar de forma ordenada y evitar posibles problemas o dolores de cabeza:

  • Hacer commits de forma periódica cuando tengamos una unidad lógica terminada (es algo que deberíamos hacer siempre, independientemente de la plataforma de versionado que utilicemos)
  • Trabajar con ramas para separar las distintas features o funcionalidades que desarrollemos
  • Considerar que todo lo que hacemos en nuestro repositorio (excepto push y pull) es 100% local. Eso nos da flexibilidad para hacer determinadas acciones sin consecuencias
  • Tener el entorno de trabajo limpio ante acciones que tienen impacto. Antes de cambiar de rama, de hacer un merge, de hacer un pull debo tener mi entorno de trabajo sin cambios pendientes. Antes debería haber hecho un commit o un stash
  • Cuando trabajo con otras ramas, generalmente para un merge, debo tener actualizada el contenido de la misma localmente con los últimos cambios del servidor, ya que el merge es una operación local
  • El estado stage es de cambios, no de archivos. Esto implica que si hice un stage de un archivo y luego continuo editándolo, deberé hacer stage nuevamente si es que quiero hacer un commit de los mismos

Gracias por leer!

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s