De Git a Fossil
Hace un tiempo que en Git han empezado a trabajar en una propuesta para hacer obligatorio el lenguaje de programación Rust1. A mi no me gusta Rust y, sobre todo, no me gusta su comunidad de personajillos extremistas que pretenden hacer tragar a todo el mundo su basura reescribiendo proyectos que llevan décadas funcionando, haciendo campañas de acoso y derribo en redes sociales y otras lindezas dignas de cualquier grupúsculo con Ãnfulas totalitarias. Por eso cuando veo que un proyecto pretende "obligar" el uso de o migrar de C a Rust, en la medida de mis posibilidades, huyo de él como si me persiguiera el Balrog del Señor de los Anillos con su látigo de fuego.
A lo largo de mis años he conocido y usado (o probado) muchos sistemas de control de versiones: RCS (Revision Control System), CVS (Concurrent Version System), SVN (Subversion), HG (Mercurial), BZR (Bazaar) y el susodicho Git, lo que significa que no tengo mayor problema en volver a cambiar asà que empecé a buscar un sustituto para mis proyectos personales.
Las opciones eran volver a uno de los ya conocidos o mirar otra cosa y me acordé de Fossil. Empecé echando un vistazo por encima al código fuente y a leerme la documentación oficial2 para enterarme de lo que ofrecÃa, de sus dependencias, de cómo se instalaba y configuraba, etc., y và que tenÃa muchas cosas que me gustan:
- Está hecho en C (aunque utiliza algo de js y de tcl para su funcionalidad web) y es un programa pequeño y eficiente que consume pocos recursos de hardware.
- Su uso es más sencillo y natural (por lo menos para alguien que conoce otros sistemas como Subversion) ya que no contiene funcionalidades rebuscadas como el staging area de Git, que puede que sean útiles en proyectos grandes y complejos como el kernel Linux pero que para mà no tienen ninguna utilidad práctica.
- Permite autoalojar un servidor en tu propia infraestructura de forma rápida y sencilla porque ya viene preparado para ello. De hecho ya tiene integrado un servidor y un sistema web con las vistas del control de versiones, wiki, sistema de tickets, etc. Sin embargo con Git hay que recurrir a soluciones externas como GitLab, Gitea o Forgejo y cada una de ellas es como mÃnimo una nueva dependencia.
- No utiliza direcciones de correo en los commits sino que utiliza nombres de usuario por lo que si tu repositorio es público te evitas el que tu correo caiga en manos de las redes de spam o el tener que usar una dirección de correo especÃfica para este tipo de cosas.
- Es interoperable con Git en el sentido de que si surge la necesidad de volver a cambiar un repositorio a Git se puede hacer e incluso soporta la sincronización bidireccional entre un repositorio Fossil y uno Git3 (que es lo que usan Fossil y el proyecto Sqlite para mantener sus repositorios espejo en GitHub).
Teniendo en cuenta todo esto decidà instalarlo y migrar mis proyectos de Git a Fossil. A continuación vamos a ir viendo cómo hacer eso mismo.
Instalación de Fossil
El primer paso es instalar Fossil y es más que probable que ya se encuentre entre los paquetes de tu sistema operativo:
sudo apt install fossil # Devuan GNU+Linux
pkg install fossil # FreeBSD
Tras ejecutar la instalación podemos comprobar que efectivamente se ha instalado ejecutando en terminal el siguiente comando:
fossil version
Ese comando devolverá algo como lo siguiente:
This is fossil version 2.21 [3c53b6364e] 2023-02-26 19:24:24 UTC
Importación de repositorios Git
En la documentación4 de Fossil nos ponen como ejemplo para exportar de Git e importar en Fossil el siguiente comando con una tuberÃa:
cd nombre_de_repo
git fast-export --all | fossil import --git nombre_de_repo.fossil
Sin embargo yo lo hice de otro modo para poder ajustar algunas cosas y dejar los nuevos repositorios importados "bien". Como tenÃa varios repositorios creé dos carpetas distintas, una, git-exported, para almacenar los repositorios exportados y otra, fossils, para almacenar los nuevos repositorios.
mkdir ~/git-exported
mkdir ~/fossils
Ahora ya podemos empezar a exportar nuestros repositorios de Git:
cd nombre_de_repo
git fast-export --all > ~/git-exported/nombre_de_repo.export
Una vez que ya tenemos exportados todos los repositorios de Git nos vamos a la carpeta ~/fossils y los importamos con el comando:
fossil import --git \
--rename-master trunk \
--attribute "tu@correo.es tu_usuario" \
nombre_de_repo.fossil ~/git-exported/nombre_de_repo.export
La opción --rename-master trunk renombra la rama master de Git como trunk
en Fossil ya que Fossil, al igual que otros programas de control de versiones
como Subversion, utiliza el nombre trunk para indicar la rama maestra. Si eres
de los desafortunados que en lugar de "master" tienen su rama principal nombrada
como "main" esta opción no es para tà y tendrás que consultar la documentación
de Fossil si quieres renombrarla.
La opción --attribute "tu@correo.es tu_usuario" cambia la dirección de correo
tu@correo.es en los commits de Git por el nombre de usuario tu_usuario,
que en Fossil por defecto coincide con tu nombre de usuario del sistema.
Lógicamente la dirección indicada debe existir en algún commit de Git.
Si quieres cambiar más de una dirección de correo puedes hacerlo utilizando
varias opciones --atribute:
cd ~/fossils/
fossil import --git \
--rename-master trunk \
--attribute "tu@correo.es tu_usuario" \
--attribute "rms@gnu.org rms" \
--attribute "linus@kernel.org torvalds" \
nombre_de_repo.fossil ~/git-exported/nombre_de_repo.export
La salida del comando de importación del repositorio será algo como:
Rebuilding repository meta-data...
100.0% complete...
Vacuuming... ok
project-id: e64b112b40eb3db188060ddb8deeaa96a6ad3b71
server-id: bfbcd4bf8f0f64eaa2d832ddc3b4af00639624a6
admin-user: tu_usuario (password is "XAxPVZcNQ6")
Si te fijas, cada vez que importas un repositorio te da la contraseña de tu usuario administrador. Guárdala ya que la necesitarás para realizar determinadas operaciones con tu repositorio.
Servidor Fossil
Fossil tiene un servidor web embebido asà que lo podemos aprovechar para crear un servidor autoalojado de forma rápida y sencilla. El método que expongo a continuación es suficiente para un sistema con pocos usuarios, en una red privada que no se puede acceder desde el exterior. Hay diferentes formas de configurar un servidor Fossil y algunas son mejores que otras dependiendo de las necesidades, por lo que te recomiendo revisar la documentación oficial.
Primero creamos una carpeta donde se guardarán todos los repositorios *.fossil en el servidor:
mkdir /ruta/a/mis/fossils
Luego copiamos nuestros repositorios fossil a dicha carpeta en el servidor:
scp *.fossil usuario@mi_server:/ruta/a/mis/fossils/
Ahora arrancamos el servidor Fossil de la siguiente manera:
fossil server --port 8043 \
--cert /ruta/a/mi_certificado.pem \
--pkey /ruta/a/la/clave/del/certificado.pem \
--repolist /ruta/a/mis/fossils/
Si no tienes un certificado válido puedes arrancarlo con:
fossil server --port 8043 \
--cert unsafe-builtin
--repolist /ruta/a/mis/fossils/
Una vez arrancado el servidor, si pones la url https://dirección_de_servidor:8043/
en tu navegador deberÃas de poder acceder a una página con el listado de tus repositorios.
Pinchando en cada uno de ellos te llevará a la página del repositorio en cuestión y, una
vez en la página del repositorio, si te fijas en el menú de navegación hay una opción login.
Si pinchas en esa opción y pones tu nombre de usuario y la contraseña que te devolvió el
comando fossil import accederás como administrador y podrás configurar el espacio del
proyecto a tu gusto. Para saber más consulta la documentación oficial de Fossil.
Si no apuntaste o has perdido la contraseña de tu repositorio Fossil la podrás recuperar con los siguientes pasos:
- Entra en el servidor y dirÃgete a la carpeta dónde están tus repositorios fossil.
- Si no tienes instalado el programa sqlite, instálalo siguiendo el método habitual de tu sistema operativo.
Abre el archivo mi_repo.fossil con sqlite:
sqlite3 mi_repo.fossil
Una vez dentro de sqlite haz la siguiente consulta:
select login,pw from user;
Esta consulta te devolverá algo como:
tu_usuario|My3w2jRxt1 anonymous|57EBCBD1AAE663B4 nobody| developer| reader|
La contraseña es el segundo elemento de la fila (en este ejemplo la cadena My3w2jRxt1).
- Sal de sqlite3 tecleando
.quit.
Usando Fossil
A continuación pongo una guÃa muy breve sobre cómo dar unos primeros pasos con Fossil. Esta guÃa presupone que sabes usar Git, de forma muy básica, y es solo un punto de partida por lo que te recomiendo que leas la documentación de Fossil y su manual5.
Obteniendo ayuda
El comando de ayuda es imprescindible para ver qué comandos ofrece Fossil y para ver los usos y opciones de cada uno de estos comandos. La ayuda funciona igual que en Git:
fossil --help
fossil nombre_de_comando --help
Creando y clonando repositorios
Estos procesos son parecidos a los de Git pero no del todo. En Git lo habitual es que el repositorio de trabajo coincida con la carpeta de trabajo. En Fossil esto no es asÃ, hay una clara diferencia entre el archivo del repositorio nombre_de_repo.fossil y la carpeta de trabajo nombre_de_repo.
Creando un nuevo repositorio
Creamos un nuevo repositorio con el comando:
fossil init nombre_de_repo.fossil
Este comando creará solamente el repositorio, esto es, el archivo nombre_de_repo.fossil. Para empezar a trabajar con él tenemos que "abrirlo" por lo que crearemos la carpeta de trabajo y abriremos el repositorio en ella:
mkdir mi_carpeta_de_trabajo
cd mi_carpeta_de_trabajo
fossil open /ruta/a/nombre_de_repo.fossil
También podemos indicarle a Fossil el nombre de la carpeta de trabajo y si esta no existe Fossil intentará crearla:
fossil open --workdir mi_carpeta_de_trabajo /ruta/a/nombre_de_repo.fossil
Clonando un repositorio
Clonamos un repositorio utilizando el comando fossil clone seguido de la url
del repositorio. La url puede ser una url web, una url ssh, una ruta en un sistema
de archivos, etc.:
fossil clone https://host/nombre_de_repositorio
Este comando descargará automáticamente el achivo nombre_de_repo.fossil y creará, al mismo nivel, la carpeta de trabajo nombre_de_repo. Si no queremos que cree la carpeta de trabajo ejecutamos el comando como:
fossil clone --no-open https://host/nombre_de_repositorio
Una vez clonado el repositorio, si tienes permisos para ello y tu intención
es enviar tus commits al repositorio remoto, necesitarás configurarlo en la carpeta
de trabajo con el comando fossil remote:
fossil remote https://usuario@dominio/nombre_de_repositorio
Este comando nos pedirá la contraseña de nuestro usuario y nos ofrecerá la posibilidad de guardarla para usarla en el futuro.
Consejo: Teniendo en cuenta la peculiaridad de Fossil de tener un archivo de repositorio por un lado y las carpetas de trabajo por otro yo lo tengo organizado tal que en mi /home tengo una carpeta fossils donde guardo todos los repositorios y luego tengo las carpetas de trabajo en el lugar más adecuado en cada caso.
Obteniendo información
A la hora de obtener información sobre el estado del repositorio y de nuestra carpeta hay ciertas diferencias con respecto a Git, sobre todo en el nombre y uso de los comandos.
Viendo el histórico
En Fossil los comandos fossil time y fossil timeline son los equivalentes
del comando git log de Git. A continuación pongo ejemplos ordenados desde el
que proporciona menos información al que proporciona más:
fossil time --oneline # similar a git log --oneline
fossil time
fossil time --medium
fossil time --verbose # similar a git log
Viendo los cambios en nuestra carpeta de trabajo
Para ver los cambios en nuestra carpeta de trabajo con respecto del repositorio hay varios comandos y cada uno de ellos tiene distintas opciones.
Para ver los archivos y carpetas que no están bajo control de versiones usamos:
fossil extras
Para ver los archivos que están bajo control de versiones y que han sufrido cambios:
fossil changes
Para ver una combinación de los dos anteriores usarÃamos el comando:
fossil changes --differ
Para ver el estado del repositorio estilo a cómo lo verÃamos en Git con el comando git status usarÃamos el comando:
fossil status --differ
Viendo las diferencias
Para ver las diferencias entre los contenidos de nuestros archivos en la carpeta de trabajo y lo que hay en el repositorio utilizamos, al igual que en Git, el comando diff:
fossil diff
Para ver las diferencias entre un commit especÃfico y la carpeta de trabajo:
fossil diff --from 2c26dd6b69 # 2c26dd6b69 es el hashtag del commit
Para ver las diferencias entre dos commits concretos:
fossil diff --from 2c26dd6b69 --to cd086a1045
El comando diff de Fossil no muestra los diffs en color. Si quieres esta caracterÃstica echa un vistazo a la Wiki de Fossil6
Obteniendo los cambios de los demás
Fossil tiene una opción llamada autosync que viene activada por defecto. Esta opción mantiene sincronizado nuestro repositorio local con el repositorio remoto. Si tenemos activada la opción autosync podemos obtener todos los cambios del repositorio remoto (si lo hubiera) con el comando:
fossil update
En caso contrario la dinámica serÃa más parecida a la de Git. TendrÃamos que hacer primero un pull para obtener los cambios y luego un update para que estos aparecieran en nuestra carpeta de trabajo:
fossil pull
fossil update
Versionando nuestros cambios
Como Fossil no tiene staging area, el comado commit se parece mucho más al de sistemas de control de versiones como Subversion que al de Git.
Si queremos hacer un commit con todos los cambios pendientes:
fossil commit
Este comando ejecutado de esta manera mostrará un editor para que podamos introducir el mensaje del commit. Sin embargo podemos pasarle el mensaje directamente si lo ejecutamos tal que asÃ:
fossil commit -m "Mi mensaje de commit"
Podemos hacer un commit con solo determinados archivos especÃficos:
fossil commit archivo1 archivo2
fossil commit archivo1 archivo2 -m "Mi mensaje de commit"
Si tenemos activada la opción autosync el comando commit enviará nuestros cambios también al servidor remoto (si lo hubiera). En caso contrario tendremos que enviar los cambios al servidor remoto con el comando:
fossil push
Añadiendo y borrando archivos
Cuando tenemos archivos nuevos que añadir al control de versiones utilizamos el comando:
fossil add nombre_de_arhivo
Para borrar archivos del control de versiones utilizamos cualquiera de los siguientes dos comandos:
fossil delete nombre_de_archivo
fossil rm nombre_de_archivo
Por defecto los comandos de borrado no borran el archivo fÃsicamente del disco sino que simplemente lo marcan para indicar que ya no se encuentra bajo control de versiones.
También existe un comando fossil addremove que añade al control de versiones todos los
archivos que están en la carpeta de trabajo pero que no están bajo control de versiones y
"borra" del control de versiones todos los archivos que están bajo control de versiones pero
que ya no se encuentran en la carpeta de trabajo.
Ignorando archivos
La configuración es uno de los puntos donde hay varias diferencias importantes entre Git
y Fossil por lo que te recomiendo revisar la documentación. Para ignorar archivos tenemos
que crear en la carpeta de trabajo el archivo .fossil-settings/ignore-glob
cd mi_carpeta_de_trabajo
mkdir .fossil-settings
touch .fossil-settings/ignore-glob
Luego editamos los contenidos del archivo y podemos usar patrones7:
build/
3rdparty/
*.o
*/a.out
Ramas y etiquetas
El paradigma de Git hace mucho hincapié en el uso intensivo de ramas y también de las etiquetas. Sin embargo Fossil tiene unas caracterÃsticas y un paradigma diferente, más clásico podrÃamos decir, por lo que los flujos de trabajo son distintos a los de Git.
Como no hago mucho uso de las ramas en mis proyectos personales, creo que para que te hagas una idea de las diferencias y asà poder adaptar las caracterÃsticas de Fossil a tu flujo de trabajo, o viceversa, lo mejor es que leas los siguientes enlaces de la Wiki de Fossil:
Interfaz web en local
No quiero terminar esta pequeña guÃa de Fossil sin dejar claro que se puede acceder y usar el interfaz web sin tener Fossil en modo servidor. Para ello solamente hay que ejecutar, desde dentro de la carpeta de trabajo, el comando:
fossil ui
Conclusión
Fossil me ha gustado mucho y, en mi opinión, es una mezcla casi perfecta entre un sistema de control de versiones centralizado como Subversion y uno distribuido como Git. Me gusta la simplicidad para ponerlo en modo servidor, su interfaz web y, sobre todo, la sencillez de sus comandos y de las tareas más habituales.
Creo que es un pequeño gran programa que tiene muchÃsimo que ofrecer, sobre todo a programadores independientes y pequeños grupos que están interesados en sistemas autoalojados ya que como se ha visto es muy fácil de poner en marcha. Si buscas una alternativa sencilla y eficaz a Git no dudes en echarle un vistazo porque puede que Fossil sea exactamente lo que andas buscando.