- Introducción a Git (Primera Parte)
- Usando Git para manipular el directorio de trabajo, el índice y commits (segunda parte)
- Trabajando con las ramas de git (tercera parte)
- Repositorios remotos y flujos de colaboración (cuarta parte)
Prefacio
Este es una breve lectura introductoria a git. El propósito es tener una explicación personal de git para miembros del foro. No es su propósito ser extremadamente específico y explicar git en su totalidad, ni de describir como funciona cada una de las herramientas que lo compone.
He puesto ejemplos que pueden seguir asumiendo que tengan acceso a una terminal y al propio programa de git. Los ejemplos están trabajados sobre un sistema en Linux pero es posible seguir los ejemplos usando Windows. Esta no es una guía para instalar git ya que hay diversas formas en las que uno puede descargar e instalar git. Sin embargo, para aquellos que estén en Windows yo recomiendo que utilicen git tal cual es disponible desde este sitio, ya que el instalador también provee un entorno similar al que uno tiene en un sistema Linux (Git Bash).
Se requiere saber un mínimo acerca de la terminal para seguir los ejercicios. En concreto, uno debería poder navegar el sistema de archivos a través de la terminal.
¿Que es git?
git es un sistema de control de versiones distribuido (DCVS, Distributed Version Control System). Su principal uso es el de mantener el historial del código fuente en un proyecto y poder manejar cada uno de los cambios sobre el código fuente a través del tiempo. Hoy en día, un número de herramientas se han desarrollado a la par de git por lo cual se podría decir que git se utiliza para muchas otras cosas.
Por ejemplo, las plataformas para distribuir código libre usan principalmente git. En un pasado, el código fuente era distribuido por otros sistemas de control de versiones, por ejemplo SVN. En el peor de los casos el código fuente se distribuía en comprimibles para cada versión. Hoy en día, git se ha vuelto el VCS por defecto. De forma que si quieres obtener el código fuente de un proyecto lo más probable es que necesites usar git. De igual forma, si quieres contribuir a un proyecto lo más probable es que necesites usar git también.
git está en todos lados. Administración de proyectos, distribución de paquetes, integración/entrega continua y muchos otros procesos en el desarrollo de software. Es muy probable que si estás involucrado en el desarrollo de algún software tengas que usar git en alguna ocasión. De hecho, como consumidor de software es probable que también tengas que usar git en alguna ocasión. De manera que aprender git nunca está de más.
¿Que significa que git sea distribuido?
Tradicionalmente, el control de versiones se hacia sobre una instancia central (un servidor) en la cual personas (clientes) introducían o pedían código fuente. Todo se procesaba en esta instancia central. Lo que significa que no podías agregar cambios o solicitar código fuente si la instancia no estaba disponible. En un sistema central todos dependen de está instancia.
En un sistema distribuido, uno no depende de una sola instancia. En sí cada cliente es dueño de una instancia que se puede valer por si misma. Así que cada instancia puede procesar cambios y solicitar información independientemente de cualquier otra instancia. Cada instancia puede recibir y compartir cambios entre todas las instancias que existen.
Cada instancia se le conoce como un "repositorio".
¿Que es un repositorio?
Del latín repositorium: Lugar donde se guarda algo.
Un repositorio de git es básicamente un lugar donde se guarda (o almacena) el código fuente. Un repositorio está marcado por la carpeta .git/ en la cual se encuentra toda la información acerca del repositorio. La carpeta que contiene a la carpeta .git/ es conocida como la carpeta raíz del repositorio. La carpeta raíz es la carpeta que contiene una versión del código fuente y también es conocida como directorio de trabajo para git.
¿Como crear un repositorio de git?
Para crear un repositorio en blanco de git se utiliza el comando:
Código
git init
Dentro de esta carpeta se creará la carpeta .git/, la cual contendrá toda la información del repositorio.
Es importante mencionar que el repositorio está vació a estas alturas. La raíz del proyecto (la carpeta donde se hace git init) puede contener información a la hora de crear el repositorio pero está información todavía no forma parte del repositorio. Necesitan ser agregados manualmente.
Ejemplo:
Nota: Para efectos de esta explicación voy a utilizar un sistema en Linux con git.
Supongamos que tenemos nuestro directorio proyecto/:
Hasta ahora, es un directorio normal. El siguiente paso sera crear un archivo README.md que contenga el nombre del proyecto.
Ahora lo convertiremos a un repositorio git.
Y vamos a notar que el mismo comando nos está diciendo que el repositorio está vacío.
¿Como agregar información al repositorio?
Antes de empezar a agregar información al repositorio, es muy importante conocer como es que git mantiene nuestra información.
git mantiene conjuntos de archivos en lo que se denomina un commit. Es uno de las términos de los cuales no quisiera traducir literalmente al español. El commit es básicamente una replica del estado de tu código fuente en un punto en el tiempo. Es decir, el commit contiene el código fuente exactamente igual a la vez que se creo dicho commit. Dentro de un repositorio, pueden existir miles de commits. Cada uno simbolizando el progreso del código a través del tiempo.
¿Como crear un commit? ¿Que es el índice de git?
Para crear un commit, es importante también conocer un poco acerca del índice de git. El índice de git mantiene los cambios a agregar a un commit. Los cambios pueden ser varios entre cambiar el nombre a un archivo, remover o agregar un archivo o hacer alguna modificación sobre el archivo.
Es a través del índice de git en el cual podemos construir nuestros commits. Son los cambios agregados al índice los que forman parte del commit. Puedes pensar del índice como el paso intermedio a la construcción del commit. Imagina que el índice es un contenedor abierto (una caja de cartón por ejemplo) a la cual vas agregando cosas. Una vez que terminas de empaquetar todo, cierras este contenedor y ahora una vez cerrado este contenedor deja de ser el índice y ahora es un commit.
Ejemplo:
Vamos a empaquetar nuestro archivo README.md, es decir vamos a agregar el archivo al índice. Primero vamos a visualizar el estado del índice. Para revisarlo, podemos utilizar:
Código
git status
Como puedes observar en la última línea git me está diciendo que no hay nada para hacer el commit pero hay archivos que no están siendo rastreados. Nuestro índice está vacio.
Usamos el comando que nos menciona git para agregar el archivo al índice:
Código
git add README.md
y volvemos a revisar el estado del índice:
Ahora git dice que hay un cambio en el índice para el cual podemos crear un commit. Por lo pronto vamos a hacer otro cambio a nuestro archivo README.md y simplemente vamos a agregar una descripción.
Lo único que voy a hacer es agregar la siguiente línea a mi archivo, "Este es mi proyecto que estoy haciendo con git". Ustedes pueden usar cualquier editor para agregar la linea si no quieren usar su terminal.
Y como pueden ver, el índice ahora está rastreando los cambios en el archivo README.md. Y el índice me alerta que hay cambios pendientes que no han sido agregados al índice todavía.
Si yo creara un commit en este mismo momento, lo único que añadiría al repositorio son los cambios que han sido agregados al índice hasta ahora. Es decir, el nuevo archivo con el texto original (antes de la modificación).
Para que este nuevo cambio sea parte del commit, necesito agregarlo al índice. Nuevamente tenemos que usar:
Código
git add README.md
Y al revisar el estado nuevamente con git status obtendremos los mismos resultados antes de hacer la modificación.
Finalmente, podemos crear nuestro commit. Para ello necesitamos usar el comando:
Código
git commit
Importante:
Si está es la primera vez que utilizan git va a ser necesario configurar los datos relevantes al autor que realiza el commit. Configurar estas opciones son muy sencillas:
Código
git config --global user.email "tucorreo@dominio.com" git config --global user.name "Tu nombre"
Un editor deberá aparecer (dependiendo de la configuración de git) y les pedirá que introduzcan un mensaje asociado al commit. Este mensaje en general actúa como un resumen de los cambios que se han realizado en ese dado commit. No es necesario que sea así, el mensaje puede ser cualquier cosa excepto un mensaje vació. Si el mensaje es vació (y no se ha configurado git para aceptar mensajes vacios), git aborta el comando y no se crea ningún commit.
Opcionalmente podemos utilizar:
Código
git commit -m "mensaje corto"
Y esto nos permite crear un mensaje rápido para hacer el commit. Vamos a usar esta opción para crear el commit en caso de que no tengan un editor configurado correctamente.
Más acerca de los mensajes en los commits más adelante. Por ahora este es un ejercicio de prueba y la intención es que puedas agregar tus cambios al repositorio. Una vez que el commit se haya agregado puedes considerar que tu información es parte del repositorio. Si volvemos a checar el estado del índice veremos que no tendremos ningún cambió pendiente a agregar:
Y si queremos revisar que nuestro commit está ahí podemos usar:
Código
git log
En el cual podemos observar varias cosas:
1) El nombre del Autor es mi usuario: "MinusFour"
2) Entre las flechas < > aparece el correo del autor (en mi caso lo he tapado).
3) La fecha en la que se realizo el commit.
4) El mensaje del commit.
5) Un identificador del commit (SHA-1 por defecto): de00cee7484d435d471b964920e6122a1511b788
Y por último, dos palabras entre paréntesis que tienen un significado especial: HEAD y master. Ambas están relacionadas al siguiente tema importante de Git, las ramas.
Importante:
El identificador SHA1 no será el mismo para ustedes. Cada commit que se realize es único, incluso si son los mismos cambios. git no necesita el identificador entero para funcionar puedes usar solo una parte siempre y cuando no haya otro commit que también comparta esa parte.
¿Que es una rama (branch)?
Hasta ahora sabemos lo que es un repositorio y sus commits. Las ramas son el eslabón faltante entre estos dos. Cada repositorio está compuesto de una o varias ramas que estos a su vez están formados por commits. Las ramas en sí no son nada en especial para git y al mismo tiempo resultan extremadamente útil. Primero tenemos que explorar un poco más a fondo los commits.
Verás, cada commit después del primer commit tendrá un ancestro del cual proviene. Es decir, el primer commit será el ancestro del segundo commit, el segundo será el ancestro del tercero y así sucesivamente. Esta línea de sucesión entre commits es lo que se podría considerar una rama. Y git no necesita mucho para averiguar todos los commits que componen una rama. Usando un solo commit, git puede rastrear hasta el último ancestro (porque cada commit tiene un ancestro). Es por eso que las ramas son esencialmente punteros los cuales contienen el identificador del último commit, también llamado la punta de la rama.
Cuando creamos un repositorio, git crea una rama por defecto bajo el nombre de master (esto nombre posiblemente este por cambiar a main en un futuro). Cuando nosotros creamos un commit sobre la rama master, git remplaza el identificador del commit anterior por el identificador del nuevo commit (ya que este es el último commit, la nueva punta de la rama). ¿Y Como sabe git en que rama estás haciendo el commit? Pues para eso está el puntero especial HEAD cuya función es la de apuntar directamente al commit o rama en la que estamos trabajando. Cuando HEAD no apunta a una rama y apunta a un commit directamente se dice que la cabeza está desconectada (detached head). En esta situación, al hacer un commit git no sabría que rama actualizar para apuntar al nuevo commit recién creado. Es necesario tomar precauciones cuando trabajamos de está forma ya que sin una rama los cambios realizados pueden perderse. En nuestro ejemplo anterior podemos ver que HEAD está apuntando a la rama master. Esto simplemente quiere decir que la rama en la cual estamos trabajando actualmente es master y que cualquier cualquier operación que modifique el estado de la rama (como git commit) será sobre master.
Ejemplo:
Ahora mismo nuestro repositorio solo tiene un commit con el identificador de00cee. Nuestro HEAD está apuntado a master que a su vez está apuntando a de00cee. Todo esto lo podemos verificar con los archivos internos de git.
Aquí podemos ver que HEAD apunta a refs/heads/master (una notación más especifica para master) que a su vez apunta a de00cee. Lo podemos ver de una manera gráfica:
Para ejemplificar como es que la rama empieza a tomar forma vamos a agregar unos cuantos commits.
Nuestro primer commit simplemente cambiara el nombre del proyecto en el archivo README.md. En esta ocasión estoy utilizando el programa sed para cambiar el texto "Mi Proyecto" por "Aprendiendo Git", pero ustedes pueden abrir su editor de texto y hacer cambios sobre el README.md.
Y el tercer commit simplemente agregara un archivo nuevo al cual por ahora simplemente llamaremos prueba.txt.
Ahora podemos revisar todos nuestros commits usando git log nuevamente.
Podemos ver nuestros tres commits: 0ba7347, 0f55ed3 y de00cee. Tambien podemos ver como master ya no está apuntando a de00cee sino al último commit 0ba7347. HEAD sigue apuntando a master.
Ahora, para mostrarles que efectivamente el ancestro/padre de 0ba7347 es 0f55ed3 usare un comando especial para mostrarles el contenido del commit:
Usando esta información podemos crear una nueva gráfica:
Recapitulando el estado de este repositorio de prueba:
1) Tenemos tres commits. Cada uno apunta a un padre (con la expceción del primer commit).
2) La rama master apunta al último commit.
3) Nuestro HEAD apunta a master (lo que significa que la rama sobre la cual estamos trabajando es master.
Más adelante pondré ejemplos de como usar multiples ramas para organizar el repositorio.
Epilogo
Al final de la lectura deberán saber que es git, para que se usa git y deberían poder crear sus propios repositorios y agregar información a ellos. Deberían tener una noción básica de lo que es un repositorio, los commits, el índice de git y las ramas.