Por Fernando Jordán / @fjordansilva
En esta presentación de GIT básico veremos los siguientes puntos:
GIT es un sistema de control de versiones. Un sistema de control de versiones registra los cambios realizados sobre un archivo o conjunto de archivos a lo largo del tiempo, de modo que se puedan recuperar versiones específicas más adelante.
GIT es una evolución de los sistemas de control de versiones actuales. Es un sistema de control de versiones distribuido.
GIT surge a partir de la necesidad de gestionar el código fuente del núcleo de Linux.
Durante muchos años Linux utilizó un sistema propietario denominado BitKeeper, pero Linus Torvalds decidó desarrollar un sistema propio enfocado en:
Entonces... ¿cómo trabaja GIT?
Cada vez que se confirma un cambio, GIT hace una foto del aspecto de los archivos en ese momento y guarda una referencia a esa instantánea. Los archivos no modificados no son almacenados de nuevo.
La mayoría de las operaciones en GIT sólo necesitan archivos y recursos locales para operar. Por ejemplo:
Todo en GIT es verificado mediante el checksum antes de ser almacenado, y es identificado a partir de ese momento mediante dicha suma. Esto significa que es imposible cambiar los contenidos de cualquier archivo o directorio sin que GIT lo sepa.
De hecho, de forma interna, GIT guarda todo no por el nombre del archivo, si no por el hash de dicho archivo.
Cuando realizas acciones en GIT, casi todas ellas sólo añaden información a la base de datos de GIT. Es muy difícil conseguir que el sistema haga algo que no se pueda deshacer, o que de algún modo borre información.
Esto hace que usar GIT sea muy agradable, porque sabemos que podemos experimentar sin peligro de fastidiar gravemente las cosas.
GIT tiene tres estados principales en los que se pueden encontrar tus archivos: confirmado (committed), modificado (modified), y preparado (staged).
El flujo de trabajo sería:
Para empezar a trabajar con GIT necesitaremos las siguientes herramientas:
Para la generación de los certificados necesarios para la autenticación en servidores GIT utilizaremos:
La generación de certificados permite conectarse al servidor GIT utilizando una conexión SSH. Este tipo de conexión es la recomendada en términos de seguridad.
Las claves SSH permiten que dos ordenadores se identifiquen entre si, sin la necesidad de introducir contraseñas.
Como cliente GIT utilizaremos SourceTree desarrollado por Atlassian.
Podremos trabajar con cualquier servidor GIT. Algunos de los más populares son:
Tarea que se realiza al inicio del proyecto o durante la vida del proyecto si se subdivide en distintos módulos. Como ejemplo vamos a crear un proyecto en GitLab:
La autenticación con GIT la podemos realizar de dos formas: claves SSH o mediante login/password.
La autenticación mediante claves SSH es preferible en términos de seguridad y comodidas para el usuario, ya que una vez generados los juegos de claves pública / privada e informado al servidor, el cliente SourceTree se encargará de todo lo relativo a la autenticación.
La URL del repositorio nos indica el tipo de login a realizar:
git@git.connectis-ict.es:aireuropa_casillero_digital/mod-middleware.git
https://gitlab.connectis-ict.es/aireuropa_casillero_digital/mod-middleware.git
Creación de las claves SSH en Windows:
Como resultado de la creación de las claves SSH en Windows obtendremos 3 archivos:
ssh_key.pub
- clave publicassh_key.ppk
- clave privadassh_key.txt
- Información de las claves para el servidor GITUna vez creadas las claves SSH, debemos informar al servidor GIT de las mismas para que nos permita el acceso:
Es la primera operación a realizar sobre un repositorio. Para obtener una copia de un repositorio existente al que se desea contribuir el comando a utilizar es clone.
Clonar significa realizar una copia de todo el contenido del repositorio que se encuentra en el servidor GIT en nuestro PC.
A diferencia de otros sistemas (SVN), se obtiene una copia completa del repositorio del servidor, de forma que se podrá trabajar sin necesidad de conexión.
mkdir git-training
cd git-training
git clone git@git.connectis-ict.es:fjordan/git-training.git
Se debe utilizar el botón de la barra de herramientas "Clone / New".
Tu principal herramienta para determinar qué archivos están en qué estado es el comando git status. Si ejecutas este comando justo después de clonar un repositorio, deberías ver algo así:
cd git-training
git status
# On branch master
nothing to commit, working directory clean
Esto significa que tienes un directorio de trabajo limpio —en otras palabras, no tienes archivos bajo seguimiento y modificados—. GIT tampoco ve ningún archivo que no esté bajo seguimiento, o estaría listado ahí. Por último, el comando te dice en qué rama estás. Por ahora, esa rama siempre es "master", que es la predeterminada.
Conocer el estado de los archivos en SourceTree es muy sencillo: Una vez seleccionado el repositorio con el que queremos trabajar, tendremos dos formas de verlo:
Para empezar el seguimiento de un nuevo archivo se usa el comando
git add.
Iniciaremos el seguimiento del archivo README ejecutando esto:
touch README
cd git-training
git add README
Si vuelves a ejecutar el comando git status, verás que tu README está ahora bajo seguimiento y preparado:
git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# new file: README
#
Para realizar el seguimiento de un archivo nuevo con SourceTree, únicamente necesitamos pulsar el botón "Add".
Esta acción añadirá todos los archivos sobre los que NO se realice seguimiento, no se podrá realizar una selección individual.
Vamos a modificar un archivo que ya estuviese bajo seguimiento. Si, por ejemplo, modificamos el archivo MiArchivo.txt que ya está bajo seguimiento, y ejecutamos el comando git status de nuevo, veremos algo así:
git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# new file: README
#
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
#
# modified: MiArchivo.txt
#
El archivo MiArchivo.txt aparece bajo la cabecera "Modificados pero no actualizados" ("Changes not staged for commit") —esto significa que un archivo bajo seguimiento ha sido modificado en el directorio de trabajo, pero no ha sido preparado todavía—.
Para prepararlo, ejecuta el comando
git add
y volvemos a ejecutar git status:
$ git add MiArchivo.txt
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# new file: README
# modified: MiArchivo.txt
#
Al modificar los archivos, en SourceTree nos aparecerán como pendientes de ser enviados ( "Uncommited changes" ).
Mientras no sean enviados, la herramienta queda a la espera y va añadiendo al mismo commit todos los archivos que sean modificados.
A menudo tendrás un tipo de archivos que no quieras que GIT añada automáticamente o te muestre como no versionado. Suelen ser archivos generados automáticamente, como archivos de log, o archivos generados por tu compilador.
Para estos casos puedes crear un archivo llamado .gitignore, en el que listas los patrones de nombres que deseas que sean ignorados. por ejemplo:
$ cat .gitignore
*.sh
*.class
target/
# un comentario – esta línea es ignorada
# no permitir archivos con extensión .a
*.a
# autorizar el archivo lib.a, incluso aunque no se permitan los archivos .a
!lib.a
# ignorar el archivo TODO que está en el raíz, pero no otros (por ejemplo subdir/TODO)
/TODO
# ignorar todos los archivos en la carpeta build/
build/
# ignorar los archivos txt (ejemplo: doc/notes.txt) en el primer nivel de la carpeta, pero permitir doc/server/arch.txt
doc/*.txt
# ignorar todos los archivos .txt de la carpeta doc/
doc/**/*.txt
Para poder ignorar archivos, tenemos que modificar las propiedades del proyecto:
Ahora que el área de preparación está como tú quieres, podemos confirmar los cambios. Hay que recordar que cualquier cosa que esté sin preparar no se incluirá en la confirmación de archivos.
La forma más fácil de confirmar es escribiendo
git commit -m <comentario>:
$ git commit -m "Story 182: Fix benchmarks for speed"
[master]: created 463dc4f: "Fix benchmarks for speed"
2 files changed, 3 insertions(+), 0 deletions(-)
create mode 100644 README
En cada commit, GIT almacena un punto de control que conserva: un puntero a la copia puntual de los contenidos, metadatos del autor y el mensaje. Con cada commit, GIT realiza una fotografía del estado actual del repositorio.
Una rama GIT es simplemente un puntero móvil apuntando a una de esas confirmaciones. La rama por defecto de Git es la rama master.
Con GIT podemos crear ramas fácilmente gracias al comando:
git branch <nombre>
$ git branch testing
IMPORTANTE! Este comando sólo crea una nueva rama, no nos sitúa en ella.
Para crear una rama con SourceTree, pulsaremos el botón "Branch":
Nos mostrará el diálogo de propiedades:
Más adelante veremos una forma más eficiente de trabajar con Ramas y Etiquetas gracias a GIT Flow.
Para pasar de una rama a otra, utilizaremos el comando
git checkout <rama>
$ git checkout testing
A partir de este momento, cualquier commit que se realice será sobre la rama activa, en nuestro caso "testing"
$ vim test.rb
$ git commit -a -m 'made a change'
¿Qué sucede si ahora queremos volver a la rama anterior "master"?
$ git checkout master
Si hacemos algún cambio sobre la rama actual... ¿donde se almacenará? ¿cómo quedará nuestro repositorio?
$ vim test.java
$ git commit -a -m 'hacemos algunos cambios'
Con SourceTree podemos situarnos sobre las ramas fácilmente, pero primero tenemos que realizar un seguimiento local de la rama remota:
Tras mostrar el diálogo de confirmación del nombre de la rama, tendremos en local la rama remota y estaremos situados en ella.
Pero si ya hemos hecho en algún momento un seguimiento de la rama y queremos situarnos sobre ella, sólo tenemos que hacer doble clic sobre el nombre de la rama o seleccionar el menu contextual "Checkout branch <nombre>...".
Podemos saber en todo momento la rama en la que estamos ya que su nombre está seleccionado en negrita.
Con GIT se pueden crear etiquetas (marcas) en puntos específicos de la historia del repositorio. Para ello utilizaremos el comando git tag. Por ejemplo, para listar las etiquetas del repositorio actual:
$ git tag
v0.1
v1.3
O podemos buscar una etiqueta utilizando un patrón de búsqueda: git tag -l <:patrón>
$ git tag -l 'v1.4.2.*'
v1.4.2.1
v1.4.2.2
v1.4.2.3
v1.4.2.4
Con GIT podemos crear etiquetas en nuestra rama de trabajo gracias al comando:
git tag -a <nombre> -m <mensaje>
$ git tag -a v1.4 -m 'my version 1.4'
$ git tag
v0.1
v1.3
v1.4
Este tipo de etiquetas se denominan
Para crear una etiqueta con SourceTree, pulsaremos el botón "Tag":
Nos mostrará el diálogo de propiedades:
Más adelante veremos una forma más eficiente de trabajar con Ramas y Etiquetas gracias a GIT Flow.
Cuando se quiere compartir una rama o un conjunto de cambios con el resto del mundo, se debe enviar a un servidor remoto (push).
Los cambios realizados sobre las ramas locales NO se sincronizan automáticamente con los remotos, hay que enviarlo (push) expresamente.
Por ejemplo, supongamos que tenemos cambios que queremos publicar en una rama llamada "testing":
git push <remoto> <rama>
$ git push origin testing
Counting objects: 20, done.
Compressing objects: 100% (14/14), done.
Writing objects: 100% (15/15), 1.74 KiB, done.
Total 15 (delta 5), reused 0 (delta 0)
To git@gitlab.com:fjordan/git-training.git
* [new branch] testing -> testing
Para publicar los cambios con SourceTree, pulsaremos el botón "Push":
Nos mostrará el diálogo de propiedades:
Activando (checkout) una rama local a partir de una rama remota, se crea automáticamente lo que podríamos denominar "una rama de seguimiento" (tracking branch). Las ramas de seguimiento son ramas locales que tienen una relación directa con alguna rama remota.
Cuando queremos actualizar los contenidos de nuestro local con los contenidos del remoto, debemos utilizar el comando:
git pull
$ git pull
remote: Counting objects: 20, done.
remote: Compressing objects: 100% (14/14), done.
remote: Total 15 (delta 5), reused 0 (delta 0)
Unpacking objects: 100% (15/15), done.
From git@gitlab.com:fjordan/git-training
* [new branch] serverfix -> origin/serverfix
Para recuperar cambios con SourceTree, pulsaremos el botón "Pull":
Nos mostrará el diálogo de propiedades:
En el día a día, para realizar las tareas más comunes utilizaremos esta secuencia de comados sobre la rama de trabajo en curso:
Añadir cambios al repositorio:
$ git add .
$ git commit -m <mensaje>
$ git push origin <rama>
Obtener cambios del repositorio:
$ git pull
Con SourceTree, la secuencia de trabajo que emplearemos para compartir nuestro trabajo será:
El elemento principal de trabajo con GIT son las ramas. En ellas vamos a ir almacenando todos los elementos de nuestro proyecto: Releases, Fixes, nuevas Features, experimentos, etc. Necesitamos una forma de organizar el trabajo ordenada y que nos permite poder tener una trazabilidad y seguimiento del proyecto.
Git Flow es una extensión de GIT que facilita la gestión de ramas y flujos de trabajo.
Elementos básicos en Git Flow:
Para activar Git Flow en el proyecto, pulsamos su botón en la barra de herramientas:
La primera vez que lo utilicemos, nos preguntará los nombres de las ramas/etiquetas a utilizar. Dejamos los valores por defecto:
Una vez configurado Git Flow, para cualquier rama o etiqueta nueva que necesitemos, al pulsar el botón nos preguntará:
Una vez finalizada la rama en la que estamos trabajando, al pulsar el botón nos preguntará:
La metodología de trabajo propuesta irá asociada al uso en el proyecto de Git Flow.
Se utilizarán todos los tipos de ramas disponibles en Git Flow más un conjunto personalizado de etiquetas:
Un proyecto típico tendrá esta apariencia:
Las ramas de tipo feature tendrán las siguientes características:
Las ramas de tipo release tendrán las siguientes características:
Ejemplo: release/1.2.x
Las ramas de tipo hotfix tendrán las siguientes características:
Durante el ciclo de vida del proyecto, se establecerán las siguientes etiquetas para una versión X.Y.Z del proyecto:
Por Fernando Jordán / @fjordansilva