Introducción a sistemas de control de versión distribuidos

Hugo O. Barrera <hugo@whynothugo.nl>

UNPSJB, Oct. 2024

Contenidos

Parte 1:

  • Sistemas de control de versión distribuidos.
  • Git: conceptos y uso básico.

Parte 2:

  • Compartir cambios con git.
  • Forjas y platforms de colaboración.
  • Code Review.

Sistemas de control de versión

Control de versión ("version control"), también llamado:

  • control de revisión ("revision control")
  • control de fuentes ("source control")
  • gestión de código fuente ("source code management")

Sistemas de control de versión

Almacena versiones del mismo código a lo largo del tiempo.

Sistemas de control de versión

Permite:

  • Ver versiones anteriores del código.
  • Comparar diferencias entre versiones.
  • Revertir cambios.
  • Aplicar cambios de distintas fuentes.

Ejemplos

  • Wikipedia
  • Procesadores de texto
  • Hojas de cálculo
  • Editores colaborativos online

Sistemas de control de versión centralizados

  • Servidor central.
  • Un único punto de falla.
  • Requieren conectividad para ser usados.

Ejemplos

  • Wikipedia
  • SVN ("Apache Subversion")
  • CVS ("Concurrent Versions System")
  • Google Docs

Sistemas distribuidos

  • Ubicado en distintas computadoras.
  • No hay un servidor central.
  • Requieren coordinación entre participantes.

Sistemas de control de versión distribuidos

  • Cada desarrollador tiene una copia completa de todo:
    • Del código
    • Del historial de cambio.
  • Permite trabajar offline (incluyendo consultar historial).
  • Operaciones más rápidas (no necesita conectarse a un servidor)
  • No hay un único punto de fallas.
  • Backups implícitos.

Sistemas de control de versión distribuidos

Ejemplos

  • GNU Bazaar, bzr
  • git
  • Mercurial, hg
  • got
  • jujutsu, jj

git

git es un sistema de control de versión distribuido.

  • Creado para desarrollar Linux.
  • Enfocado en rapidez e integridad de datos.
  • Escala a miles de desarrolladores trabajando en paralelo.
  • El modelo no depende de ningún servidor.
  • Software libre y de código abierto (GPL-2.0-only).

git

Git no guarda archivos, guarda cambios.

Patches

patch es un formato para representar cambios:

diff --git a/demo.md b/demo.md
index e440d87..ebc8717 100644
--- a/demo.md
+++ b/demo.md
@@ -1,6 +1,6 @@
 # git

-**git** es un sistema de control de versión distirbuido.
+**git** es un sistema de control de versión distribuido.

 - Creado para desarrollar Linux.
 - Enfocado en rapidez e integridad de datos.

Git no elimina archivos

diff --git a/demo.md b/demo.md
deleted file mode 100644
index ebc8717..0000000
--- a/demo.md
+++ /dev/null
@@ -1,8 +0,0 @@
-# git
-
-**git** es un sistema de control de versión distribuido.
-
-- Creado para desarrollar Linux.
-- Enfocado en rapidez e integridad de datos.
-- Escala a miles de desarrolladores trabajando en paralelo.
-- El modelo no depende de ningún servidor.

Git no elimina archivos

No es ideal para archivos binarios grandes.

Ver: git-annex.

Repositorios

  • Directorio donde se guardan archivos y se rastrea sus cambios a lo largo del
    tiempo.
  • Tiene un subdirectorio .git, que contiene todo el historial de cambios y
    otros metadatos.

Flujo de trabajo básico

  • Inicializar repositorio.
  • Escribir código.
  • Preparar cambios (git add)
  • "Commitear" cambios (git commit).
  • Modificar código.
  • Preparar cambios (git add)
  • "Commitear" cambios (git commit).
  • ...

Los primeros dos pasos pueden intercambiarse en orden.

Flujo básico: Inicializar repositorio

Inicializar directorio actual:

git init

Inicializar otro directorio:

git init path/a/un/directorio/

En IDEs, editores o TortoiseGit:

Git Create Repository here

Flujo básico: Preparar cambios

  • Agregar cambios para la siguiente versión.
  • Equivalent a SQL INSERT o UPDATE dentro de una transacción.

Flujo básico: Preparar cambios

> git add -p
diff --git a/demo.md b/demo.md
index e440d87..ebc8717 100644
--- a/demo.md
+++ b/demo.md
@@ -1,6 +1,6 @@
 # git

-**git** es un sistema de control de versión distirbuido.
+**git** es un sistema de control de versión distribuido.

 - Creado para desarrollar Linux.
 - Enfocado en rapidez e integridad de datos.
(1/1) Stage this hunk [y,n,q,a,d,e,p,?]?

Flujo básico: Preparar cambios

git reset deshace todos los git add.

Flujo básico: Commitear cambios (git commit).

  • Crea un nuevo "commit"; una nueva versión.
  • "Guarda" esta versión en el historial de cambios.
  • Equivalente a SQL COMMIT.
  • Incluye un mensaje descriptivo.

Un "commit"

  • Una versión del código.
  • Cada commit tiene un o más commits ancestros.

Un "commit"

  • El identificador es un hash (SHA-256), e.g.:
    af7b396becf4416d5bcadf60dacf18752e2daeba
  • Típicamente se usan 7-8 dígitos, e.g.: af7b396
  • Es el hash del contenido del commit junto con el hash de los commits
    ancestros.
  • Integridad de los datos es una característica de primera clase.
  • Los números secuenciales no sirven en sistemas distribuidos.

Clonar un repositorio

  • git clone permite clonar un repositorio existente.
  • Usa otros protocolos como transporte:
    • ssh: seguro, el más común.
    • https://: menos eficiente, generalmente sólo lectura.
    • git://: inseguro, sin autenticación.
    • file://: sólo funciona localmente.
    • ...

Remotos ("remotes")

  • Un remoto es la ubicación de otra copia del repositorio.
  • Al clonar un repositorio, la copia nueva tiene un remoto origin.
    • origin apunta a la ubicación de donde se clonó el repositorio.
  • Información sobre remotos se guardan dentro de .git.
  • Un repositorio puede tener cero, uno o más remotos.

Push y Pull

  • git push: empuja (manda) commits a un remoto.
  • git pull: trae commits de un remoto.

Por defecto, ambas operaciones interactúan con el remoto origin.

Actividad 1

  • Clonar el repositorio https://git.sr.ht/~whynothugo/breadscript.
  • Corregir los errores de ortografía en el archivo pan.md.
  • Commitear los cambios.

Configuración básica

git config --global user.name "Hugo Osvaldo Barrera"
git config --global user.email "hugo@whynothugo.nl"
git config --global color.ui true

Actividad 1.1

  • ¿Qué hace git show?

Actividad 1.2

  • ¿Qué hace git log?
  • ¿Y git log -p?

Actividad 1.3

  • ¿Qué hace git blame pan.md?

Actividad 1.3

  • Comparen commits entre participantes.

Divergencia

  • Juan crea un repositorio con 3 commits y lo publica.
  • María clona el repositorio y crea un cuarto commit.
  • Carlos clona el repositorio original, y crea otro cuarto commit.

Los commits de María y Carlos tienen los mismos ancestros, pero distinto hash.

Los números secuenciales no sirven en sistemas distribuidos.

Divergencia local: branches

  • Branches ("ramas") permiten trabajar en varias lineas de historia paralelas.
  • El branch predeterminado es main/master.
  • Hay un branch activo a la vez (git branch --show-current).
    • HEAD es una alias para "branch activo".
  • Permiten trabajar en distintas funcionalidades en paralelo.
  • Permite experimental sin afectar el branch main.
  • Son la base para colaboración en equipo.

Branches

  • Un branch es un puntero a un commit.
  • El archivo .git/refs/heads/main que contiene el id del commit.

Branches

  • Crear y activar un branch nuevo: git checkout -b mi_branch_nuevo.
  • Activar un branch existente: git checkout main
  • En caso de conflictos, aborta la operación.

Branches remotos

Son branches que existen en un remoto.

Branches remotos

  • Los branches remotos son visible con git branch -a.
  • Tienen el formato de origin/main (o remotes/origin/main).
  • git fetch trae nuevos commits y branches remotos sin modificar el branch
    activo.

Convergencia: unir dos branches

Dos mecanismos para conciliar dos branches:

  • Merge ("unir").
  • Rebase ("volver a base").

Merge ("unir")

  • Crea un commit con dos ancestros.
  • Es el mecanismo más sencillo.
  • El historial de versiones resultante es no-lineal.

Merge ("unir")

  • git merge OTRO_BRANCH crea un nuevo commit en el branch actual.
  • Une al branch actual con OTRO_BRANCH.
  • OTRO_BRANCH permanece intacto.
  • El nuevo commit tiene dos ancestros.
  • Si hay conflictos, deben ser resueltos a mano.

Rebase ("volver a base")

  • Re-escribe commits, cambiando su ancestro.
  • Es más complejo en caso de muchos commits o muchos conflictos.
  • El historial de versiones resultantes es lineal.

Rebase ("volver a base")

  • git rebase OTRO_BRANCH re-escribe la historia del branch actual.
  • Usa como base los commits presentes en OTRO_BRANCH.
  • Agrega los commits que sólo están presentes en el branch actual.
  • Re-escribe la historia de estos commits para que sean lineares usando
    OTRO_BRANCH como base.
  • OTRO_BRANCH permanece intacto.
  • Si hay conflictos, deben ser resueltos a mano.
    • Pueden haber conflictos en cada commit re-escrito.

Actividad 2

  • Usando el repositorio clonado...
  • Unir los cambios del branch origin/agua-tibia.

Actividad 2.1

  • ¿Qué hace git log --graph?

Conflictos

Dos branches divergentes modifican la misma línea (o líneas cercanas).

Resolución de conflictos

  • Merge require resolver conflictos una sola vez.
  • Rebase require resolver conflictos por cada commit re-escrito que tenga
    conflictos.

Merge tiende a ser más fácil.

Actividad 3

  • Usando el repositorio clonado...
  • Unir el branch origin/azucar.

Tags

  • Puntero a un commit específico.
  • Opcionalmente, puede tener una firma digital.
  • Típicamente: releases.

Tags

git tag v1.0.0
git push origin v1.0.0 # empuja sólo un tag
git push --tags # empuja todos los tags
git fetch --tags # trae todos los tags

Preguntas

Tarea

https://codeberg.org/

Random names

Juan

María

Carlos

Sofía

Ejemplos

- Email

- Extra space at the beginning of unaltered lines. - Some tools highlight changed words. - Trivia: diff: June 1974, unified diff: January 1990.

- Nada es agregado implícitamente.

TODO: best practices for messages. passive voice explains WHAT it does, not HOW

TODO: leave visible commands here

Code editors allow surfacing blame info easily

TODO: it would be IDEAL to have a tree graph here!

- Al crear un nuevo commit en el branch actual, se actualiza el branch. - Se puede modificar un branch para que apunte a un nuevo commit -> rewrite history

TODO: example of what this looks like

TODO: do they need git-fetch here?

TODO: este branch cambia sólo la primera línea, sin conflicto con el ejercicio anterior.

TODO: this branch needs to branch from `main`, and conflicts due to the changes in `agua-tibia`.

TODO: git reset --hard was useful for going back when students make a mistake, perhaps it should be explained to?

TODO: git rev-list --count HEAD

TODO: git commit --amend

TODO: rebase -i ?