Documentos de Académico
Documentos de Profesional
Documentos de Cultura
INTRODUCCIÓN 4
TERMINOLOGÍA 5
TIPOS DE SCV 6
3.1 Local 7
3.2 Centralizado 7
3.3 Distribuido 9
GIT 11
4.1 Fundamentos de Git 11
4.2 Instalación 14
4.3 Configuración inicial 14
4.4 Obteniendo un repositorio 15
4.5 Comandos básicos 17
4.6 Comandos avanzados 25
4.7 Trabajar con ramas 28
4.8 Etiquetado 35
4.9 Hooks 39
4.10 Pull Request 46
GIT WORKFLOWS 48
5.1 GitFlow 48
Funcionamiento 49
Extensión flow de Git (Git-Flow) 51
5.2 GitHub Flow 54
Ventajas 54
Inconvenientes 54
5.3 GitLab Flow 55
Ventajas 55
Inconvenientes 56
5.4 Trunk-based Flow 56
Ventajas 56
Inconvenientes 56
5.5 Master-only Flow 57
Ventajas 57
Inconvenientes 57
6. GITHUB PAGES 58
7. BIBLIOGRAFÍA 60
2
UD 1 Sistemas de Control de Versiones
En ingeniería del software el control de versiones podemos definirlo como un sistema que
registra los cambios realizados sobre un archivo o conjunto de archivos a lo largo del tiempo
de tal manera que sea posible recuperar versiones específicas más adelante. Este control
puede llevarse a cabo utilizando herramientas como CVS, Mercurial, Git, etc
Aunque la gestión de los sistemas de control de versiones suele hacerse por línea de
comandos, las versiones más modernas de este tipo de herramientas suelen ofrecer la
posibilidad de realizar la gestión a través de interfaces gráficas fáciles de usar. Además,
muchas de ellas se integran con los los IDE más populares.
1. INTRODUCCIÓN
En proyectos de desarrollo software de una determinada envergadura resulta imprescindible
el uso de un SCV puesto que nos ofrece la posibilidad de deshacer cambios no deseados e
incluso, volver a versiones anteriores de nuestro desarrollo.
No existe un límite en el número de ramas que podemos crear sobre el tronco principal de
nuestro SCV. Por ejemplo, en la siguiente imagen disponemos de una rama principal y dos
ramas utilizadas para implementar la Little Feature y la Big Feature respectivamente.
3
UD 1 Sistemas de Control de Versiones
2. TERMINOLOGÍA
Los distintos Sistema de Control de Versiones suelen utilizar una terminología muy similar
que es interesante conocer para poder trabajar correctamente. Entre los conceptos más
destacados encontramos:
4
UD 1 Sistemas de Control de Versiones
● Subir (commit o check in): es añadir los cambios locales en el repositorio. Cabe
destacar que no los envía al servidor; los cambios quedan almacenados en el
repositorio local que se debe sincronizar.
● Bajar (check out): es copiar en el área de trabajo local una versión desde un
repositorio local, un repositorio remoto o una rama diferente.
● Pull: es la acción que copia los cambios de un repositorio (habitualmente remoto) en
el depósito local. Esta acción puede provocar conflictos.
● Push o fetch: son acciones utilizadas para añadir los cambios del repositorio local a
otro repositorio (habitualmente remoto). Esta acción puede provocar conflictos.
● Cambio (change o diff): representa una modificación concreta de un documento bajo
el control de versiones.
● Sincronización (update o sync): es la acción de combinar los cambios hechos al
repositorio con la copia de trabajo local.
● Conflicto (conflict): se produce cuando se intentan añadir cambios a un fichero que
ha sido modificado previamente por otro usuario. Antes de poder combinar los
cambios con el repositorio deberá resolver el conflicto.
● Bloqueo (lock): algunos sistemas de control de versiones en lugar de utilizar el
sistema de fusiones lo que hacen es bloquear los archivos en uso, por lo que sólo
puede haber un solo usuario modificando un fichero en un momento dado.
● Fusionar (merge o integration): es la acción que se produce cuando se quieren
combinar los cambios de un repositorio local con un remoto y se detectan cambios
en el mismo archivo en ambos repositorios y se produce un conflicto. Para resolver
este conflicto se deben fusionar los cambios antes de poder actualizar los
repositorios. Esta fusión puede consistir en descartar los cambios de uno de los dos
repositorios o editar el código para incluir los cambios del archivo en ambos lados.
Cabe destacar que es posible que un mismo fichero presente cambios en muchos
puntos diferentes que deben ser resueltos para poder dar la fusión por finalizada.
● Versión (versión o revisión): es el conjunto de cambios en un momento concreto del
tiempo. Se crea una versión cada vez que se añaden cambios a un repositorio.
● Etiqueta (tag, label o baseline): permite añadir una etiqueta a una subida para poder
identificar esta subida concreta de una forma más comprensible. Por ejemplo, se
puede etiquetar la primera versión de un software (1.0) o una versión en la que se ha
solucionado un error importante.
● Volver a la versión anterior (revert): descarta todos los cambios producidos en la
copia de trabajo desde la última subida al depósito local.
3. TIPOS DE SCV
Podemos diferenciar 3 tipos de sistemas de control de versiones; local, centralizado y
distribuido.
5
UD 1 Sistemas de Control de Versiones
3.1 Local
El más sencillo de todos. Consiste en copiar los archivos a otro directorio con el fin de
mantener un historial de cambios en local (ya sea copias o mediante registros en una base
de datos). Este método es muy común pero también es tremendamente propenso a
errores. Es fácil olvidar en qué directorio te encuentras y guardar accidentalmente en el
archivo equivocado o sobrescribir archivos que no querías.
Una de las herramientas de control de versiones más popular fue un sistema llamado
RCS, que todavía podemos encontrar en sistemas como Mac OS X. Esta herramienta
funciona guardando conjuntos de parches en un formato especial en disco, y es capaz de
recrear cómo era un archivo en cualquier momento a partir de dichos parches.
3.2 Centralizado
Los CVS locales aunque sencillos de utilizar traen consigo una problemática muy común; no
son válidos cuando lo que se necesita es llevar a cabo un proyecto que implique
colaboración entre varios. Los sistemas de Control de Versiones Centralizados (CVCS por
sus siglas en inglés) fueron desarrollados para solucionar este problema. Estos sistemas
tienen un único servidor que contiene todos los archivos versionados y varios
clientes que descargan los archivos desde ese lugar central. Este ha sido el estándar
para el control de versiones por muchos años.
6
UD 1 Sistemas de Control de Versiones
Como podemos deducir de lo anterior, las principales ventajas que presentan los CVS
centralizados son:
● Todas las personas saben hasta cierto punto en qué están trabajando los otros
colaboradores del proyecto.
● Más fácil administrar un CVCS que tener que lidiar con bases de datos locales en
cada cliente
Como desventajas, podemos remarcar el hecho de que sólo existe un punto único de
fallo que representa el servidor centralizado. Cuando tienes toda la historia del proyecto en
un mismo lugar, te arriesgas a perderlo todo (cosa que también ocurre en los SCV locales).
● CVS (Current Versions System). Creado en los 80 y con licencia GNU, se considera
el primer SCV centralizado. Una característica distintiva es que el servidor solo
acepta actualizaciones de los ficheros que estén en la última versión. Esto implica
que los usuarios deben actualizar sus copias locales antes de subirlas al servidor.
● SVN. El proyecto de Subversion surgió en el año 2000 con el objetivo crear un
sistema de control que solventase las carencias y problemas de CVS como por
ejemplo:
○ Commits atómicos, en CVS un commit interrumpido puede dejar datos
inconsistentes.
○ La creación de ramas es más eficiente, con complejidad constante a
diferencia de CVS que es lineal (aumenta con el número de ramas).
○ Manejo de archivos binarios como tal, CVS los trata como archivos de texto.
○ Envía los incrementos de los ficheros en la comunicación cliente- servidor,
en lugar de los ficheros completos como CVS.
7
UD 1 Sistemas de Control de Versiones
3.3 Distribuido
Los sistemas de Control de Versiones Distribuidos (DVCS por sus siglas en inglés) ofrecen
soluciones para los problemas que han sido mencionados. En un DVCS (como Git,
Mercurial, Bazaar o Darcs), los clientes no solo descargan la última copia instantánea de los
archivos, sino que se replica completamente el repositorio. De esta manera, si un servidor
deja de funcionar y estos sistemas estaban colaborando a través de él, cualquiera de los
repositorios disponibles en los clientes puede ser copiado al servidor con el fin de
restaurarlo. Cada clon es realmente una copia completa de todos los datos.
8
UD 1 Sistemas de Control de Versiones
extensible.
● Git. Sin duda el SCV más utilizado en la actualidad. En el 2005, la relación entre la
comunidad que desarrollaba el kernel de Linux y la compañía que desarrollaba
BitKeeper se vino abajo y la herramienta dejó de ser ofrecida de manera gratuita.
Esto impulsó a la comunidad de desarrollo de Linux (y en particular a Linus Torvalds,
el creador de Linux) a desarrollar su propia herramienta basada en algunas de las
lecciones que aprendieron mientras usaban BitKeeper. Algunos de los objetivos del
nuevo sistema fueron los siguientes:
○ Velocidad
○ Diseño sencillo
○ Gran soporte para desarrollo no lineal (miles de ramas paralelas)
○ Completamente distribuido
○ Capaz de manejar grandes proyectos (como el kernel de Linux)
eficientemente (velocidad y tamaño de los datos)
9
UD 1 Sistemas de Control de Versiones
4. GIT
Como hemos dicho, Git es el Sistema de Control de Versiones más utilizado en la
actualidad. Desde su nacimiento en 2005, Git ha evolucionado y madurado para ser fácil de
usar siempre basándose en una serie de características que le permiten destacar del resto
de soluciones similares que hemos visto en el punto anterior.
10
UD 1 Sistemas de Control de Versiones
Git no maneja ni almacena sus datos de esta forma. Git maneja sus datos como un
conjunto de copias instantáneas de un sistema de archivos miniatura. Cada vez que
confirmas un cambio, o guardas el estado de tu proyecto en Git, él básicamente toma una
foto del aspecto de todos tus archivos en ese momento y guarda una referencia a esa
copia instantánea. Para ser eficiente, si los archivos no se han modificado Git no
almacena el archivo de nuevo, sino un enlace al archivo anterior idéntico que ya tiene
almacenado. Git maneja sus datos como una secuencia de copias instantáneas.
La mayoría de las operaciones en Git sólo necesitan archivos y recursos locales para
funcionar. Al no intervenir retardos de red como podría suceder en otros sistemas, Git
resulta mucho más rápido. Además, esta característica, permite que podamos seguir
realizando cambios y confirmándose en nuestro servidor local sin necesidad de estar
conectados a la red.
Integridad
Todo en Git es verificado mediante una suma de comprobación (checksum en inglés) antes
de ser almacenado, y es identificado a partir de ese momento mediante dicha suma. Esto
11
UD 1 Sistemas de Control de Versiones
significa que es imposible cambiar los contenidos de cualquier archivo o directorio sin
que Git lo sepa. No puedes perder información durante su transmisión o sufrir corrupción
de archivos sin que Git sea capaz de detectarlo.
Git guarda todo no por nombre de archivo, sino por el valor hash de sus contenidos. Esta
funcionalidad está integrada en Git al más bajo nivel y es parte integral de su filosofía
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 enmendar,
o que de algún modo borre información.
Tres estados
Sin duda es el fundamento más importante. Git tiene tres estados principales en los que se
pueden encontrar tus archivos:
12
UD 1 Sistemas de Control de Versiones
4.2 Instalación
Git se encuentra disponible en la mayoría de plataformas, incluyendo Linux, Windows,
MacOS y Solaris. En la página oficial podemos encontrar el enlace para descargarlo para
los diferentes sistemas operativos.
Una vez hecho esto, podemos comprobar que efectivamente la versión instalada es la
correcta por medio de la instrucción:
git --version
● Archivo /etc/gitconfig: Contiene valores para todos los usuarios del sistema y todos
sus repositorios. Si pasamos la opción --system a git config, lee y escribe
específicamente en este archivo.
git config --system core.editor emacs
● Archivo config en el directorio de Git (es decir, .git/config) del repositorio que
estemos utilizando actualmente: Este archivo es específico del repositorio actual.
13
UD 1 Sistemas de Control de Versiones
Cada nivel sobrescribe los valores del nivel anterior, por lo que los valores de .git/config
tienen preferencia sobre los de /etc/gitconfig.
Una vez realizados los cambios en la configuración que deseemos, podemos comprobar
que éstos se han almacenado correctamente. Para ello, solo tenemos que ejecutar:
Inicializar un repositorio
git init
Esto crea un subdirectorio nuevo llamado .git, el cual contiene todos los archivos
necesarios del repositorio.
14
UD 1 Sistemas de Control de Versiones
del proyecto.
● La carpeta info guarda un archivo global de exclusión con los patrones a ignorar
además de los presentes en el archivo .gitignore
● El archivo description se utiliza solo en el programa GitWeb
Tras ejecutar el comando git init sobre nuestro directorio, necesitaremos una serie de pasos
extra para poder conectar éste con el repositorio remoto que, como hemos dicho, debemos
haber creado previamente. Todos estos pasos suele exponerlos Github en el momento que
creamos un repositorio desde cero y suelen ser:
Clonar un repositorio
La segunda de las formas de obtener un repositorio Git consiste en obtener una copia o clon
de uno que ya exista. En este caso, la instrucción que deberemos ejecutar será git clone
[url]. Por ejemplo:
15
UD 1 Sistemas de Control de Versiones
La ejecución de este comando hará lo mismo que el anterior pero el directorio donde
descargará toda la información será misComandos
Como hemos visto, uno de los fundamentos principales de Git consiste en diferenciar los
distintos archivos almacenados según su estado. Por este motivo, es interesante conocer
de qué forma podemos averiguar qué elementos de nuestro proyecto están rastreados y
cuáles no. Los archivos rastreados (tracked files en inglés) son todos aquellos
archivos que estaban en la última instantánea del proyecto; pueden ser archivos sin
modificar, modificados o preparados. Los archivos sin rastrear son todos los demás -
cualquier otro archivo en tu directorio de trabajo que no estaba en tu última instantánea y
que no está en el área de preparación (staging area).
La Herramienta principal para determinar en qué estado están los archivos de un proyecto
con el comando git status. Si ejecutamos este comando inmediatamente después de clonar
un repositorio, obtenemos una salida similar a la siguiente:
16
UD 1 Sistemas de Control de Versiones
El comando te indica en qué rama estás y te informa sobre qué ha variado con respecto a la
misma rama en el servidor.
17
UD 1 Sistemas de Control de Versiones
En los ejemplos de consulta de estado que hemos visto en el punto anterior, hemos hecho
uso de la instrucción git add. Así pues, git add nos permite rastrear ficheros (pasarlo a la
stage área) de nuestro directorio de trabajo indicando así que se han realizado los cambios
oportunos sobre estos y que formarán parte del próximo commit a nuestro servidor local.
La sintaxis de la instrucción git add admite como parámetro tanto el nombre de un fichero en
concreto, como un patrón. Por tanto, podemos ejecutar:
o bien:
● -u: sólo añade al índice aquellos ficheros que ya están siendo monitorizados por git
● -n: opción es muy práctica ya que nos mostrará en pantalla lo que el comando
git-add haría sin actualizar el índice.
Si queremos eliminar de nuestra staged area algún archivo podemos utilizar el comando
git reset HEAD nombreArchivo para devolverlo a su estado de no confirmado. Eso sí,
debe existir algún commit previo en nuestro repositorio para que exista el HEAD.
Para eliminar archivos de Git, debemos eliminarlos de nuestros archivos rastreados (del
área de preparación) y luego confirmar. No basta con eliminarlos físicamente del
directorio de trabajo. Para ello existe el comando git rm que se encarga de eliminar el
archivo de nuestro directorio de trabajo, y además lo añade al área de staged files.
18
UD 1 Sistemas de Control de Versiones
Al igual que pasaba con el comando git reset, podemos utilizar git rm --cached
nombreFichero para eliminar archivos de nuestra área de preparación. No obstante, hay
que tener en cuenta que:
● git rm --cached elimina el archivo del índice pero lo deja en el directorio de trabajo.
Esto le indica a Git que ya no desea rastrear el archivo.
● git reset HEAD deja el archivo como un archivo de seguimiento en el índice, pero las
modificaciones almacenadas en caché en el índice se pierden.
19
UD 1 Sistemas de Control de Versiones
Estos dos pasos (realizar el commit y escribir el comentario asociado) pueden ejecutarse al
mismo tiempo si añadimos la opción -m como en el siguiente ejemplo:
A veces queremos tirar para atrás el último commit que hemos hecho porque hemos
añadido más archivos de la cuenta, queremos hacer commit de otra cosa o, simplemente,
porque ahora no tocaba. Si todavía no has llevado tus cambios al repositorio remoto tienes
dos formas de hacer esto. Ambas son válidas pero dependerá si quieres, o no, mantener los
cambios del commit.
Con el comando reset hacemos que la rama actual retroceda a la revisión que le
indicamos. En este caso le decimos HEAD∼1. Esto significa que queremos volver a
la versión inmediatamente anterior a la que estamos ahora.
El parámetro --soft es el que va a hacer que los cambios que habíamos hecho en el
commit, en lugar de eliminarlos, nos los mantenga como cambios locales en nuestro
repositorio. De hecho, al ejecutar este comando, no se eliminarán los cambios del
commit, sino que se mantendrán como cambios locales. Por lo que podrías volver a
hacer exactamente el mismo commit que antes.
20
UD 1 Sistemas de Control de Versiones
Es simplemente el mismo comando pero cambiamos --soft por --hard. Esto eliminará
los cambios de los que habíamos hecho commit anteriormente.
A veces no quieres tirar atrás el último commit que has hecho si no que simplemente
quieres arreglarlo. Aquí hay dos opciones:
● Sólo queremos arreglar el mensaje que hemos usado para el último commit
Ya sea que sólo queremos cambiar el mensaje de commit o que además queremos añadir
modificaciones en el último commit, lo importante es que esto NO va a crear un nuevo
commit si no que va a solucionar el anterior.
Importante: El parámetro de --amend es muy útil pero sólo funciona con el último commit
y siempre y cuando NO esté publicado en el repositorio remoto. Si ya hemos hecho push
de ese commit, esto no va a funcionar. Deberíamos hacer un git revert en su lugar.
El comando git diff se utiliza cuando deseamos ver las diferencias entre distintas versiones
de nuestros archivos. Las comparaciones que más se suelen utilizar son:
● git diff (sin ningún parámetro): Revisa las diferencia entre nuestro entorno de trabajo
y nuestra staged área
21
UD 1 Sistemas de Control de Versiones
● git diff --staged o git diff --cached: revisa las diferencias entre nuestra staged area y
la última confirmación o commit
● git diff nombreRama1 nombreRama2: revisa diferencias entre dos ramas distintas.
Un ejemplo de salida del comando git diff sería el que se muestra a continuación. En este
caso, en nuestro entorno de trabajo tenemos el fichero CONTRIBUTIN.md que aún no
hemos añadido al stage area:
Después de haber hecho varias confirmaciones, o si has clonado un repositorio que ya tenía
un histórico de confirmaciones, probablemente quieras mirar atrás para ver qué
modificaciones se han llevado a cabo. La herramienta más básica y potente para hacer esto
es el comando git log.
En caso de no pasar ningún parámetro a la llamada, git log nos muestra las confirmaciones
hechas sobre ese repositorio en orden cronológico inverso. Es decir, las confirmaciones
más recientes se muestran al principio.
22
UD 1 Sistemas de Control de Versiones
El comando git shortlog se utiliza para resumir la salida de git log. Toma muchas de las
mismas opciones que el comando git log pero, en lugar de enumerar todos los commits,
presentará un resumen de los commits agrupados por autor.
Este no es un comando de git como tal sino una opción que Git nos ofrece. Puede que
existan determinados archivos en nuestro espacio de trabajo que no queremos que Git
rastree. Pues bien, en estos casos tenemos la opción de crear un fichero .gitignore en
donde listaremos los patrones que no queremos que Git tenga en cuenta.
Crear un archivo .gitignore antes de comenzar a trabajar es generalmente una buena idea,
pues así evitamos confirmar accidentalmente archivos que en realidad no queremos incluir
en nuestro repositorio.
Las reglas sobre los patrones que puedes incluir en el archivo .gitignore son las siguientes:
23
UD 1 Sistemas de Control de Versiones
Este comando solo funciona si clonaste de un servidor sobre el que tenemos permisos de
escritura y si nadie más ha enviado datos por el medio. Si alguien más clona el mismo
repositorio y envía información antes que nosotros, nuestro envío será rechazado. En ese
caso, tendremos que traernos su trabajo y combinarlo con el nuestro antes de poder enviar
datos al servidor.
git fetch
Puede que el contenido del servidor remoto sea modificado mientras nosotros trabajamos
en nuestro servidor local y necesitemos ver cuáles han sido los cambios efectuados para
poder juntarlos con los nuestros. En estos casos podemos optar por dos opciones:
● Obtener en un primer paso los cambios remotos pero no juntarlos (mergearlos) con
los nuestros y en un segundo paso realizar la unión.
● Obtener y combinar los cambios remotos con un único paso
Para el primero de los casos, Git nos ofrece el comando git fetch [nombre rama remota].
Una vez ejecutado, el comando irá al proyecto remoto y se traerá todos los datos que aún
no tenemos en nuestro servidor local. Luego de hacer esto, tendremos referencias a todas
las ramas del remoto, las cuales podemos combinar e inspeccionar cuando quieras.
24
UD 1 Sistemas de Control de Versiones
En cambio, si consultamos el contenido de la nueva rama vemos que el fichero creado por
el usuario 2 sí que está:
Por tanto, es importante destacar que el comando git fetch solo trae datos a nuestro
repositorio local. Ni lo combina automáticamente con nuestro trabajo ni modifica el
trabajo que llevamos hecho. La combinación con nuestro trabajo debemos hacerla
manualmente cuando estemos listos.
En nuestro caso deberíamos hacer un merge (que veremos más adelante pero que
básicamente añade los cambios de una rama en otra) de la rama nueva que se ha creado a
la rama master para poder disponer de los cambios del usuario 2.
25
UD 1 Sistemas de Control de Versiones
git pull
Imaginemos ahora que queremos actualizar nuestro repositorio local con los posibles
cambios que se hayan podido producir en el repositorio remoto. Si trabajamos en un mismo
repositorio con más gente, este es un paso imprescindible para mantener nuestra copia
local del repositorio al día. De hecho, si existen cambios en el repositorio remoto, Git no nos
dejará subir cambios al repositorio hasta que hayamos descargado la versión más reciente
y la hayamos fusionado con nuestra versión local. Incluso si trabajamos solos, es posible
que subamos cambios desde más de un ordenador, por lo que saber cómo descargar los
cambios del repositorio remoto también resulta útil.
La forma más sencilla de actualizar el repositorio local es mediante el comando git pull:
git pull
A continuación se muestra un ejemplo del comando git pull. En este caso, previo a la
ejecución de dicha instrucción, otro usuario con permisos ha modificado un fichero del
repositorio. Al ejecutar el git pull vemos como se descarga el cambio en nuestro repositorio
local.
26
UD 1 Sistemas de Control de Versiones
A diferencia de git fetch, git pull descarga los cambios e intenta fusionarlos sobre nuestra
rama de trabajo.
Esto ocurre cuando git no puede realizar el merge tras haberse traído de remoto todos los
cambios. En este caso hemos realizado cambios sobre el primerFichero.txt. Tras estos
cambios (sobre los cuales hemos hecho commit), hemos intentado realizar el pull para
actualizar nuestro directorio local. Lo que ha pasado es que, como otro usuario ya había
subido un nuevo cambio sobre primerFichero.txt que nosotros no teníamos en local, git no
sabe cómo combinar ambos y nos delega esta tarea a nosotros.
27
UD 1 Sistemas de Control de Versiones
Las ramas nos pueden servir para muchos casos de uso. Por ejemplo, para la creación de
una funcionalidad que queramos integrar en un programa y para la cual no queremos que la
rama principal se vea afectada. Esta función experimental se puede realizar en una rama
independiente, de modo que, aunque tardemos varios días o semanas en terminarla, no
afecte a la producción del código que tenemos en la rama principal y que permanecerá
estable.
El trabajo con ramas resulta muy cómodo en el desarrollo de proyectos, porque es posible
que todas las ramas creadas evolucionen al mismo tiempo, pudiendo el desarrollador pasar
de una rama a otra en cualquier momento según las necesidades del proyecto. Si en un
momento dado el trabajo con una rama nos ha resultado interesante, útil y se encuentra
estable, entonces podemos fusionar ramas para incorporar las modificaciones del proyecto
en su rama principal.
git branch
Es importante comprender que las ramas son solo punteros a las confirmaciones. Cuando
creas una rama, todo lo que Git tiene que hacer es crear un nuevo puntero, no modifica el
repositorio de ninguna otra forma. Si empiezas con un repositorio que tiene este aspecto:
28
UD 1 Sistemas de Control de Versiones
Hay que tener en cuenta que este comando solo crea la nueva rama. Para empezar a
añadir confirmaciones, necesitaremos seleccionarla con el comando git checkout que
ahora veremos y, a continuación, utilizar los comandos estándar git add y git commit.
Ahora que ya hemos creado una rama en local, necesitamos saber cómo subirla a nuestro
repositorio remoto para que el resto de usuarios pueda tener acceso. Para ello, bastará con
ejecutar el siguiente comando push:
Por ahora, todas las de ramas locales. El comando git branch también funciona con ramas
remotas. Para trabajar en ramas remotas, primero hay que configurar un repositorio remoto
y añadirlo a la configuración del repositorio local.
Eliminación de ramas
29
UD 1 Sistemas de Control de Versiones
Una vez que hayamos terminado de trabajar en una rama y la hayamos fusionado con el
código base principal, podemos eliminar la rama sin perder ninguna historia ejecutando:
Esto nos protege ante la pérdida de acceso a una línea de desarrollo completa. Si
realmente queremos eliminar la rama (por ejemplo, si se trata de un experimento fallido),
podemos usar el indicador -D (en mayúscula):
Este comando elimina la rama independientemente de su estado y sin avisos previos, así
que debemos usarla con cuidado.
Los comandos anteriores eliminarán una copia local de la rama pero seguirá existiendo en
el repositorio remoto. Para eliminar una rama remota, ejecuta estos comandos.
git checkout
30
UD 1 Sistemas de Control de Versiones
El comando git checkout nos permite desplazarnos entre las ramas creadas por git branch.
Al ejecutar la operación de cambio de rama, se actualizan los archivos en el directorio de
trabajo para reflejar la versión almacenada en esa rama y se indica a Git que registre todas
las confirmaciones nuevas en esa rama. Podemos pensar en ello como una forma de
seleccionar en qué línea de desarrollo vamos a trabajar.
En ocasiones, el comando git checkout puede confundirse con git clone. La diferencia entre
ambos comandos estriba en que el segundo extrae código de un repositorio remoto,
mientras que el primero cambia entre versiones de código que ya se encuentran en el
sistema local.
El comando git checkout va de la mano de git branch que ya hemos visto. Una vez creada
una rama con git branch, podemos usar git checkout <nombre rama> para cambiar a esa
rama.
El comando git checkout acepta el argumento -b, que actúa como un práctico método que
creará la nueva rama y cambiará a ella al instante.
31
UD 1 Sistemas de Control de Versiones
git merge
La fusión es la forma que tiene Git de volver a unir un historial bifurcado. El comando git
merge permite tomar las líneas independientes de desarrollo creadas por git branch e
integrarlas en una sola rama.
Supongamos que tenemos una rama de funcionalidad nueva que se basa en la rama
master. Ahora, queremos fusionar esa rama de funcionalidad con la master.
Antes de ejecutar una fusión, hay un par de pasos de preparación que llevar a cabo con el
fin de garantizar que la fusión se realice sin problemas.
32
UD 1 Sistemas de Control de Versiones
Una vez adoptados los pasos comentados anteriormente de "preparación para la fusión", es
posible iniciar una fusión mediante la ejecución de git merge <branch name> donde
<branch name> es el nombre de la rama que se fusionará con la rama de recepción.
Si las dos ramas que tratas de fusionar han cambiado la misma parte del mismo archivo, Git
no podrá averiguar qué versión utilizar. Cuando esto ocurre, Git se detiene justo antes de la
confirmación de fusión para que podamos resolver los conflictos manualmente.
La mayor parte del proceso de fusión de Git consiste en utilizar el conocido flujo de trabajo
de edición, preparación y confirmación para resolver los conflictos de fusión. Cuando se
observa un conflicto de fusión, la ejecución del comando git status muestra qué archivos se
deben resolver.
33
UD 1 Sistemas de Control de Versiones
4.8 Etiquetado
Como muchos SCV, Git tiene la posibilidad de etiquetar puntos específicos del historial
como importantes. Esta funcionalidad se usa típicamente para marcar versiones de
lanzamiento (v1.0, por ejemplo).
Listar etiquetas
Listar las etiquetas disponibles en Git es sencillo. Simplemente escribimos git tag:
También podemos buscar etiquetas con un patrón particular. Imaginemos que nuestro
repositorio contiene multitud de etiquetas. Si sólo nos interesa ver las de la versión 1.,
podemos ejecutar:
Crear etiquetas
● Una etiqueta ligera es muy parecida a una rama que no cambia, simplemente es un
puntero a un commit específico.
34
UD 1 Sistemas de Control de Versiones
Para crear una etiqueta ligera, no tenemos que pasar las opciones -a, -s ni -m:
Si una etiqueta coincide con alguno de los commits de nuestro repositorio, podemos verlo
en la salida del comando git log.
Eliminar etiquetas
De igual forma que podemos crear nuevas etiquetas, también podemos eliminarlas. Para
ello, simplemente debemos ejecutar la instrucción:
35
UD 1 Sistemas de Control de Versiones
Etiquetado tardío
36
UD 1 Sistemas de Control de Versiones
Compartir etiquetas
Por defecto, el comando git push no transfiere las etiquetas a los servidores remotos.
Debemos enviar las etiquetas de forma explícita al servidor tras haberlas creado. Este
proceso es similar al de compartir ramas remotas - puedes ejecutar git push origin
[etiqueta].
Si queremos enviar varias etiquetas a la vez, podemos usar la opción --tags del comando git
push. Esto enviará al servidor remoto todas las etiquetas que aún no existen en él.
En Git, no puedes obtener (checkout) directamente el código del repositorio asociado a una
etiqueta (no es algo que podamos mover). Si queremos colocar en nuestro directorio de
trabajo una versión de tu repositorio que coincida con alguna etiqueta, debemos crear una
rama nueva en esa etiqueta:
37
UD 1 Sistemas de Control de Versiones
4.9 Hooks
Igual que ocurre en otros sistemas de versiones, Git dispone de mecanismos que le
permiten ejecutar scripts cuando se producen ciertos eventos. A estos se les suele
denominar hooks (ganchos) y existen de dos tipos: de cliente y de servidor. Mientras los
primeros se ejecutan al producirse operaciones en la parte de nuestro servidor local (por
ejemplo, commit o merge), los ganchos de servidor se ejecutan al producirse cambios en el
servidor remoto (push principalmente). En esta unidad únicamente veremos cómo crear
hooks locales.
Los hooks residen en el directorio .git/hooks/ de cada repositorio de Git. Git crea
automáticamente este directorio con scripts de ejemplo cuando inicializa un repositorio. Si
echamos un vistazo dentro de .git/hooks, encontraremos los siguientes archivos:
Estos representan la mayoría de los hooks disponibles, pero la extensión .sample evita que
se ejecuten de forma predeterminada. Para "instalar" uno, todo lo que tenemos que hacer
es eliminar la extensión .sample. O, si está escribiendo una nueva secuencia de comandos
desde cero, podemos agregar un nuevo archivo que coincida con uno de los nombres de
archivo anteriores, menos la extensión .sample.
38
UD 1 Sistemas de Control de Versiones
Es importante tener en cuenta que los hooks del lado del cliente no se copian cuando se
clona un repositorio
39
UD 1 Sistemas de Control de Versiones
● Los hooks deben ser ejecutables, por lo que es posible que necesitemos cambiar los
permisos de archivo del script en caso es que lo hayamos creado desde cero. Por
ejemplo, para asegurarnos de que prepare-commit-msg sea ejecutable,
ejecutaremos el siguiente comando:
40
UD 1 Sistemas de Control de Versiones
pre-commit
41
UD 1 Sistemas de Control de Versiones
Se ejecuta cada vez que realizamos un commit en git antes de que Git nos pida el mensaje
de confirmación o genere un objeto de confirmación. Podemos utilizar este hook para
inspeccionar el snapshot que está a punto de confirmarse. Por ejemplo, es posible que
queramos ejecutar algunas pruebas automatizadas que se aseguren de que la confirmación
no rompa ninguna funcionalidad existente.
prepare-commit-msg
Este hook (su script asociado) se ejecuta después del anterior hook y, como hemos visto en
el ejemplo inicial, permite mostrarnos el mensaje de commit a añadir a nuestros cambios.
Podemos utilizarlo para modificar estos mensajes a nuestro gusto.
Igual que pasaba con el anterior hook, si devolvemos un valor distinto de cero, asumimos
que se ha producido una condición que anulará el commit.
42
UD 1 Sistemas de Control de Versiones
Hay que tener en cuenta que este hook, en caso de estar activado, nos propondrá el
mensaje de commit configurado aunque nosotros hayamos establecido uno con el
parámetro -m. Eso sí, siempre podremos modificarlo a nuestro gusto antes de realizar el
commit.
commit-msg
Este hook es muy similar al anterior pero se ejecuta tras haber introducido el mensaje de
commit. Es el sitio ideal donde podemos verificar si el mensaje introducido sigue el patrón
deseado que hayamos marcado como válido.
El único argumento que se le pasa a este hook es el nombre del fichero que contiene el
mensaje y, como con el resto, retornando un valor distinto de cero podremos anular el
commit.
43
UD 1 Sistemas de Control de Versiones
post-commit
Este hook se ejecuta tras el hook anterior. No puede anular el mensaje y, por este motivo,
suele utilizarse para realizar notificaciones (por ejemplo, para enviar un email a las personas
implicadas en el proyecto). Este hook no recibe ningún parámetro.
post-checkout
Este hook se ejecutará tras realizar un git checkout sobre nuestro proyecto. Podría ser útil,
por ejemplo, si queremos limpiar nuestro proyecto y realizar una reinstalación tras la acción
de checkout.
pre-rebase
Este hook se ejecutará antes de realizar una operación de rebase. Es ideal si queremos
verificar antes que todo va a seguir funcionando antes de realizarlo.
44
UD 1 Sistemas de Control de Versiones
Mantener hooks para un equipo de desarrolladores puede ser un poco complicado porque el
directorio .git/hooks se clonará con el resto de nuestro proyecto al ser una carpeta que no
está bajo control de versiones. Una solución simple es almacenar nuestros hooks en el
directorio del proyecto real (arriba del directorio .git). Esto nos permitirá editarlos como
cualquier otro archivo controlado por versión. Para instalar el hook, podemos crear un
enlace simbólico a él en .git/hooks, o simplemente lo copiaremos pegaremos en el directorio
.git/hooks siempre que se actualice algún hook.
Desde la versión 2.9 de GIT también podemos guardar nuestros hooks en otro directorio
distinto de .git/hooks (para poder subirlo al repositorio) y mediante la opción de
configuración siguiente podemos especificar a GIT la nueva ubicación de estos.
● Una vez que el repositorio esté en nuestra cuenta, lo clonamos para trabajar
localmente.
● Creamos una rama. Es una buena práctica crear una rama nueva cuando
trabajamos con repositorios, ya sea que se trate de un proyecto pequeño o estemos
contribuyendo en un equipo de trabajo.
45
UD 1 Sistemas de Control de Versiones
El nombre de la rama debe ser breve y debe reflejar el trabajo que estamos
haciendo.
● Realizamos los cambios oportunos en el código de la rama que hemos creado y
hacemos add, commit i push para enviarlos, primero a nuestro repositorio local (add
y commit ) y a la rama del repositorio remoto (push). Algunos proyectos de código
abierto especifican claramente el formato de mensaje de commit que esperan.
● Creamos una pull request. Vamos a nuestro repositorio gitHub y pulsamos en la
opción Pull Request. A continuación, detallaremos todos los cambios realizados y
especificaremos claramente desde qué rama de nuestro proyecto queremos aportar
los cambios y a qué rama del proyecto origen queremos hacerlo.
Antes de enviar cualquier pull request al repositorio original debemos sincronizar nuestro
repositorio local con el remoto de origen ya que pueden haberse agregado algunas
prestaciones o funciones adicionales y haberse corregido algunos errores desde la vez
que realizamos un fork de aquel repositorio. Para ello:
46
UD 1 Sistemas de Control de Versiones
● En este punto nuestra rama local está sincronizada con la rama maestra del
repositorio original. Si deseamos actualizar el repositorio de GitHub, necesitamos
enviar nuestros cambios.
git push origin master
5. GIT WORKFLOWS
Cuando trabajamos en proyectos relativamente grandes formados por diversos
desarrolladores, es interesante disponer de una metodología o forma de trabajar en lo que
al sistema de control de versiones se refiere. A continuación listamos algunos ejemplos de
cómo proceder cuando estamos utilizando Git en un proyecto y debemos trabajar en equipo
y de forma organizada para evitar cualquier posible error.
5.1 GitFlow
Gitflow es un diseño de flujo de trabajo de Git que fue publicado por primera vez y
popularizado por Vincent Driessen en nvie que define un modelo estricto de ramificación
diseñado alrededor de la publicación del proyecto. Es ideal para los proyectos que tienen un
ciclo de publicación programado. Este flujo de trabajo no añade ningún concepto ni
comando nuevos más allá de lo que se necesita para el flujo de trabajo de rama de función.
En su lugar, asigna funciones muy específicas a las diferentes ramas y define cómo y
cuándo deben interactuar.
47
UD 1 Sistemas de Control de Versiones
Funcionamiento
En vez de una única rama maestra, este flujo de trabajo utiliza dos tipos de ramas para
registrar el historial del proyecto:
En este esquema hay dos ramas principales con un tiempo de vida indefinido:
Para labores concretas, pueden usarse otro tipo de ramas, las cuales tienen un tiempo de
vida definido. Es decir, cuando ya no son necesarias se eliminan:
48
UD 1 Sistemas de Control de Versiones
49
UD 1 Sistemas de Control de Versiones
Instalación y configuración
Para poder empezar a trabajar con la extensión de Git Git-Flow, será necesario instalar
ésta. Para ello, simplemente tenemos que ejecutar la siguiente instrucción:
Una vez instalado, si nos encontramos en un proyecto nuevo en el que queremos utilizar
git-flow, ejecutaremos:
git-flow-init
No branches exist yet. Base branches must be created now.
50
UD 1 Sistemas de Control de Versiones
Al ejecutar el último comando, entramos en un menú interactivo que nos va preguntando las
opciones que aparecen arriba:
A partir de aquí, se nos habrán creado las dos ramas principales (master y develop) en
nuestro repositorio y podremos implementar nuevas releases, features y hotfix con unos
simples comandos sin necesidad de preocuparnos por la creación y merge de las ramas
necesarias para ello.
gitflow git
INICIALIZACIÓN
FEATURES
51
UD 1 Sistemas de Control de Versiones
RELEASES
HOTFIX
52
UD 1 Sistemas de Control de Versiones
Ventajas
● Útil y amigable con las actuales herramientas de CI/CC.
● Recomendado para features de duración corta (diarias o incluso de horas).
● Flujo ligero y recomendado si el proyecto requiere de una entrega de valor
constante.
Inconvenientes
● Inestabilidad de master si no se utilizan las herramientas de testing/PR
correctamente.
53
UD 1 Sistemas de Control de Versiones
GitLab Flow es una alternativa/extensión de GitHub Flow y Git Flow, que nace debido a las
carencias que adoptan estos dos flujos. Mientras que una de las consignas de GitHub es
que todo lo que haya en master es desplegado, hay ciertos casos en los que no es posible
cumplirlo o no se necesita. Por ejemplo: aplicaciones iOS cuando pasan a la App Store
Validation o incluso tener ventanas de despliegue por la naturaleza del cliente.
El flujo propone utilizar master, ramas features y ramas de entorno. Una vez que una feature
está finalizada hacemos una merge request contra master. Una vez que master tiene varias
features, llevamos a cabo una merge request a preproducción con el conjunto de features
anteriores, que a su vez, son candidatas de pasar a producción haciendo otro merge
request. De esta manera conseguimos que el código subido a producción sea muy estable,
ya que validamos featues tanto a nivel individual como en lote.
La naturaleza de este flujo no requiere generar ramas de releases, ya que cada entorno
será desplegado con cada merge request aceptada.
Ventajas
54
UD 1 Sistemas de Control de Versiones
Inconvenientes
● Requiere de un equipo que valide las MR tanto de las features, como de los
diferentes entornos.
● Tiempo demasiado alto para la entrega de valor. Desde que se crea y se valida la
feature, hasta que llega a producción, tiene que pasar por muchas validaciones.
● Más complejo que GitHub Flow.
Este flujo es muy similar a GitHub Flow, con la característica nueva de las releases branch y
el cambio de filosofía que presenta. Los principios que rigen este flujo son los siguientes:
Ventajas
● Muy útil si nuestro proyecto necesita iterar rápido y entregar valor lo antes posible.
● Responde muy bien a proyectos agile pequeños.
● Preparado para equipos que utilizan pair-programming.
● Funciona muy bien con un equipo experimentado y cerrado.
Inconvenientes
● Debemos ser responsables de nuestro código y hacer el esfuerzo de subir código de
calidad.
55
UD 1 Sistemas de Control de Versiones
El flujo de trabajo usa solo una rama infinita. Usaremos master en esta descripción, ya
que probablemente sea el nombre más común y ya es una convención de Git, pero también
puedes usar, por ejemplo, current, default, mainline, ...
Realizaremos cada feature o hotfix sobre la misma rama, testearemos y haremos commit
en local. Una vez que este cambio se ha aprobado, haremos push contra master en origin,
desplegándose en producción inmediatamente.
Debemos usar features-flags para poder integrar el código en la rama master y evitar
conflictos a lo largo del tiempo.
Ventajas
Inconvenientes
● No soporta múltiples entornos productivos.
● Requiere de desarrolladores experimentados para no dejar inestable la rama
principal.
● El proyecto requiere de guidelines de código muy estrictas.
56
UD 1 Sistemas de Control de Versiones
6. GITHUB PAGES
GitHub nos brinda herramientas muy útiles para el trabajo en equipo. Una de esas es Github
Pages, la cual permite alojar sitios web estáticos sin necesidad de tener conocimientos en
servidores. GitHub pages permite dos modalidades de publicación:
● La primera es “User site” (solo se podrá tener un sitio de este tipo por cuenta); en
este caso el sitio web será publicado en username.github.io (siendo username el
nombre de usuario de la cuenta).
● La segunda opción es “Project site” (proyectos ilimitados) el cual será publicado en
username.github.io/repository (siendo repository el nombre del repositorio).
Una vez tengamos nuestro repositorio, el siguiente paso consistirá en subir los ficheros que
vayan a ser utilizados en nuestro site. Estos, pueden ser tanto ficheros html normales como
ficheros en formato .md (pero no combinar ambos tipos para evitar problemas). Además,
dichos ficheros podrán residir en la rama principal (master) o en una rama específica
dedicada únicamente a alojar la documentación o site de nuestro proyecto (suele utilizarse
en este caso una rama denominada gh-pages).
Tras crear nuestro repositorio y disponer en él de todos los archivos del site subidos,
deberemos proceder a habilitar github Pages en nuestro almacén de código. Para ello, nos
dirigiremos a la sección de setting de este y marcaremos el check de la sección de gitHub
pages. Además:
57
UD 1 Sistemas de Control de Versiones
● Mensajes de commit
Deben ser simples y claros. Es aconsejable tener en cuenta:
○ Separar el asunto del cuerpo del mensaje por una línea en blanco.
○ El asunto no debe superar los 50 caracteres, debe iniciarse con letra
mayúscula y no finalizar con punto. Se debe usar la forma imperativa en su
redacción.
○ El cuerpo del mensaje es aconsejable que tenga líneas con un ancho de no
más de 72 caracteres para facilitar la lectura de este.
○ Utilizar el cuerpo del mensaje para explicar qué se ha resuelto y cómo.
● Añadir solo los archivos con los que hemos trabajado
○ Usar git add . no es la mejor práctica. Lo mejor en estos casos es añadir solo
los archivos en los que hayamos estado trabajando, esto evita que se
añadan muchos archivos “trash” que pueden traer una repercusión grave en
la dimensión del repositorio.
○ En su lugar, es conveniente añadir los ficheros individualmente (git add
documento.txt).
58
UD 1 Sistemas de Control de Versiones
7. BIBLIOGRAFÍA
59