2013-09-04

Control de versiones con Git Paso a Paso

¿Qué es GIT?

Git nació de la insatisfacción de Linus Torvalds (creador del kernel de Linux) con los programas de control de versiones. En Linux Foundation, utilizaban BitKeeper, pero en cuanto éste modificó su acuerdo de licencia; tuvieron que optar por una alternativa. La comunidad Linux creó dos nuevos proyectos: Git y Mercurial. Ambos tienen sus orígenes en la emergencia y lideran el ranking de software de control de versiones distribuido. Git se hizo más popular y actualmente se utiliza en proyectos como: el kernel de Linux, jQuery, Ruby on Rails, Symfony, CakePHP, Debian, Fedora, entre otros.

Centralizado o Distribuido

Git, al igual que Mercurial, es un software de control de versiones distribuido (DVCS). Sistemas comoSubversion y CVS, en contraste, funcionan como sistemas centralizados (CVCS).
En los sistemas centralizados, sólo existe un repositorio "maestro" (master), a donde cada desarrollador envía sus cambios. Cada acción debe ser sincronizada con el repositorio central, y como en general el sistema reside en un servidor central, cada acción debe pasar a través de la red; por lo que si la red se cae, el desarrollador no puede trabajar.
En los sistemas distribuidos, cada desarrollador tiene su propio repositorio. En la mayoría de las veces, estos repositorios se comunican con un repositorio central el cual permite compartir los cambios con otros desarrolladores; sin embargo, esto no es un requerimiento.

Ventajas de Git

Una de las principales ventajas de Git es su naturaleza distribuida, lo cual permite que sea igual el tener muchos repositorios remotos o sólo uno para compartir código. Los DVCS permiten trabajar desconectado sin ninguna restricción.
Un factor importante de Git es la velocidad. Git destacó sobre otros DVCS como Mercurial, por la rapidez con la que procesa las operaciones. Esto se debe a que Git está escrito en C y fue pensado para trabajar con el kernel de Linux, por lo que el tiempo de respuesta era sumamente importante. Otro punto interesante, es que el repositorio local de Git sirve como backup, porque contiene todo el historial del proyecto y considerando que (casi) cada acción en Git añade datos, perder datos del historial es algo difícil.
Finalmente se encuentra el workflow que utiliza Git, que analizaremos más adelante.

El repositorio local

En SVN, a cada carpeta que se encuentre asignada al controlador de versiones, se le agrega una carpeta oculta que guarda toda la metadata relevante de dicho directorio. Git por el contrario sólo tiene una de estas carpetas ocultas. Esto significa que se pueden copiar, mover, borrar archivos y carpetas, sin dolores de cabeza. Esta carpeta (.git) se genera en la raíz del proyecto y genera el repositorio local. Los archivos en los que diariamente se trabaja, conforman el "directorio de trabajo" (working directory).
Además del repositorio y el directorio de trabajo, existe el "área de puesta en escena" (staging area), que permite definir qué cambios serán aplicados en el próximo commit. Commit es la acción de consignar un grupo de cambios.
Vamos a visualizar todo con un ejemplo. Hicimos modificaciones a 8 archivos y nos damos cuenta que deberíamos separar estos cambios en dos commits (cada commit debe incluir sólo cambios relacionados). Utilizando el staging area, se puede definir exactamente, sobre qué cambios debe hacerse commit, y cuales deben esperar al siguiente.
Técnicamente, el staging area, no es más que un archivo (llamado index) que se encuentra en el repositorio .git local.

Estados de los archivos

Existen varios estados en los que puede encontrarse un archivo en el working directory. La distinción básica es "tracked" (con seguimiento) y "untracked" (sin seguimiento). Un archivo está en estado tracked, cuando se encuentra dentro del sistema de control de versiones, o sea, Git observa todos los cambios a dicho archivo. En el caso que el archivo no haya sido agregado a Git, el mismo es tratado como untracked.
Los archivos que están en estado tracked, pueden encontrarse a su vez en tres estados:
  • unmodified (sin modificar) o committed (con commit): el archivo se encuentra en su último estado, por lo cual no tiene modificaciones locales.
  • modified: el archivo ha sido modificado desde la última vez que se incluyó en un commit.
  • staged: el archivo fue modificado y agregado al staging area, lo que significa que será incluido en el próximo commit.

Hashes


Git no entiende de números de revisión. En los sistemas CVCS, cada commit tiene asociado un número de revisión consecutivo. En los DVCS como los commits son creados localmente, el sistema no puede asignar números consecutivos. Por este motivo Git utiliza hashes SHA-1.
Un hash es un algoritmo que mediante una entrada (texto, contraseña, archivo, etc.) genera una salida alfanumérica de longitud normalmente fija, que representa un resumen de toda la información que se le ha dado.
SHA-1 es una función de hash creada por los Estados Unidos, que significa Secure Hash Algorithm (Algoritmo de Hash Seguro). Existen varias implementaciones, siendo la 1 la más utilizada.
Entonces Git utiliza estos hashes como si fueran los números de revisión, ya que estos son compatibles con el modelo DVCS.

Git desde la linea de comando

Existen varios programas de terceros como Netbeans, Eclipse, etc; que le dan una interfaz gráfica a Git, pero para comprender en profundidad a Git, lo mejor es observar el workflow de trabajo desde la consola. Si instalás uno de esos programas, varios de los pasos que siguen no tendrás que hacerlos.
Si todavía no lo hiciste, es necesario que descargues e instales la última versión de Git. Esto lo podés hacer desde la página oficial: http://git-scm.com. Una vez instalado, hay que configurarlo. Para eso, hay que abrir el programa Git Bash y veremos lo siguiente.
Git Bash
Ahora es momento de configurar tu usuario. Primero hay que indicarle tu nombre a Git, para que pueda utilizarlo en los commits. Para eso es necesario ejecutar la siguiente línea:
git config --global user.name "Tu nombre"
Luego tenés que indicar tu email.
git config --global user.email "tu@email.com"
Con eso, ya está todo listo para empezar a utilizar Git. En caso que necesites ayuda, siempre podés ejecutar el siguiente comando:
git help git

Forma de trabajo

Repositorios

Un repositorio es el requerimiento básico para trabajar con Git. Vamos a suponer que no tenemos ningún repositorio, por lo cual necesitamos crear uno. Ejecutando el siguiente comando, Git nos creará una carpeta con el nombre del repositorio y dentro una carpeta llamada ".git" la cual contiene toda la información del repositorio.
git init repositorioDePrueba
Para acceder a nuestro repositorio desde Bash, una vez creado el mismo, utilizaremos el siguiente comando:
cd repositorioDePrueba
En el caso que necesites obtener un repositorio remoto, en vez de crear uno local, deberías utilizar el comando clone, en lugar de init.

Commit

Luego de un tiempo trabajando, tendremos algunos archivos que querremos guardar en nuestro repositorio como commits. Para empezar vamos a ejecutar el comando git status para ver qué cambios hay en nuestro directorio de trabajo. En este caso, Git nos informará:
  • que estamos en la rama master
  • que es el commit inicial
  • que hay archivos sin seguimiento
  • que no hay nada para hacer commit
Recordemos que necesitamos hacer que los archivos tengan seguimiento y agregarlos al staging area para poder hacer commit. Para indicarle a Git qué archivos queremos que formen parte del próximo commit, tenemos que utilizar el comando add (supongamos que estuvimos trabajando en un archivo llamado prueba.php).
git add prueba.php
Si volvemos a ejecutar el comando status, veremos que ahora hay cambios para hacer commit.
Para guardar el commit dentro de nuestro repositorio local, debemos utilizar el comando commit.
git commit -m "Mensaje para indicar qué incluye este commit"
El comentario que ponemos al final, nos permite tener una historia de los commits para poder saber qué fue lo que motivó el commit. Para ver la historia de los commits, hay que ejecutar el comandolog; el cual se puede modificar para mostrar lo que necesitemos.
git log // muestra todos los datos
git log --oneline // muestra sólo los mensajes de los commits 
git log -p //muestra los cambios hechos sobre los archivos

Ramificaciones (Branch y Merge)

Gracias a la ramificación, podemos (para explicarlo de forma simple) hacer una especie de copia total del repositorio. De esta forma podremos trabajar en cada rama en una funcionalidad diferente sin que una afecte a la otra. Una vez que estemos contentos con los cambios, podemos fusionar ambas ramas para que ambas tengan los cambios y seguir como al principio.
Ramificación en Git
Para crear una rama, se utiliza el comando branch:
git branch funcionalidad1
Si ejecutamos el comando branch sin indicar un nombre para la nueva rama, Git nos muestra una lista de todas las ramas activas. Hay que tener en cuenta que la rama principal se denomina "master" y que Git nos indica con un asterisco cuál es la rama en la que estamos posicionados (a la cual se la denomina HEAD). Podemos ver que a pesar de haber creado una rama, no nos movimos a ella. Para saltar de rama en rama utilizamos el comando checkout.
git checkout funcionalidad1
Todos los commits que realicemos estando en la rama "funcionalidad1" no serán vistos por la rama "master".
Una vez que hayamos terminado con los cambios en nuestra funcionalidad nueva, y queramos enviar los mismos a la rama master, tendremos que usar el comando merge (estando posicionados en la rama master).
git checkout master
git merge funcionalidad1
Finalmente, como ya fue implementada la funcionalidad, la rama "funcionalidad1" ya no nos sirve más; por lo cual la eliminamos.
git branch -d funcionalidad1

Trabajando con repositorios remotos

Los repositorios remotos nos permiten tener nuestro código disponible para nuestros compañeros de trabajo, así como también integrar el código de ellos a nuestro repositorio local. Para añadir un repositorio remoto debemos ejecutar el siguiente comando:
git remote add reporemoto https://direccionremota.com
Una vez que tenemos configurado un repositorio remoto podemos obtener todos los datos del mismo utilizando dos comandos: fetch o pull. Fetch obtiene todos los datos sin hacer cambios sobre las ramas locales (por lo cual después habrá que hacer un merge), mientras que Pull obtiene los datos y hace merge con las ramas locales.
git fetch reporemoto
o
git pull reporemoto master
Para enviar nuestros datos al repositorio remoto utilizaremos el comando push:
git push reporemoto master
Para ilustrar mejor el flujo de trabajo con los repositorios remotos, te dejo esta imagen.
Trabajar con repositorios remotos en Git

Información recopilada de nebaris.com

No hay comentarios: