Módulo 12: Laboratorio — Git interno e IA

Unidad: GIT-14
Capa: laboratorio avanzado opcional
Público: alumnado de DAW, DAM, ASIR y grados de informática con experiencia básica colaborando con Git.
Itinerario y dependencias: posterior a fundamentos, ramas, remotos, recuperación y prácticas de colaboración. El uso de git worktree es una ampliación opcional (módulo 10).
Nivel: avanzado.
Encaje curricular: contenido transversal; no se asigna a un módulo concreto sin verificar la programación del centro.
Duración: 3 horas, dos laboratorios de 90 minutos.
Fuentes técnicas: documentación oficial de Git: modelo y comandos de bajo nivel, objetos con git cat-file, almacenamiento del repositorio y worktrees.

Laboratorio A — Qué guarda Git realmente

Objetivo observable

Identificar blobs, trees, commits y referencias en un repositorio pequeño, relacionándolos con el directorio de trabajo, el área de preparación y el historial local.

Prerrequisitos

Uso seguro de init, add, commit, status, log y ramas.

Explicación

Git no guarda «versiones completas de carpetas» como una copia manual. Guarda objetos identificados por un hash de su contenido:

  • Un blob es el contenido de un archivo. No guarda su nombre.
  • Un tree es una carpeta: nombres, modos y los objetos que contiene.
  • Un commit apunta a un tree y almacena autoría, fecha, mensaje y, salvo el primero, el commit padre.
  • Una referencia como main apunta al commit más reciente. HEAD apunta normalmente de forma simbólica a esa rama.

El área de preparación o index es la propuesta concreta con la que Git construirá el siguiente tree. Por eso git add todavía no confirma nada.

Demostración práctica

mkdir lab-git-interno
cd lab-git-interno
git init -b main
git config user.name "Alumno Git"
git config user.email "alumno@example.test"

printf "hola\n" > saludo.txt
git hash-object -w saludo.txt
5c1b14949828006ed75a3e8858957f86a2f7e2eb

Con -w, Git calcula el blob y lo almacena en su base de objetos. Todavía no hay commit y el archivo ni siquiera está preparado:

git status --short
git cat-file -t 5c1b1494
git cat-file -p 5c1b1494
find .git/objects -type f
?? saludo.txt
blob
hola
.git/objects/5c/1b14949828006ed75a3e8858957f86a2f7e2eb

Ahí está el objeto en disco: los dos primeros caracteres del hash son la carpeta y los 38 restantes el nombre del archivo. git status dice ?? —Git no sigue el archivo— y sin embargo su contenido ya está guardado. Son dos cosas distintas.

Basta con los primeros caracteres del hash para referirse a un objeto, siempre que sean inequívocos.

El hash depende solo del contenido

printf "hola\n" > copia.txt
git hash-object copia.txt
printf "hola mundo\n" > otro.txt
git hash-object otro.txt
5c1b14949828006ed75a3e8858957f86a2f7e2eb
24db42bb7b999597a72801da70efd5876059bc0b

copia.txt da exactamente el mismo hash que saludo.txt: mismo contenido, mismo objeto. Git no guarda el archivo dos veces, aunque aparezca con dos nombres o en diez carpetas. Cambia un solo byte y el hash es otro.

Esto explica de paso por qué Git detecta un renombrado sin que se lo digas: el blob es el mismo, solo cambia el nombre que lo referencia desde el tree.

Del index al tree

git add saludo.txt
git write-tree
git cat-file -p 801e4533
801e45332eddf6a31000c9c885c163b5590a9110
100644 blob 5c1b14949828006ed75a3e8858957f86a2f7e2eb	saludo.txt

git write-tree convierte el índice en un objeto tree. Y ahí se ve el mecanismo: el nombre del archivo vive en el tree, no en el blob. El tree asocia saludo.txt con el blob que ya habíamos creado.

El commit

git commit -m "docs: añade saludo"
git cat-file -p HEAD
tree 801e45332eddf6a31000c9c885c163b5590a9110
author Alumno Git <alumno@example.test> 1785877663 +0200
committer Alumno Git <alumno@example.test> 1785877663 +0200

docs: añade saludo

El commit es un objeto de texto de cinco líneas que apunta al tree que ya existía. No contiene los archivos: contiene una referencia.

Con un segundo commit aparece la pieza que faltaba:

printf "adiós\n" > despedida.txt
git add despedida.txt && git commit -m "docs: añade despedida"
git cat-file -p HEAD
tree 75c4e260e882bc851ca533db1ac6906660d5761f
parent abe8a64b63643f88a1bb9a1aa448c50b7efbd703
author Alumno Git <alumno@example.test> 1785877681 +0200
committer Alumno Git <alumno@example.test> 1785877681 +0200

docs: añade despedida

La línea parent es el historial. Un commit no «contiene» a los anteriores: los encadena.

Las referencias

git symbolic-ref --short HEAD
git rev-parse HEAD
cat .git/refs/heads/main
main
abe8a64b63643f88a1bb9a1aa448c50b7efbd703
abe8a64b63643f88a1bb9a1aa448c50b7efbd703

Una rama es un archivo de texto con un hash dentro. Eso es todo. Por eso crear una rama es instantáneo por grande que sea el proyecto (módulo 5), y por eso un tag anotado, que sí es un objeto, se comporta distinto (módulo 7).

Las carpetas son trees anidados

mkdir -p docs/guias
printf "contenido\n" > docs/guias/intro.md
git add docs && git commit -m "docs: añade guía"

git cat-file -p HEAD^{tree}
git cat-file -p HEAD:docs
git cat-file -p HEAD:docs/guias
100644 blob 7e8370422e59e40a2b2de30c5565f7725734d9c7	despedida.txt
040000 tree de166d80ba2206ab9d9c36705adeb5180885c765	docs
100644 blob 5c1b14949828006ed75a3e8858957f86a2f7e2eb	saludo.txt
040000 tree da278967d67b13c4482d3bb40a71312e30705f30	guias
100644 blob 764df4e2bf5c8afd5ab625cda76bdc30ece1eeef	intro.md

El modo 040000 marca un tree y 100644 un archivo normal. Compáralo con el 160000 de un submódulo (módulo 10): ahí se entiende de golpe que un submódulo es una entrada de tree de un tipo especial.

Y el inventario completo del repositorio:

git cat-file --batch-all-objects --batch-check='%(objecttype)' | sort | uniq -c
   3 blob
   3 commit
   5 tree

Tres commits, tres contenidos distintos y cinco trees (la raíz de cada commit más los anidados).

Qué cambia en cada paso

Acción Directorio de trabajo Index Historial local
Crear saludo.txt Se crea el archivo Sin cambios Sin cambios
hash-object -w Sin cambios Sin cambios Se almacena un blob sin referencia
add Sin cambios Incluye el blob Sin cambios
commit Sin cambios Conserva el estado confirmado Se crea el commit y main avanza

No hay remoto en este laboratorio. Ninguna orden publica objetos ni modifica repositorios ajenos.

Errores frecuentes

  • Confundir el hash de un archivo con el de un commit. Compruébalo con git cat-file -t <id>: te dirá blob, tree, commit o tag.
  • Pensar que hash-object -w equivale a confirmar. El objeto queda sin referencia: no aparece en ningún commit y el mantenimiento acabará eliminándolo.
  • Editar a mano archivos dentro de .git. Aquí se abre para observar, no para trabajar. Todo lo que hay que hacer tiene un comando.
  • Leer el hash como una firma de autoría. Identifica contenido, no personas. La verificación de identidad requiere firmas (git commit -S).

Ejercicio autocorregible

Añade notas/pendientes.md, prepara y crea un tercer commit. Entrega la salida de:

git log --oneline --decorate -3
git cat-file -p HEAD
git cat-file -p HEAD^{tree}
git cat-file -t $(git rev-parse HEAD)
git status --short

Criterios de revisión: hay tres commits; el actual muestra una línea parent; el tree raíz incluye una entrada 040000 tree para notas; git cat-file -t sobre HEAD devuelve commit; git status --short no muestra cambios pendientes. Debe explicarse por qué el blob de un archivo no contiene su nombre.

Resumen

El alumnado debe poder explicar por qué un commit no es un archivo, dónde vive el nombre de cada archivo, cómo interviene el index y qué referencia mueve una rama al confirmar cambios.


Laboratorio B — Cambios propuestos por IA: aislamiento, revisión y trazabilidad

Objetivo observable

Incorporar una propuesta generada con IA sin darle autoridad de publicación: en rama aislada, con revisión del diff, pruebas ejecutadas y un commit atribuible a una persona.

Prerrequisitos

Laboratorio A, ramas, diff y revisión básica de código.

Explicación

La IA no cambia las reglas de Git. Una propuesta generada es un cambio no confiado hasta que una persona lo entiende, lo prueba y decide integrarlo — exactamente el mismo trato que la contribución de alguien externo al equipo. El flujo mínimo:

  1. Definir una tarea limitada y sus criterios de aceptación.
  2. No compartir secretos, datos personales ni código cuya política prohíba enviarlo al servicio elegido.
  3. Trabajar en una rama dedicada.
  4. Revisar el diff y ejecutar las pruebas del proyecto.
  5. Crear un commit atribuible a la decisión humana.
  6. Pedir revisión antes de integrar o publicar.

Este laboratorio no exige GitHub ni un asistente concreto. Si se usa una herramienta externa, su configuración, privacidad, licencia y retención de datos deben verificarse en su documentación oficial antes de usarla.

Antes de empezar: la norma que te aplica a ti

Este curso no te impone una política de uso de IA: te da el mecanismo técnico para trabajar con ella de forma trazable. Pero casi con seguridad hay una norma que sí te aplica, y comprobarla es parte del trabajo:

  • Si estudias, la de tu centro: qué herramientas se admiten y cómo hay que declarar el uso de IA en una entrega evaluable.
  • Si trabajas, la de tu empresa. Suele ser la más restrictiva, y suele existir aunque nadie te la haya enseñado.
  • Si desarrollas para un cliente, lo que diga el contrato sobre enviar su código a servicios de terceros.

Mientras no tengas una norma concreta delante, esta base te mantiene fuera de problemas:

Regla Por qué
Nunca pegues credenciales, .env, datos personales ni datos de producción Sales del ámbito técnico y entras en el legal. Es irreversible.
Comprueba en la herramienta si tus datos se usan para entrenar Suele ser una opción desactivable, y por defecto no siempre lo está.
Ante código de un cliente o de la empresa, pide permiso antes El silencio no es autorización.
Deja constancia del origen en el commit Es lo que enseña este laboratorio, y te cubre.
Responde tú del código que aceptas «Lo generó la IA» no es una explicación válida en una revisión.

La regla que resume todas: si dudas de si puedes enviar algo, no lo envíes. Reformula la pregunta sin el dato sensible; casi siempre se puede.

Nota para quien imparta este curso presencialmente. Este laboratorio se ha redactado para estudio autónomo. Si lo llevas a un aula, sustituye esta sección por la normativa concreta de tu centro; en 00-gestion/RECOMENDACIONES_IA.md de este repositorio hay una propuesta de política y de criterios de evaluación lista para adaptar.

Aislar la propuesta

mkdir lab-ia-git
cd lab-ia-git
git init -b main
git config user.name "Alumno Git"
git config user.email "alumno@example.test"

printf "# Agenda\n" > README.md
printf "No incluir claves ni datos personales en peticiones a asistentes.\n" > SECURITY.md
git add README.md SECURITY.md
git commit -m "docs: crea base del proyecto"

git switch -c ia/documentacion-agenda
Switched to a new branch 'ia/documentacion-agenda'

El prefijo ia/ no es obligatorio, pero hace visible en git branch de dónde salió la propuesta. Todo lo que venga después queda separado de main.

Revisar el diff

Simula la propuesta con un cambio pequeño y explícito:

printf "\n## Uso\n\nRegistra una tarea y revisa sus cambios antes de confirmar.\n" >> README.md
git diff --check
git add README.md
git diff --cached
diff --git a/README.md b/README.md
index 5d8b6e4..8eff263 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,5 @@
 # Agenda
+
+## Uso
+
+Registra una tarea y revisa sus cambios antes de confirmar.

git diff --check no imprime nada cuando el cambio está limpio. Cuando no lo está, es la red que más rentabiliza este laboratorio:

printf "linea con espacios sobrantes   \n" >> README.md
git diff --check
README.md:6: trailing whitespace.
+linea con espacios sobrantes

Y sobre todo esto, que es el error más penalizado del proyecto final (módulo 8):

printf "<<<<<<< HEAD\nversion a\n=======\nversion b\n>>>>>>> otra\n" > pegado.txt
git add pegado.txt
git diff --cached --check
pegado.txt:1: leftover conflict marker
pegado.txt:3: leftover conflict marker
pegado.txt:5: leftover conflict marker

Un texto pegado de cualquier origen puede arrastrar marcadores de conflicto. --check los detecta antes de que lleguen al historial.

Ejecutar las pruebas

Revisar el diff no basta: hay que comprobar que el resultado funciona. Cualquier proyecto debería tener una comprobación reproducible, por sencilla que sea. Para la agenda del proyecto final:

cat > comprobar.sh <<'EOF'
#!/bin/sh
# Comprobaciones mínimas del proyecto. Devuelve 0 si todo pasa.
grep -q "^## Uso" README.md   || { echo "FALLO: falta la sección Uso"; exit 1; }
grep -q "claves" SECURITY.md  || { echo "FALLO: SECURITY.md sin regla de claves"; exit 1; }
echo "OK: comprobaciones superadas"
EOF
chmod +x comprobar.sh
./comprobar.sh
OK: comprobaciones superadas

Y cuando la propuesta rompe algo:

FALLO: falta la sección Uso

Lo que importa es el código de salida: 0 si pasa, distinto de 0 si falla. Ese contrato es el que permite automatizar después con git bisect run (módulo 9) o con integración continua (módulo 11). En un proyecto real, comprobar.sh se sustituye por pytest, npm test, mvn test o lo que use el lenguaje.

Confirmar con trazabilidad

git add -A
git commit -m "docs: explica el uso de la agenda" \
  -m "Propuesta inicial generada con asistente de IA; revisada, probada y aceptada por la autora del commit."
git log -1 --format="autor: %an <%ae>%nmensaje:%n%B"
autor: Alumno Git <alumno@example.test>
mensaje:
docs: explica el uso de la agenda

Propuesta inicial generada con asistente de IA; revisada, probada y aceptada por la autora del commit.

Dos ideas en esa salida:

  • El autor es una persona. Quien acepta el cambio responde de él. No se atribuye un commit a una herramienta.
  • El cuerpo del mensaje deja constancia del origen. El asunto describe el resultado (docs: explica el uso), no la herramienta; el cuerpo aporta el contexto. Dentro de seis meses, esa línea es la diferencia entre saber de dónde salió un cambio y suponerlo.

Comprobación final:

git log --oneline --decorate -2
git status --short
1178b87 (HEAD -> ia/documentacion-agenda) docs: explica el uso de la agenda
a456ee8 (main) docs: crea base del proyecto

El trabajo está aislado en su rama y main intacta. Integrarlo es una decisión posterior, y pasa por la misma revisión que cualquier otra contribución (módulos 5 y 8).

Extensión: revisar en paralelo

Un equipo puede aislar la revisión en otro directorio sin abandonar lo que tiene a medias:

git worktree add ../lab-ia-revision -b review/ia-documentacion
git worktree list

Al terminar, git worktree remove ../lab-ia-revision, solo tras comprobar que no contiene cambios sin confirmar (módulo 10).

Errores frecuentes

  • Pegar una propuesta y confirmar sin leer el diff. La salida puede ser incorrecta, insegura o simplemente innecesaria.
  • Incluir tokens, .env, credenciales o datos de producción en una petición. Es la fuga más fácil de cometer y la más difícil de deshacer: si además acaba en un commit publicado, el revert no lo borra del historial (módulo 6).
  • Confirmar sin ejecutar las pruebas. Un diff correcto en apariencia puede romper el proyecto.
  • Trabajar directamente en main.
  • Atribuir el commit a una IA en lugar de registrar qué persona aceptó el cambio.
  • Confundir una rama local con una pull request: la PR pertenece a GitHub, no a Git (módulo 5).

Ejercicio autocorregible

A partir del repositorio anterior, crea la rama ia/mejora-seguridad, añade una regla concreta a SECURITY.md, amplía comprobar.sh para verificarla y entrega:

git branch --show-current
git diff main...HEAD
git diff --check
./comprobar.sh; echo "código de salida: $?"
git log --oneline main..HEAD
git log -1 --format="%an <%ae>%n%B"

Criterios de revisión: la rama no es main; el diff de tres puntos contiene solo el cambio solicitado; --check no informa de nada; la comprobación devuelve 0; existe exactamente un commit nuevo; el asunto describe el resultado y no la herramienta, y el autor es una persona identificable.

Resumen

El alumnado debe saber tratar una propuesta de IA como una contribución que exige límites de datos, aislamiento, revisión humana, pruebas y trazabilidad. Git aporta el mecanismo de control; la calidad y la responsabilidad siguen siendo humanas.

Estado editorial: listo.

Registro de revisión técnica

Revisado el 4 de agosto de 2026 con Git 2.47.1. Los dos laboratorios se han reproducido desde carpetas vacías, con identidad de práctica y configuración aislada.

Laboratorio A. El borrador describía las salidas en prosa («un identificador hexadecimal», «el contenido del commit incluye una línea tree») en lugar de mostrarlas. Se han sustituido por las salidas reales, lo que permite seguir la cadena completa: el blob 5c1b1494… aparece dentro del tree 801e4533…, que a su vez es la primera línea del commit. Se ha añadido, verificado, lo que faltaba para cerrar el modelo:

  • La ubicación del objeto en disco (.git/objects/5c/1b1494…), que hace tangible el almacén.
  • Que el hash depende solo del contenido: copia.txt con el mismo texto devuelve el mismo hash que saludo.txt. De ahí se explica la deduplicación y la detección de renombrados.
  • Que el nombre del archivo vive en el tree, no en el blob.
  • El segundo commit con su línea parent.
  • Que una rama es un archivo de texto con un hash: cat .git/refs/heads/main coincide con git rev-parse HEAD.
  • Los trees anidados de una carpeta (040000 tree), contrastados con el 160000 de un submódulo del módulo 10.
  • El inventario git cat-file --batch-all-objects, que devuelve 3 blobs, 3 commits y 5 trees.

Laboratorio B. Verificado el flujo completo. Se ha comprobado que git diff --check no imprime nada con un cambio limpio, informa trailing whitespace ante espacios sobrantes y —lo más relevante para este curso— leftover conflict marker en las tres líneas de un texto pegado con marcadores de conflicto, que es el error más penalizado de la rúbrica del módulo 8.

Añadido lo que pedía la nota editorial del borrador: un ejemplo de pruebas. Se ha escrito y ejecutado comprobar.sh, un guion de comprobación del proyecto de la agenda que devuelve 0 al pasar y 1 con su mensaje de fallo al romperse. Se ha elegido un guion de shell en vez de un marco de pruebas concreto para no atar el laboratorio a un lenguaje, y se enlaza explícitamente con el contrato de código de salida que ya usan git bisect run (módulo 9) y la integración continua (módulo 11).

Se ha añadido también la trazabilidad en el cuerpo del mensaje de commit, verificando con git log --format="%an <%ae>%n%B" que el autor sigue siendo la persona y que el origen queda documentado sin ensuciar el asunto.

Resuelto el 5 de agosto de 2026. La nota del borrador pedía contrastar el laboratorio con la política de IA del centro. Al publicarse el curso como formación online sin tutor no hay centro que fije una, así que la sección se ha reorientado a quien estudia por su cuenta: se le pide comprobar la norma que le aplique —de su centro, su empresa o su cliente— y se le da una base mínima de cinco reglas para mientras tanto. Las recomendaciones para una impartición presencial, con propuesta de política y criterios de evaluación, se han llevado a 00-gestion/RECOMENDACIONES_IA.md, que no se publica.

Los hashes y las marcas de tiempo de las salidas son los de esta ejecución y serán distintos en cada repositorio.