Introducción a Git y control de versiones
Introducción a Git y control de versiones
Integración continua
$OIUHGR2OWUD
9HUVLµQ
Nomenclatura
A lo largo de este tema se utilizarán distintos símbolos para distinguir elementos
importantes dentro del contenido. Estos símbolos son:
Anotación importante.
Enlace WEB.
Comandos.
Ejemplo.
Vídeo de ejemplo.
1. Objetivos
Los objetivos a alcanzar en este tema son:
• Conocer qué es una herramienta CASE.
• Conocer qué es un IDE.
• Entender qué es un VCS y cuáles son sus funciones principales.
• Comprender las distintas razones por las que se debe usar un VCS.
• Conocer la terminología asociada a un VCS.
• Conocer los distintos tipos de VCS.
• Conocer distintos VCS.
• Conocer las características de Git.
• Instalar Git.
• Realizar la confguración inicial de Git.
2. Introducción
Hace ya tiempo que el concepto de programador solitario que desarrolla aplicaciones
monolíticas (salvo por el uso de alguna librería externa) con una decena o poco más de
fcheros y una vida útil relativamente corta, pasó a la historia. Hoy en día la competencia
existente y la mejora de la tecnología nos lleva a la creación de aplicaciones complejas,
desarrolladas por varios equipos (muchas veces en ubicaciones distintas) y con una vida
relativamente larga con el objeto de amortizar la inversión realizada. Es por ello que los
propios programadores han ido desarrollando herramientas para facilitar las tareas de
cada una de las fases del ciclo de desarrollo de una aplicación.
Cada una de ellas (y otras muchas que no aparecen) se aplican en alguna de las fases
de ciclo de desarrollo, siendo la fase de codifcación la que incluye más y más diferentes
tipos de herramientas. De hecho, lo más habitual hoy en día es encontrarlas agrupadas en
los denominados IDE (Integrated Development Environment) o entornos de desarrollo.
Estos entornos son aplicaciones modulares que teniendo al editor de código como
elemento central, incluyen de manera nativa o mediante la inclusión de plugins muchas de
estas herramientas.
Estos entornos dan soporte a las tareas de desarrollo realizadas por una persona pero,
en cuanto el proyecto crece en complejidad y por tanto en número de personas, es
necesario dar un paso más allá. En estos escenarios, cada miembro del equipo de
desarrollo dispone de un sistema con su propio IDE en el que realiza cierto trabajo de
manera individual. Dicho trabajo debe ser convenientemente combinado con el resto de
sus compañeros para obtener el resultado fnal. Es en este punto donde aparecen
herramientas más relacionadas con la ingeniería del software como los gestores de
incidencias, gestores de proyectos o los sistemas de control de versiones (aunque con
alguna puntualización como veremos en el siguiente apartado).
2. ¿Qué es un VCS?
Tal y como acabamos de ver un sistema de control de versiones (VCS, Version Control
System) es una herramienta CASE, utilizada en la fase de integración y/o mantenimiento,
y no necesariamente incluida en los entornos de desarrollo. Pero ¿qué es exactamente?
¿cuál es su función?
Pensemos en primer lugar en el trabajo de un programador solitario. En su día a día
hace cambios en el código muy a menudo: corrige errores, añade nuevas características o
simplemente modifca el código. Mucho de este código se almacena como fcheros de
texto plano y la gran mayoría de cambios se realizan modifcando estos fcheros. Cada vez
que realiza un cambio y guarda el fchero, la antigua versión del fchero se sobrescribe con
las nuevas características. Desafortunadamente, el programador no es perfecto y el nuevo
código puede generar un mal funcionamiento del programa. En esos casos para poder
averiguar donde está el error, es interesante poder volver a la versión anterior que
funcionaba para comparar y poder detectar qué es lo que se ha hecho mal.
Por otra parte, situémonos en un escenario en el que dos programadores están
trabajando sobre el mismo fchero situado en una unidad de red compartida. Uno de los
programadores modifca el fchero y lo graba mientras el otro sigue trabajando en él.
Cuando el segundo graba el fchero, los cambios que ha realizado el primero desaparecen.
Estas son las dos funciones principales que un sistema de control de versiones ayuda a
solucionar, pero no las únicas. Los VCS proporcionan otras funcionalidades como la
comparación de versiones, el etiquetado, creación de bloqueos, generación de ramas...
3. Terminología
La mayoría de los VCS defnen de manera común una serie de terminología (entre
corchetes se indica la traducción en inglés, de uso más común que la española):
3.1. Conceptos
3.2. Acciones
• Añadir [en: add]: Añadir un fchero al repositorio por primera vez, es decir, permitir
al sistema de control de versiones que realice un seguimiento del fchero.
• Traer versión [en: get latest version o check out]: traer desde el repositorio la
última versión de un fchero.
• Traer para editar [en: check out for edit]: traer desde el repositorio la última versión
de un fchero pero de modo “editable”. En muchos sistemas check out es lo mismo
que check out for edit ya que por defecto traen el fchero en modo edición.
• Enviar [en: check in o commit]: sube un fchero al repositorio (si ha sido cambiado).
Al fchero se le asigna un número de versión y el resto de programadores puede
hacer un check out o un sync posteriormente para obtener la última versión.
• Mezclar [en: merge]: aplicar los cambios de un fchero a otro para ponerlo al día.
Por ejemplo, podemos mezclar las novedades de una rama en otra.
• Resolver confictos [en: resolve]: solucionar los problemas encontrados (confictos)
al hacer un check in. Una vez solucionados se realiza el check in de nuevo.
• Comparar [en: dif o delta]: encontrar las diferencias entre dos fcheros. Habitual
para ver que ha cambiado entre revisiones.
• Revertir [en: revert]: descartar los cambios locales y recargar la última versión que
existe en el repositorio.
• Actualizar o sincronizar [en: update o sync]: actualiza todos los fcheros con la
última versión existente en el repositorio.
• Bloquear [en: locking]: tomar el control de un fchero para que ningún otro
programador pueda editarlo hasta que no sea desbloqueado. Utilizado en algunos
sistemas para evitar confictos.
• Romper el bloqueo [en: breaking the lock]: forzar el desbloqueo de un fchero. No es
recomendable, pero puede darse el caso en el que sea necesario. Por ejemplo, que
un usuario haya bloqueado y se haya ido de vacaciones.
3.3. Ejemplo
Para entender un poco mejor la terminología anterior vamos a trabajar con un escenario
fcticio sobre el que realizaremos algunas operaciones.
Add
Lo primero que hay que hacer es añadir lista.txt al control de versiones mediante una
comando de Add
En este caso podemos ver como el usuario u1, desde su directorio de trabajo, incluye el
fchero lista.txt a la línea principal (main) del servidor donde se encuentra el sistema de
control. El fchero lista.txt ya tiene un ítem (café), pero podría estar vacío.
Automáticamente el VCS le asigna un número de revisión (r1).
Check out (for edit), check in (commit) y revert
u1 va modifcando el fchero a lo largo de la semana, incluyendo nuevos ítems a la lista.
Para ello, u1 realiza primero un check out for edit. Esta operación en realidad son dos
operaciones: en primer lugar se actualiza el fchero lista.txt del directorio de trabajo a la
última versión existente en el servidor (r1) y posteriormente se activa la posibilidad de
editarlo.
En la mayoría de VCS las acciones check out y check out for edit están
agrupadas en una sola, check out. Es por ello que a lo largo de este tema
se utilizará únicamente check out, dando por entendido que en dicha
acción se incluye la posibilidad de edición del fchero.
Una vez u1 tiene a su disposición la copia, la edita y añade un ítem (peras) y, una vez
añadido, lo actualiza en el servidor mediante un chek in (o commit) creando una nueva
revisión (r3). Es posible que u1 una vez modifcado el fchero, se de cuenta de un error y
no quiera perder los cambios y volver a la última versión del servidor para lo cual
realizaría una acción revert.
Tags
Puede ser interesante que al fnal de cada semana, antes de empezar con la lista de la
semana siguiente, etiquetar cada versión del fchero para saber que fue lo que se compró
en una determinada fecha.
Dif
Uno de los usuarios tiene interés en ver en qué se ha modifcado la lista entre dos
versiones. Para ello realizará una acción dif
Para obtener las diferencias, el VCS se hace preguntas como ¿qué debo modifcar en
una versión para llegar a otra?. Si nos fjamos en el ejemplo, para llegar a r5 a partir de r4,
habría que añadir (+) vino y leche y eliminar (-) café y zumo. Las consultas pueden
hacerse entre cualesquiera versiones si bien cuanto más alejadas en el tiempo estén, por
lo general, más tiempo tarda el sistema en calcular las diferencias y más complejo será
seguirlas. Además, el VCS da las diferencias por líneas o bloques de líneas consecutivas,
es decir, indica que en la línea 1 de la versión r4 había café y en la línea 1 de r5 se ha
quitado (-) café y se ha añadido (+) vino.
Branch
u1 decide que quiere experimentar cocinando comida japonesa. Para ello abre una
rama llamada japonesa, donde irá incluyendo ítems relacionados con ese tipo de comida,
hasta que una semana decida ponerse a ello.
Al abrir una rama lista.txt puede evolucionar por dos caminos distintos main y japonesa.
El punto de partida de japonesa (r4) es una copia de la revisión existente en main en el
momento de abrir la rama. A partir de ese momento u1 puede elegir sobre que rama
trabajar. Si desea incluir algo en la rama japonesa, u1 tiene que ir a esa rama, hacer un
chekout, modifcar y hacer un chekin sobre la rama. Posteriormente para seguir añadiendo
cosas en la lista del día a día debe volver a la rama main.
Merge
u1 por fn se decide y la semana que viene está dispuesto a cocinar comida japonesa,
por lo que ha de mezclar (merge) la lista de la rama japonesa con la rama principal que es
de donde se obtiene la lista con la que se irá al mercado.
Cuando el usuario mezcla una rama con otra, el VCS calcula las diferencias entre el
principio de la rama a mezclar (o desde la última versión del fchero que fue mezclada) y
la versión fnal y aplica dichas diferencias a la versión actual de la rama destino. En el
ejemplo se calcula la diferencia entre r7 y r4, es decir añadir (+) soja y sake.
El hecho de mezclar una rama con otra no implica que una de las dos
desaparezca. Cada una puede seguir avanzando por su camino.
El mezclado no sólo implica la existencia de dos ramas. En el caso de que dos usuarios
estén editando el mismo fchero, cuando ambos realizan el checkin, el VCS realiza
automáticamente el merge.
Confictos
En la gran mayoría de casos el propio VCS mezcla las versiones sin mayor problema,
pero puede darse casos en que esto no sea así.
Tanto u1 como u2 deciden que quieren cambiar la lista y para ello hacen un check out
de manera más o menos simultánea. u2 no quiere zumo y en cambio quiere agua,
mientras que u1 que tampoco quiere zumo, quiere pan en su lugar. u2 realiza el cambio y
e checkin antes que u1. Cuando u1 va a realizar el chekin, su copia local tiene que
mezclarse con la r4 pero el sistema detecta que desde que se hizo el checkout (r3) otro
usuario ha cambiado las mismas líneas (en este caso la nº2). El VCS no tiene información
sufciente para decidir con cual quedarse (¿agua o pan?) y genera un conficto. En este
caso solicita al usuario u2 que resuelva el conficto, es decir, o que manualmente decida
cual es la línea que deberá permanecer o que incluya las dos líneas.
En condiciones normales la aparición de confictos no es (o al menos no debería ser)
muy habitual. Con un poco de organización, distribución ordenada del trabajo y haciendo
checkin de manera más o menos habitual, su aparición disminuye mucho. Aun así, tal
como se comentó anteriormente, si se va a editar gran parte del fchero y durante mucho
tiempo, puede ser recomendable que el usuario lo bloqueé para evitar la edición por parte
de otros.
4. Tipos VCS
Hay dos tipos diferentes de VCS: distribuidos y centralizado.
4.1. Centralizados
Los sistemas centralizados usan un servidor central para almacenar el repositorio así
como el control de acceso al mismo. El repositorio se mantiene separado de la copia que
existe en el directorio de trabajo de cada usuario. Normalmente, este servidor suele ser un
servidor dedicado (o al menos un ordenador distinto al de cualquier usuario), aunque en
proyectos pequeños o con un único usuario se suele asignar otra carpeta del ordenador de
trabajo.
Con un sistema centralizado, la copia de trabajo sólo almacena la versión actual de los
fcheros del proyecto y las modifcaciones que el usuario esté realizando en ese momento.
La única copia de la historia completa está en el repositorio. Cuando un usuario envía
(checkin) cambios, los envía al repositorio central y en ese momento ya podrán ser
descargados por el resto de usuario.
Los esquemas del apartado anterior pueden referirse claramente a este tipo de VCS.
Como puede verse en el esquema, todos los usuarios hacen su checkin y checkout sobre
la rama principal: u1 añade peras y u2 añade agua. Para que los cambios de u1 puedan
ser vistos por u2, u1 tiene que hacer checkin al servidor.
Cada uno de los usuarios realiza los checkout y chekin con respecto a su propio
repositorio. A esos cambios sólo tendrá acceso cada usuario (cada uno al suyo
respectivamente) hasta que decida compartirlos con uno o con el resto de usuarios (o con
el servidor). Esto es una diferencia con respecto al sistema centralizado, en el que al hacer
un chekin todos los usuarios tienen acceso a la modifcación.
5. Sistemas distribuidos
5.1. Ventajas
• El ordenador de cada usuario hace las veces de entorno de pruebas. Se pueden
hacer todos los cambios que se deseen, y sólo compartirlos cuando sean
adecuados.
• Es posible trabajar desconectado. Sólo es necesario conectarse en el momento de
compartir los cambios.
• Es rápido. Los cálculos de las diferencias, los checkin, checkout o revertir el código
se hace en local.
• A cada cambio se le asigna un identifcador, de manera que resulta muy sencillo
realizar un seguimiento del mismo.
• El trabajo con un repositorio local permite que la creación de ramas y el mezclado
sea muy sencillo. Además, es posible la creación de ramas en local para pruebas
personales, pero también en un posible servidor remoto para crear una nueva
revisión de la aplicación.
• Requieren menos mantenimiento. En general, no es necesario la instalación y
confguración de un servidor.
• Es más seguro ante pérdidas de información. Al haber información replicada en los
repositorios locales, la recuperación en caso de perdida de uno de ellos se hace sin
problemas.
5.2. Inconvenientes
• No hay claramente una última versión del código. En un sistema distribuido en el
que no haya un repositorio central, no queda claro de qué se compone la última
versión estable.
• No existen números de revisión defnidos. En un sistema distribuido en realidad no
hay números de versión, ya que cada repositorio tiene sus propios números
dependiendo de la cantidad de cambios que se han realizado en él. Por contra,
como se ha comentado antes, existe un identifcador de la forma e4e561f3 por
cada cambio, más complicado de recordar.
5.3. Terminología
La propia idiosincrasia de un sistema distribuido hace que sea necesaria la aparición de
tres nuevas acciones:
• Empujar [en: push]: envía un cambio desde un repositorio a otro. Según cual sea la
política del sistema podría ser necesario tener los permisos adecuados.
• Extraer [en: pull]: coge los cambios desde un repositorio.
• Clonar [en: clone]: traer una copia exacta del proyecto dede un repositorio a otro.
6. Git
Existen en el mercado multitud de VCS. Por hacer una lista de los más conocidos
podríamos hablar de:
• Concurrent Versions System (CVS). Posiblemente el sistema que realmente dio a
conocer el control de versiones. Es de código abierto y de modelo centralizado.
• Subversion (svn). Es la evolución de CVS. Durante muchos años ha sido, junto con
Mercurial en el modelo distribuido, un estandar de facto.
• Visual SourceSafe y Visual Studio Team Foundation Server. Son las herramientas de
control de versiones de Microsoft. La primera está orientada a equipos de desarrollo
pequeños, mientras la segunda va un poco más allá, permitiendo no sólo el control
de versiones sino además características extras relacionadas con la gestión de
proyectos en equipos como el control de incidencias. Son de código propietario y
siguen el modelo centralizado.
• BitKeeper. Conocido por ser durante algunos años el utilizado para el control del
kernel de Linux. Es código propietario y sigue el modelo distribuido.
• Mercurial. Surgió como alternativa libre a BitKeeper. Se le podría asignar el papel
de estándar de facto en modelos distribuidos.
Pero sin duda el referente libre actual esta siendo Git. Surge por la necesidad de Linux
Torvalds, creador de Linux, de disponer de un sistema que solucionara los problemas que
existían en BitKeeper a la hora de mantener el código del kernel. El kernel es un proyecto
de grandes dimensiones: no sólo maneja una gran cantidad de archivos, si no que además
implica a muchos usuarios con desarrollos en paralelo.
Resulta complicado saber porque hoy en día Git ha llegado a quitar ese título
de estándar de facto a otros sistemas como Mercurial, ya que al fnal los
factores que intervienen son muchos, pero por podríamos incluir:
• Existen muchos interfaces gráfcos para el manejo de Git. Además
cada vez más IDE's van incorporando soporte para él, ya sea de
manera nativa o mediante plugins.
• Cada vez hay más desarrolladores que trabajan con Git y que están contentos con
él. Eso amplifca el efecto "viral".
• Es distribuido. Los proyectos cada vez son más grandes y más modularizados. La
distribución permite que varios equipos trabajen con sus propias ramas y revisiones
sin interferir en el trabajo diario del resto de grupos.
• Incorpora sistemas de importación/exportación a otros VCS, lo que hace que las
migraciones no sean demasiado traumáticas.
• Existe mucha documentación en Internet (mucha de ella gratuita).
• Su escalabilidad es excelente. Permite trabajar igual de bien con proyectos
pequeños como con grandes.
• Es libre
git --version
[user]
name=alfredo
[core]
repositoryformatversion = 0
flemode = true
bare = false
logallrefupdates = true
ignorecase = true
[branch "master"]
remote = origin
merge = refs/heads/mastero.
Las variables pueden tomar valor en cualquiera de los tres fcheros o incluso en los tres,
de manera que la confguración del proyecto prevalece sobre la del usuario y esta sobre la
general.
6.3. Modifcación
En un principio, si se tiene los permisos adecuados, los fcheros de confguración pueden
modifcarse con un simple editor de texto plano como nano, gedit o notepad. De todas
maneras, para evitar posibles errores en el formato, git proporciona una herramienta para
el trabajo con las confguraciones: git confg
De manera general su esquema es:
git confg [ambito] [accion] [parametro1_accion] [parametro1_accion]
[parametro3_accion]...
donde:
• ambito: hace referencia a si la modifcación es general (--system), del usuario (--
global) o del proyecto (opción por defecto, no es necesario indicar nada, sólo estar
en el directorio correspondiente)
• acción: acción a realizar en el fchero:
• list: listar toda la confguración
• get: obtener un valor de una variable.
• add: añadir a una variable un valor.
• unset: elimina la variable.
Veamos algunos ejemplos:
7. Referencias
Proyecto Git
Fuente: git-scm
Idioma: inglés/español