Git


Tenía que ocurrir más tarde o más temprano. Y es que tenía que hablar de GIT. Es lo que tiene ser influenciado por Daniel Fanjul XD

Git es un sistema de control de versiones. Bueno, en realidad es algo más que eso. Es un sistema de ficheros sobre el que se ha construido un sistema de control de versiones.

No soy un experto, pero creo que a lo básico llego. Y, la verdad, me hacía falta este artículo antes de escribir el siguiente XD

Qué es un DVCS

Los lectores habituales de este blog pueden saltarse esta sección, ya que no es la primera vez que hablo de alguno de los DVCS.

Un DVCS, o Distributed Version Control System, es lo que dicen sus propias siglas: un sistema de control de versiones distribuido. Dicho de otra manera, es un sistema que permite gestionar versiones de archivos y coordinar dichas versiones entre distintas máquinas.

Siempre cuento la misma historia: cuando yo estaba estudiando no existían los DVCS, aunque sí había sistemas de control de versiones no distribuidos, como CVS. El caso es que tampoco los conocía. Por eso mis prácticas se encontraban en la carpeta "prácticas", "la última", "la definitiva", "la definitiva de verdad", ... Lo que me suponía un verdadero dolor de cabeza. Por eso llegué a la conclusión de que lo mejor era usar la fecha en orden inverso: "20120101", "20120102", "20120102b", ...

Pero estaba equivocado. Lo mejor era usar un DVCS :D

Antes de empezar

Vamos a usar una configuración minimísima:

.. code:: bash

$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com

Con eso le diremos a Git quiénes somos :D

No es imprescindible, pero nos evitaremos que Git proteste porque no "nos conoce".

Trabajando en local

Como sabéis, me gusta la práctica, así que vamos a crear un pequeño proyecto para demostrar el uso de Git. Podemos inicializar un repositorio en un directorio vacío o en uno existente; esto no afectará a los archivos que se encuentren allí.

Por razones obvias, vamos a trabajar sobre uno vacío, con el fin de que todos tengamos lo mismo. Lo primero es inicializar el directorio como un repositorio de Git:

.. code:: bash

$ git init
Initialized empty Git repository in /home/magmax/git/.git/

Así de fácil. Podemos ver que ahora es un repositorio Git válido:

.. code:: bash

$ git status
# On branch master
#
# Initial commit
#
nothing to commit (create/copy files and use "git add" to track)

Esto nos da mucha información: Para comenzar nos dice la rama en la que estamos... Eso son temas avanzados que dejo para más adelante. Nos dice que estamos en el commit inicial. En el repositorio, cada "paso" se llama "commit". Cada vez que hacemos una foto al sistema, es un "commit". Así que un commit contiene la información de nuestro directorio en el momento en que se creó dicho commit. Si no lo entendéis, no os preocupéis; volveremos al tema en breve. También dice que no hay nada sobre lo que hacer commit* y nos da información sobre lo que podemos hacer.

Así es Git: siempre nos dará información sobre posibles acciones que podemos realizar.

Ahora podemos crear un archivo y ver qué pasa:

.. code:: bash

$ touch README
$ git status
# On branch master
#
# Initial commit
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#   README
nothing added to commit but untracked files present (use "git add" to track)

Ajá! la cosas cambian. Ahora ha encontrado un fichero del que no sabe nada. Nuevamente nos indica que podemos añadirlo para que sea "commiteado". Pues vamos a ello:

.. code:: bash

$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#   new file:   README
#

Perfecto. Ahora nos dice que hay un archivo nuevo, que es README. Dice que será "commiteado" a no ser que lo borremos con el comando ése que indica ("rm" viene de "remove").

Aquí aparece un término raro: "unstage"; viene del stage, al que también llaman index en la documentación. Básicamente consiste en un lugar donde Git se guarda las cosas que va a realizar; una especie de cajón temporal. Eso nos permitirá jugar con los archivos hasta dejarlos como queremos y, entonces, fijarlos con un commit.

Este index o stage es muy útil y tiene muchas implicaciones. Sin embargo, cuando se está aprendiendo Git, consiste más en un estorbo que en otra cosa. Así que vamos a ignorarlo y a dejarlo en el cajón de los conceptos avanzados.

Ha llegado el momento de hacer nuestro primer commit:

.. code:: bash

$ git commit -a -m "Mi primer commit"
[master (root-commit) ba1429d] Mi primer commit
 0 files changed
 create mode 100644 README

Como veis le indico dos opciones: -a indica que lo añada todo. Así me evito contaros más sobre el stage. Si no lo pongo, sólo hará caso de lo que tenga apuntado en el stage. En este caso es redundante, ya que todas las operaciones ya se encuentran apuntadas en el stage, pero me curo en salud. Si Git no conoce un fichero (no hemos hecho add), lo ignorará tanto con "-a" como sin él; lo mismo ocurre si lo conoce pero no se ha modificado. Ahora, si se ha modificado y no hemos hecho un "add" de nuevo, entonces sólo lo considerará si pusimos el "-a". -m "mensaje" Añade un mensaje al commit, de manera que, cuando veamos la historia, nos quede claro qué hicimos ahí. Si no lo ponéis se abrirá el editor por defecto para que pongáis el mensaje. Podéis ignorarlo, pero no es una buena práctica. Sed concisos, pero precisos.

Veamos cómo estamos:

.. code:: bash

$ git status
# On branch master
nothing to commit (working directory clean)

Todo limpio, como debe ser.

Vamos a modificar el archivo:

.. code:: bash

$ echo "Archivo modificado" > README
$ git status
# On branch master
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   README
#
no changes added to commit (use "git add" and/or "git commit -a")

Como vemos, Git se da cuenta de que hay cosas que no hemos publicado. Y Git nos dice qué tenemos que hacer para descartar los cambios o fijarlos con un commit.

Además, podemos ver la historia de lo que hemos hecho:

.. code:: bash

$ git log
commit ba1429d0d9ef7c65e6fbd800f74bf7e06361540c
Author: Miguel Angel Garcia <miguelangel.garcia@gmail.com>
Date:   Thu Nov 29 17:14:36 2012 +0100

    Mi primer commit

Y tendremos orden en lo que vamos haciendo.

Trabajando en remoto

Hasta aquí todo es similar a cómo funcionan los sistemas de control de versiones no distribuidos. Pero la gracia está, justamente, en disponer de un repositorio central... O muchos XD

Aquí tenemos distintas opciones, como irnos a GitHub o a BitBucket y crearnos un repositorio. Voy a explicar el proceso con un servidor local, situado en otro directorio. Para usarlo con un sistema en cloud sería igual, pero indicando la url que nos proporcionan en lugar de la ruta al directorio (además, nos darán ayuda XD).

Lo primero es crear un repositorio "bare" en otro directorio:

.. code:: bash

/home/magmax/git-master $ git init --bare
Initialized empty Git repository in /home/magmax/git-master/

Y ahora volvemos a nuestra "working copy", que no es más que la copia local o lo que hicimos en el paso anterior. Vamos a decirle dónde está el maestro donde queremos guardar los cambios; éste es el paso que cambiaría si usáis un hosting externo o si usáis otra máquina:

.. code:: bash

$ git remote add origin /home/magmax/git-master/

Y ahora empujamos los cambios:

.. code:: bash

$ git push origin master
Counting objects: 3, done.
Writing objects: 100% (3/3), 220 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
To /home/miguel/Pruebas/git/example2
 * [new branch]      master -> master

Por ser la primera vez, hemos tenido que indicarle el nombre del repositorio remoto (origin) y la rama que queremos empujar (master, la única que tenemos). A partir de ahora bastará con "git push". Y con esto tenemos muchas cosas: Por un lado, copias de seguridad Por otro, la posibilidad de compartir el código * ¡Y la posibilidad de trabajar con otra gente colaborativamente!

Puedo asegurar que mi sistema de directorios con la fecha estaba a años luz de estas tres ventajas.

Ya solo me quedan 4 órdenes básicas que contar en este artículo: Cuando queramos actualizar nuestra copia local ("working copy") con lo que haya en remoto, basta con ejecutar "git fetch". Cuando queramos mezclar nuestros cambios con los remotos, podemos hacer "git merge". Los dos pasos anteriores quedan resumidos en uno: "git pull". Y si queremos hacer otra copia local, basta con "git clone /home/magmax/git-master/ new-copy", que creará un directorio nuevo

Git es mucho más que esto

En este artículo sólo he querido mostrar lo más básico de lo más básico del uso de Git. Git permite muchas más cosas, como la gestión de ramas, sistemas de pull-request, eliminación de historia, ... Pero eso se sale de este tutorial básico.

Hay miles de tutoriales, la mayor parte mejores que éste. Sin embargo, yo os remitiré a la documentación básica de Git, que es genial. Recomiendo la versión inglesa, ya que el resto puede no estar del todo actualizada.

Así mismo, diré que existen muchos otros DVCS, gratuitos, libres, de pago... De todos los gustos y colores: Mercurial, PlasticSCM,...

En mi opinión, Git es rápido, fiable y resuelve todos los problemas con los que me he encontrado hasta ahora. Así que... ¿por qué no darle una oportunidad?


Comentarios

Comments powered by Disqus