Llegamos a la última lección del curso, y la pregunta que toca hacerse es la más honesta que puede plantearse al final de cualquier formación técnica: ¿cuánto de todo esto seguirá siendo cierto dentro de diez años?
Git tiene ya dos décadas. Nació en 2005 para un problema muy concreto —coordinar el desarrollo del kernel de Linux cuando su equipo perdió la herramienta que usaba— y se convirtió en el estándar universal del control de versiones. Pero no está congelado: sale una versión nueva cada pocos meses, y algunas de esas versiones traen cambios profundos que casi nadie usa todavía.
Esta lección separa con cuidado tres cosas que suelen mezclarse:
- Lo que ya existe y puedes usar hoy, aunque sea poco conocido o esté marcado como experimental.
- Lo que es tendencia: hacia dónde apunta el trabajo, sin fechas ni promesas.
- Lo que casi con seguridad no va a cambiar, y que es precisamente lo que aprendiste en el módulo 1.
Y luego cerramos el curso: cómo seguir aprendiendo por tu cuenta, y una recapitulación del camino completo.
Un aviso de método antes de empezar: en lo que sigue no daré fechas para nada que no esté ya disponible, y cuando mencione una versión de Git lo haré como referencia aproximada. El software evoluciona y las notas de versión son la única fuente fiable. Lo que sí puedo darte es el criterio para valorar cada cosa: qué problema resuelve, en qué estado está y si te conviene adoptarla.
Contenido
- Cómo evoluciona Git y cómo enterarse
- SHA-256: el sustituto de SHA-1
reftable: un formato nuevo para las referencias- Clones parciales e índice disperso
commit-graphygit maintenanceswitchyrestorefrente acheckout- Tabla de madurez: qué usar hoy
- Tendencias: hacia dónde apunta el trabajo
- El papel de los asistentes de IA
- Lo que no va a cambiar
- Cómo seguir aprendiendo
- El curso completo, recapitulado
- Cómo evoluciona Git y cómo enterarse
Git se desarrolla en abierto, por correo, con el modelo que estudiamos en la lección 10-01: parches en una lista pública, un mantenedor que integra, y publicaciones periódicas cada pocos meses. Cada versión trae un fichero de notas que describe lo nuevo, lo corregido y lo que cambia de comportamiento.
Saber en qué versión estás y qué trae es el primer hábito:
Y las notas de cada versión están en el propio repositorio de Git, en Documentation/RelNotes/. Leer las de cada versión nueva cuesta cinco minutos y es la mejor forma de descubrir cosas que llevas años haciendo mal.
Un detalle que conviene conocer: Git es extraordinariamente conservador con la compatibilidad hacia atrás. Un repositorio creado en 2006 se abre hoy sin conversión, y los comandos que aprendiste siguen funcionando. Esa es una de las razones por las que las novedades tardan tanto en llegar al uso común: se introducen como opcionales, conviven años con lo anterior, y solo se convierten en el valor por defecto cuando el ecosistema entero está preparado.
Esto tiene una consecuencia práctica para ti: casi nada de lo que has aprendido va a dejar de funcionar. Lo que puede pasar es que aparezcan formas mejores de hacer lo mismo.
- SHA-256: el sustituto de SHA-1
Por qué hace falta
Recuerda del módulo 1 que todo en Git se identifica por el hash SHA-1 de su contenido: blobs, árboles, commits y etiquetas. Ese hash es el eje del sistema entero. Y SHA-1, como función criptográfica, está roto: en 2017 se demostró públicamente que es posible construir dos contenidos distintos con el mismo hash SHA-1 (una colisión), con un coste computacional elevado pero alcanzable.
Conviene ser preciso sobre lo que eso significa para Git, porque se exagera en ambas direcciones:
| Preocupación | Realidad |
|---|---|
| "Git está roto, cualquiera puede falsificar commits" | No. Una colisión útil exige construir ambos contenidos a propósito; no permite fabricar un objeto que coincida con uno existente que no controlas |
| "SHA-1 en Git es solo un identificador, no seguridad" | Parcialmente cierto, pero el hash es lo que garantiza la integridad y lo que firman las firmas de commit (08-05) |
| "Da igual, nunca pasará nada" | Es una debilidad conocida en un sistema que sostiene la cadena de suministro de software del mundo |
Git no se quedó parado. Desde hace años incorpora detección de colisiones: una variante del cálculo de SHA-1 que detecta los patrones característicos de un ataque de colisión y rechaza el objeto. Los ficheros del ataque público de 2017 son rechazados por Git.
Pero eso es un parche. La solución de fondo es cambiar de función de hash.
Qué existe hoy
Git puede crear repositorios con SHA-256:
git init --object-format=sha256 repositorio-nuevo
cd repositorio-nuevo
echo "hola" > fichero.txt
git add fichero.txt
git commit -m "Primer commit"
git log --format=%HSesenta y cuatro caracteres hexadecimales en lugar de cuarenta. Y comprobarlo:
Todo lo que has aprendido funciona igual: add, commit, log, branch, merge, rebase, bisect. El modelo de datos es idéntico; solo cambia la función que calcula los identificadores. Es la mejor prueba de que lo que aprendiste en la lección 01-04 es el concepto, no el algoritmo concreto.
El problema real: la interoperabilidad
Aquí está el motivo de que SHA-256 siga siendo experimental y de que casi nadie lo use:
Un repositorio SHA-256 y uno SHA-1 no pueden intercambiar objetos.
git clone https://git.ejemplo.es/gestor-tareas.git # repositorio SHA-1
cd gestor-tareas
git remote add otro /ruta/al/repositorio-sha256
git fetch otroNo hay conversión sobre la marcha ni traducción transparente. Y esto es un problema enorme, porque el mundo entero —todas las plataformas de alojamiento, todos los repositorios existentes, todas las herramientas— está en SHA-1.
El plan de fondo, largamente diseñado, contempla repositorios capaces de operar en ambos formatos a la vez, manteniendo una tabla de correspondencias entre el hash SHA-1 y el SHA-256 de cada objeto, de modo que un repositorio SHA-256 pueda hablar con un servidor SHA-1 traduciendo en la frontera. Esa interoperabilidad es la pieza que falta, y es un trabajo considerable.
Qué hacer tú
Nada, por ahora. SHA-256 es útil para experimentar y para entender el modelo, y puede tener sentido en un entorno cerrado que no intercambie con nadie. Para trabajo real, mientras el ecosistema esté en SHA-1, un repositorio SHA-256 es una isla.
Lo que sí conviene es entender la distinción, porque es un ejemplo perfecto de por qué el modelo de datos importa más que sus detalles: el día que Git cambie de función de hash, tú no tendrás que reaprender nada.
reftable: un formato nuevo para las referencias
reftable: un formato nuevo para las referenciasEl problema del formato actual
Recuerda de la lección 03-01: una rama es un fichero de texto con un hash dentro.
Es de una simplicidad admirable y funciona perfectamente en gestor-tareas, con sus cinco ramas. Cuando hay muchas referencias, Git las compacta en un único fichero:
# pack-refs with: peeled fully-peeled sorted 4f8a2e6c9d3b1a5e7f2c8b0d4a6e9f1c3b5d7a0e refs/heads/main 8a1f6c3d4e5b6a7c8d9e0f1a2b3c4d5e6f7a8b9c refs/remotes/origin/main 2e9f4c7b1a8d3e6f0c5b2a9d4e7f1a8c3b6d0e5f refs/tags/v1.3.0
Este sistema —ficheros sueltos más un fichero compactado— tiene límites que se notan a gran escala:
| Problema | Por qué ocurre |
|---|---|
| Muchos ficheros pequeños | Un repositorio con 100.000 referencias tiene hasta 100.000 ficheros; los sistemas de ficheros sufren |
| Escrituras costosas | Actualizar una referencia con packed-refs obliga a reescribir el fichero entero |
| Concurrencia limitada | Dos procesos actualizando referencias a la vez compiten por bloqueos |
| Colisiones de nombres | No pueden coexistir refs/heads/funcion y refs/heads/funcion/nueva: un directorio no puede ser también un fichero |
| Sin historial de referencias | El reflog es un mecanismo aparte, con su propio formato |
| Mayúsculas y minúsculas | En sistemas de ficheros que no las distinguen, Main y main chocan |
Ese cuarto punto es el que probablemente ya has sufrido:
fatal: cannot lock ref 'refs/heads/funcion/nueva': 'refs/heads/funcion' exists; cannot create 'refs/heads/funcion/nueva'
No es una regla arbitraria de Git: es que el sistema de ficheros no permite que funcion sea a la vez fichero y directorio.
Qué es reftable
reftable es un formato binario para almacenar referencias y su reflog en un conjunto pequeño de ficheros ordenados, diseñado originalmente para servidores con enormes cantidades de referencias y posteriormente incorporado a Git.
Sus propiedades:
- Búsqueda binaria sobre datos ordenados y comprimidos por prefijo: encontrar una referencia entre cientos de miles es inmediato.
- Escrituras por adición, con compactación periódica: actualizar no obliga a reescribir todo.
- Transacciones atómicas sobre múltiples referencias.
- Reflog integrado en el mismo formato.
- Sin restricciones del sistema de ficheros:
funcionyfuncion/nuevapueden coexistir, y las mayúsculas se distinguen siempre.
Se usa así:
git init --ref-format=reftable repositorio-nuevo
cd repositorio-nuevo
git rev-parse --show-ref-formatY entonces:
No hay refs/heads/. No hay packed-refs. Las referencias viven dentro de esos ficheros binarios.
Todos los comandos que conoces funcionan exactamente igual. git branch, git tag, git switch, git log, git reflog. Lo único que cambia es que ya no puedes hacer cat .git/refs/heads/main, y tienes que usar la fontanería (lección 09-06):
Que es, por cierto, lo que siempre deberías haber hecho: leer los ficheros internos a mano nunca fue una interfaz estable. Esta es una lección práctica que va más allá de reftable: usa los comandos, no los ficheros.
Estado y recomendación
reftable está disponible en versiones recientes de Git y se considera funcional, pero no es el formato por defecto y hay que contar con que herramientas externas que lean .git/refs/ directamente no funcionarán con él.
Qué hacer tú: conocerlo y no adoptarlo todavía salvo que tengas un repositorio con decenas de miles de referencias y estés sufriendo por ello. Es un ejemplo excelente de evolución bien hecha: cambia la implementación por completo sin cambiar ni un solo comando.
- Clones parciales e índice disperso
Estos ya los conoces de la lección 10-04, y aquí van con la etiqueta que les corresponde en esta lección: son presente, no futuro.
git clone --filter=blob:none https://git.ejemplo.es/proyecto.git
git sparse-checkout init --cone --sparse-index
git sparse-checkout set servicios/tareasAmbas técnicas están disponibles, soportadas por las plataformas principales y en uso en producción en organizaciones grandes. Lo interesante desde la perspectiva de esta lección es qué representan: son la respuesta de Git a un problema que su diseño original no contemplaba.
Git nació con un supuesto implícito: cada clon tiene el repositorio completo. Eso es lo que lo hace distribuido y lo que le da su resistencia (lección 09-05: cualquier clon es una copia de seguridad). Pero también es lo que lo hacía inviable para repositorios de decenas de gigabytes.
Los clones parciales relajan ese supuesto sin romper el modelo: el repositorio sigue teniendo el grafo completo y sigue sabiendo qué objetos existen; simplemente algunos no están descargados todavía y se piden cuando hacen falta. Es una solución elegante porque conserva la semántica y solo difiere la transferencia.
La tendencia que representan es clara: Git evoluciona hacia poder trabajar con repositorios de cualquier tamaño sin renunciar a su modelo. Es previsible que este trabajo continúe: mejor gestión de qué se descarga, mejores heurísticas de prefetch y menos casos raros.
commit-graph y git maintenance
commit-graph y git maintenanceTambién presente, también de la lección 10-04 y la 08-06.
git config --global core.commitGraph true
git config --global fetch.writeCommitGraph true
git maintenance startRepresentan otra línea de evolución: estructuras auxiliares que aceleran sin cambiar el modelo. El commit-graph no es información nueva: es información que ya estaba en los objetos commit, precalculada en un formato que se lee rápido. Si lo borras, no pierdes nada; se regenera.
Ese principio de diseño —cachés derivadas, regenerables y opcionales— es muy sano y es previsible que se extienda. Es la forma de mejorar el rendimiento sin comprometer la simplicidad del formato de almacenamiento, que es el activo más valioso de Git.
git maintenance, por su parte, refleja un cambio de filosofía en el mantenimiento: en lugar de que gc te interrumpa cuando menos te conviene, hay tareas programadas que se ejecutan en segundo plano. Es previsible que acabe siendo el comportamiento por defecto.
switch y restore frente a checkout
switch y restore frente a checkoutUn caso distinto: no es rendimiento ni criptografía, es diseño de la interfaz.
git checkout es el comando más sobrecargado de Git. Hace cosas conceptualmente distintas según sus argumentos:
git checkout main # cambiar de rama
git checkout -b nueva # crear rama y cambiar
git checkout 4f8a2e6 # ir a un commit (HEAD desprendido)
git checkout -- app.js # DESCARTAR cambios en un fichero
git checkout main -- app.js # traer un fichero de otra rama
git checkout --ours app.js # resolver un conflictoSeis operaciones distintas, y una de ellas —la cuarta— destruye trabajo sin posible recuperación. Que git checkout main (inofensivo) y git checkout -- app.js (irreversible) sean el mismo comando separados por dos guiones es un problema de diseño, y ha costado disgustos a mucha gente.
La solución fue partirlo en dos comandos con propósitos claros:
| Antes | Ahora | Qué hace |
|---|---|---|
git checkout main |
git switch main |
Cambiar de rama |
git checkout -b nueva |
git switch -c nueva |
Crear rama y cambiar |
git checkout 4f8a2e6 |
git switch --detach 4f8a2e6 |
HEAD desprendido, de forma explícita |
git checkout - |
git switch - |
Volver a la rama anterior |
git checkout -- app.js |
git restore app.js |
Descartar cambios del disco |
git checkout HEAD -- app.js |
git restore --source=HEAD app.js |
Restaurar desde una revisión |
git reset HEAD app.js |
git restore --staged app.js |
Quitar del índice |
git checkout --ours app.js |
git restore --ours app.js |
Resolver conflicto |
Fíjate en la fila del HEAD desprendido: con switch hay que pedirlo explícitamente con --detach. Se acabó el "he hecho checkout de una etiqueta y ahora estoy en un sitio raro" que estudiamos en la lección 03-02.
Y fíjate en la penúltima fila: git restore --staged sustituye a un uso de git reset que confundía a todo el mundo, porque reset es un comando que mueve ramas (lección 09-02) y usarlo para quitar un fichero del índice mezclaba dos conceptos.
Estado
switch y restore llevan años disponibles, estuvieron marcados como experimentales durante bastante tiempo y en versiones recientes se han consolidado. Se pueden usar con confianza.
Y checkout no va a desaparecer. Hay millones de guiones, tutoriales y hábitos que dependen de él, y Git es conservador con la compatibilidad. Convivirán indefinidamente.
Qué hacer tú: usar switch y restore en tu trabajo diario, y saber leer checkout porque lo vas a encontrar en toda la documentación existente, en las respuestas de internet y en los guiones de tu empresa. Es exactamente la recomendación que hicimos en la lección 03-02, y aquí se confirma.
- Tabla de madurez: qué usar hoy
Resumen operativo de todo lo anterior, más lo que ya conoces:
| Novedad | Estado | ¿Adoptar hoy? | Motivo |
|---|---|---|---|
switch / restore |
Consolidado | Sí, siempre | Más claro y más seguro que checkout; sin riesgo |
commit-graph |
Estable | Sí, siempre | Caché regenerable, sin inconvenientes, gran mejora en historiales grandes |
git maintenance |
Estable | Sí en repositorios medianos y grandes | Mantenimiento en segundo plano en vez de interrupciones |
fsmonitor / untrackedCache |
Estable | Sí si git status tarda |
Mide antes; en repositorios pequeños no aporta |
Clones parciales (--filter=blob:none) |
Estable, soporte amplio | Sí en repositorios grandes y en CI | Historial completo con una fracción de la descarga |
sparse-checkout --cone + índice disperso |
Estable | Solo en monorepos con muchísimos ficheros | Añade confusión si no hace falta |
| Git LFS | Maduro (externo a Git) | Sí si hay binarios grandes que cambian | Con las limitaciones de la 10-03 |
reftable |
Disponible, no por defecto | No salvo decenas de miles de referencias | Herramientas externas pueden no soportarlo |
| SHA-256 | Experimental | No para trabajo real | Sin interoperabilidad con el ecosistema SHA-1 |
La columna que importa es la tercera, y su patrón: lo que no tiene inconvenientes, adóptalo ya; lo que tiene coste de comprensión, solo si mides que lo necesitas; lo que aún no interopera, conócelo y espera.
- Tendencias: hacia dónde apunta el trabajo
Aquí salimos de lo comprobable. Lo que sigue son direcciones observables en el ecosistema, no predicciones con fecha.
Mejor experiencia para monorepos
Es la línea de trabajo más visible de los últimos años, y todo lo que vimos en la lección 10-04 forma parte de ella: clones parciales, índice disperso, fsmonitor, commit-graph. La motivación es clara: las organizaciones grandes han apostado por repositorios enormes, y necesitan que Git funcione en ellos.
Es razonable esperar más en esa dirección: menos casos raros con sparse-checkout, mejores heurísticas sobre qué descargar, y quizá que algunas de estas opciones dejen de serlo y pasen a ser el comportamiento por defecto cuando Git detecte que le conviene.
Servidores Git especializados
Un dato que conviene tener presente: el git que ejecuta un servidor grande no siempre es el git que tienes tú. Las plataformas de gran escala han desarrollado implementaciones propias del lado del servidor —a veces basadas en Git, a veces reescrituras compatibles con el protocolo— optimizadas para servir a miles de clientes concurrentes.
Para ti, esto es transparente: hablas el protocolo de Git y no sabes qué hay al otro lado. Pero explica por qué algunas plataformas soportan funciones que otras no, y por qué las cuotas y los comportamientos difieren (algo que ya notamos con LFS en la lección 10-03).
La tendencia es que esa especialización aumente, y que el Git que ejecutas en tu portátil y el que corre en un servidor sean cada vez más distintos por dentro, aunque hablen lo mismo.
Herramientas construidas sobre Git, no sustitutos
Este es un patrón de veinte años que no da señales de cambiar. Han aparecido decenas de sistemas de control de versiones nuevos, y algunos son técnicamente interesantes. Pero lo que ha triunfado no son los sustitutos, sino las capas construidas encima: plataformas de alojamiento, sistemas de revisión, interfaces gráficas, herramientas de gestión de parches, sistemas de despliegue (lección 10-05), y clientes alternativos con modelos de trabajo distintos que almacenan en el formato de Git.
La razón es el efecto de red combinado con una propiedad técnica: el formato de almacenamiento de Git es simple, está documentado y es estable. Cualquiera puede escribir una herramienta que lo lea y lo escriba. Eso convierte a Git en algo parecido a un formato de fichero universal, y sustituir un formato universal es muchísimo más difícil que sustituir un programa.
La consecuencia práctica para ti es tranquilizadora: aunque la interfaz que uses cambie, el modelo de debajo probablemente no.
Mejor experiencia de línea de comandos
Hay una corriente sostenida de mejora en los mensajes de error y en las sugerencias. Git ha pasado de mensajes crípticos a mensajes que explican qué hacer:
error: the branch 'GT-231-filtro-ocultas' is not fully merged. hint: If you are sure you want to delete it, run 'git branch -D GT-231-filtro-ocultas'.
Esa línea hint: no existía hace años. Es un trabajo poco espectacular y muy valioso, y es previsible que continúe.
- El papel de los asistentes de IA
Merece un apartado propio porque es la novedad más visible del ecosistema y la que más confusión genera. Vamos a mirarlo con el mismo criterio que hemos aplicado a todo lo demás: qué aporta de verdad y dónde está el riesgo.
Dónde ayudan realmente
Redactar mensajes de commit. Un asistente puede leer un diff y proponer un mensaje. Funciona bien para la primera línea —resumir qué cambió— y es un buen punto de partida cuando estás en blanco.
Explicar código ajeno o un diff grande. Poner en palabras qué hace un cambio de 400 líneas ahorra tiempo real durante una revisión.
Recordar comandos y opciones. "¿Cómo era el comando para ver quién escribió cada línea ignorando los cambios de espaciado?" es exactamente el tipo de pregunta que un asistente responde bien.
Primera pasada de revisión. Detectar patrones sospechosos, olvidos evidentes, inconsistencias. Como comprobación informativa, en el sentido de la lección 10-02: que informe, no que bloquee.
Generar guiones auxiliares. Los guiones de las lecciones 10-05 y 10-04 son exactamente el tipo de cosa que un asistente escribe con soltura.
Dónde no ayudan, y el riesgo
El porqué del cambio no está en el diff. Y el porqué es lo importante de un mensaje de commit (lección 08-01). Un asistente puede escribir perfectamente "añade el filtro de tareas ocultas al listado" leyendo el código. Lo que no puede escribir es:
El contador debe seguir incluyéndolas porque la especificación de GT-231 dice que "pendientes" cuenta todas las tareas no completadas, estén visibles o no.
Ese párrafo —el mismo de la lección 09-06— contiene una decisión, un motivo y una referencia a una discusión. Está en tu cabeza, no en el código. Un mensaje generado automáticamente que describe el qué y omite el porqué es un mensaje que ha perdido su función.
Un mensaje generado y no revisado es peor que ninguno, porque parece documentación y no lo es. Y el historial es el único documento del proyecto que nadie puede editar después.
El riesgo de fondo: aceptar sin entender. Es el mismo riesgo del botón "Sincronizar" de la lección 10-02, amplificado. Si un asistente te propone git reset --hard HEAD~3 y lo ejecutas sin entenderlo, el problema no es el asistente: es que estás ejecutando operaciones destructivas a ciegas.
Y hay una asimetría muy concreta que conviene tener presente: las operaciones de Git no son igual de reversibles. Una sugerencia equivocada de git log no cuesta nada. Una sugerencia equivocada de git push --force, git reset --hard o git clean -fd puede costar trabajo que no se recupera. Cuanto más destructiva la operación, más exige entenderla antes.
El criterio
Un asistente ayuda a redactar, a recordar y a explorar. No exime de entender el cambio.
Y una regla práctica derivada de todo el curso:
| Tarea | Delegar en el asistente | Por qué |
|---|---|---|
| Redactar el asunto de un commit | Sí, revisando | El qué está en el diff |
| Escribir el cuerpo que explica el porqué | No | Solo tú lo sabes |
| Recordar la sintaxis de un comando | Sí | Es documentación |
| Ejecutar una operación destructiva sugerida | No sin entenderla | reset --hard, push --force, clean -fd |
| Explicar un diff ajeno | Sí | Ahorra tiempo real |
| Decidir si un cambio es buena idea | No | Requiere contexto del producto |
| Generar un guion auxiliar | Sí, leyéndolo | Y probándolo en un repositorio de pruebas |
| Resolver un conflicto de fusión | Con mucha cautela | Requiere entender las dos intenciones (03-05) |
Fíjate en que esta tabla es la misma de la lección 10-02 sobre interfaces gráficas, con otros nombres. La regla de fondo no ha cambiado en todo el módulo: automatiza lo repetitivo, entiende lo irreversible.
Y hay una consecuencia optimista: en un mundo donde escribir código cuesta menos, entender el historial, saber por qué se tomó una decisión y poder recuperarse de un error valen más, no menos. Justo lo que enseña este curso.
- Lo que no va a cambiar
Después de mirar lo que se mueve, toca mirar lo que no. Y esto es lo más importante de la lección.
El modelo de datos direccionable por contenido
Todo objeto se identifica por el hash de su contenido. El hash puede cambiar de SHA-1 a SHA-256; la idea, no. Y de ella se derivan, como consecuencias necesarias, propiedades que has usado durante todo el curso:
- Los objetos son inmutables: cambiar el contenido produce un objeto distinto.
- El contenido idéntico se guarda una sola vez, en cualquier rama y en cualquier momento.
- El hash de un commit verifica todo su historial, porque incluye el de su árbol y el de sus padres.
- Reescribir historia crea objetos nuevos; no modifica los viejos. Por eso el reflog puede recuperarlos (09-04).
Este último punto es la clave de medio curso. rebase, amend, cherry-pick, filter-repo: todos crean objetos nuevos y mueven referencias. Los originales siguen ahí hasta que la recolección de basura los borra. Eso no es una característica añadida: es una consecuencia matemática del direccionamiento por contenido.
El grafo dirigido acíclico de commits
Cada commit apunta a sus padres. De ahí salen las ramas, las fusiones, los antepasados comunes y todo lo demás:
- Una rama es un puntero móvil a un nodo (03-01).
- Una fusión es un commit con dos padres, y la base es el antepasado común (03-03).
bisectes búsqueda binaria sobre el grafo (06-02).rebasees reproducir un camino sobre otro punto (05-01).- Una divergencia es que dos referencias apuntan a nodos sin relación de antepasado (09-03).
merge-base --is-ancestores una pregunta sobre alcanzabilidad, y es lo que usábamos para verificar despliegues (10-05).
Ese grafo no va a cambiar. Es demasiado simple, demasiado potente y demasiado central.
La naturaleza distribuida
Cada clon es un repositorio completo, con todo el historial y toda la capacidad de operar sin conexión. De ahí salen:
- Que puedas trabajar sin red y sincronizar después (04-04).
- Que cualquier clon sea una copia de seguridad viable (09-05).
- Que no exista un repositorio "oficial" salvo por acuerdo (04-01).
- Que los forks funcionen (07-01) y que el modelo del kernel sea posible (10-01).
Los clones parciales relajan el "completo" para el contenido, pero no el modelo: sigues teniendo el grafo entero y sigues siendo autónomo para casi todo.
Las tres zonas
Copia de trabajo, índice y repositorio (lección 01-03). El índice es la pieza que más desconcierta al principio y la que más valor da después: es lo que permite add -p (02-04), lo que hace que git add sea también una red de seguridad, y lo que sostiene la resolución de conflictos con sus tres etapas (03-05).
Por eso este curso no caduca
Has aprendido comandos, pero sobre todo has aprendido un modelo. Los comandos cambiarán de nombre —
checkoutse ha partido enswitchyrestore— y aparecerán opciones nuevas. El modelo lleva veinte años idéntico y no hay ninguna señal de que vaya a moverse.
Cuando dentro de cinco años te encuentres un comando que no conoces, la pregunta que te permitirá entenderlo en treinta segundos será siempre la misma: ¿qué objetos crea y qué referencias mueve?
- Cómo seguir aprendiendo
Terminado el curso, la mejor forma de seguir es usando lo que Git ya trae.
La documentación integrada
# Manual completo de un comando
git help rebase
git rebase --help
# Resumen rápido de opciones, sin abrir el manual
git rebase -h
# La lista de TODAS las guías conceptuales
git help -gEse git help -g es un descubrimiento para mucha gente. Devuelve una lista de guías que no son manuales de comandos sino explicaciones de conceptos:
| Guía | De qué trata | Cuándo leerla |
|---|---|---|
gitcore-tutorial |
Git desde la fontanería: cómo se construyen los objetos a mano | La mejor de todas. Léela ya |
giteveryday |
Los ~20 comandos que cubren el 99 % del uso, por rol | Como repaso ordenado |
gitglossary |
Definiciones precisas de toda la terminología | Cuando dudes de un término |
gitworkflows |
Cómo trabaja el propio proyecto Git con sus ramas | Complemento del módulo 7 |
gitrevisions |
La sintaxis completa de HEAD~3, main@{2}, A...B |
Después del módulo 2 |
gittutorial |
Introducción básica | Ya la superaste |
gitcvs-migration |
Migrar desde sistemas centralizados | Si te toca |
Empieza por gitcore-tutorial. Construye un repositorio desde cero usando solo comandos de fontanería: hash-object, update-index, write-tree, commit-tree. Después de este curso, esa guía te resultará legible y consolidará el modelo mental como ninguna otra cosa.
Las notas de versión
Cada versión nueva de Git trae un fichero de notas. Leerlas cuando actualices es el hábito con mejor retorno para mantenerte al día. Es donde descubrirás la opción que llevas años echando de menos y que existe desde hace tres versiones.
Practicar la fontanería en un repositorio de pruebas
Esto es lo que más consolida. Crea un repositorio desechable y construye un commit sin usar git commit:
mkdir /tmp/laboratorio && cd /tmp/laboratorio && git init
# 1. Crear un blob a partir de contenido
echo "Hola desde la fontanería" | git hash-object -w --stdin# 2. Meterlo en el índice con un nombre
git update-index --add --cacheinfo 100644,9f8c2e1a4b7d0f3c6e9b2a5d8f1c4e7a0b3d6f9c,saludo.txt
# 3. Convertir el índice en un objeto árbol
git write-tree# 4. Crear un commit que apunte a ese árbol
echo "Mi primer commit hecho a mano" | git commit-tree 2a4c8e0f1b3d6a9c2e5f8b1d4a7c0e3f6b9d2a5c# 5. Apuntar la rama a ese commit
git update-ref refs/heads/main 7e1b4d9a2c5f8b0e3d6a9c2f5b8e1d4a7c0f3b6d
# 6. Comprobar que Git lo ve como un repositorio normal
git log --stat
git statusAcabas de hacer a mano lo que git commit hace por ti. Blob → índice → árbol → commit → referencia. Es el modelo de la lección 01-04 ejecutado paso a paso, y es el ejercicio que separa a quien usa Git de quien lo entiende.
Leer el historial de proyectos ajenos
Como vimos en la lección 10-01: clona un proyecto que admires con --filter=blob:none y mira cómo trabaja. Cómo escriben los mensajes, si el historial es lineal, quién integra, cómo estructuran las series de commits. Se aprende muchísimo.
Enseñarlo
El mejor filtro para saber si has entendido algo es explicárselo a alguien. Cuando un compañero se atasque con una divergencia o pierda un commit, ayúdale explicando el modelo, no solo dando el comando. Si eres capaz de dibujar el grafo en una pizarra y señalar dónde estaba el commit perdido, lo has entendido.
- El curso completo, recapitulado
Vamos a cerrar mirando el camino entero.
De dónde partiste
Empezaste sin saber qué es un repositorio. Sin saber qué diferencia hay entre guardar una copia de una carpeta y versionar un proyecto. Diez módulos después:
flowchart TD
M1["1. Entender<br/>Modelo de datos, tres zonas,<br/>hash del contenido"]
M2["2. Construir historia<br/>add, commit, diff, log"]
M3["3. Ramificar<br/>ramas, merge, conflictos"]
M4["4. Colaborar<br/>remotos, fetch, push, seguimiento"]
M5["5. Manipular<br/>rebase, cherry-pick, tags, revert"]
M6["6. Herramientas<br/>hooks, bisect, blame, submódulos"]
M7["7. Proceso<br/>PRs, revisiones, flujos, CI"]
M8["8. Oficio<br/>mensajes, historial limpio,<br/>seguridad, rendimiento"]
M9["9. Rescatar<br/>reset, reflog, corrupción,<br/>depuración"]
M10["10. Operar<br/>casos reales, LFS, escala,<br/>DevOps, futuro"]
M1 --> M2 --> M3 --> M4 --> M5 --> M6 --> M7 --> M8 --> M9 --> M10
Los diez módulos, en una línea cada uno
| Módulo | Qué te llevas |
|---|---|
| 1. Introducción | Que Git es una base de datos de objetos direccionados por contenido, no una herramienta que guarda diferencias. Blob, árbol, commit, etiqueta; las tres zonas; el hash que lo verifica todo |
| 2. Operaciones básicas | El ciclo editar → preparar → confirmar, y que git add -p y git diff --staged convierten confirmar en un acto deliberado |
| 3. Ramas y fusión | Que una rama es un puntero móvil y que fusionar es encontrar el antepasado común. Que un conflicto no es un error: es una decisión que Git no puede tomar por ti |
| 4. Remotos | Que no hay servidor central salvo por acuerdo, y que fetch y pull son operaciones distintas. Autenticación, refspecs, ramas de seguimiento |
| 5. Operaciones avanzadas | Que la historia se puede reescribir antes de publicarla, y la regla de oro: nunca después. rebase, cherry-pick, stash, etiquetas anotadas con SemVer, revert |
| 6. Herramientas | Que Git trae respuestas para "¿cuándo se rompió?" (bisect) y "¿por qué es así?" (blame + el mensaje). Hooks, alias, submódulos, worktree |
| 7. Colaboración | Que el proceso importa tanto como los comandos: propuestas, revisión, flujos comparados e integración continua. Y que el flujo se elige según el equipo |
| 8. Buenas prácticas | El oficio: mensajes que explican el porqué, historial legible, .gitignore y .gitattributes, secretos fuera, y medir el rendimiento antes de tocar |
| 9. Solución de problemas | Que en Git casi nada se pierde de verdad. reset, divergencias, reflog, fsck --lost-found, bundle, y un método de depuración con GIT_TRACE y fontanería |
| 10. Mundo real | Que Git es una pieza de un ecosistema: casos reales, integración con herramientas, LFS, escalado, DevOps. Y criterio para elegir |
Las cuatro ideas que lo sostienen todo
Si dentro de cinco años solo recuerdas cuatro cosas de este curso, que sean estas:
1. El hash del contenido. Todo objeto se identifica por el hash de lo que contiene. De ahí salen la inmutabilidad, la verificación de integridad, la deduplicación automática y el hecho de que reescribir historia siempre cree objetos nuevos en lugar de modificar los existentes.
2. El DAG de commits. Cada commit apunta a sus padres. Ramas, fusiones, antepasados comunes, bisect, rebase, divergencias: todo es este grafo mirado desde ángulos distintos. Cuando algo no cuadre, dibuja el grafo.
3. Las tres zonas. Copia de trabajo, índice y repositorio. Saber en cuál de las tres está cada cosa explica el 90 % de las confusiones. Y recuerda la asimetría que descubrimos en la lección 10-02: lo que nunca pasó por git add es lo único verdaderamente irrecuperable.
4. La regla de oro. Reescribe la historia que no has publicado; no reescribas la que otros ya tienen. Y cuando haya que hacerlo —una migración a LFS, una limpieza de secretos—, avisa, coordina y usa --force-with-lease.
Y una quinta, que es de actitud
Casi nada se pierde de verdad. Lo que se pierde es la calma. Ante un lío, la secuencia es siempre la misma: git status para saber dónde estás, git log --oneline --graph para ver la forma del problema, git reflog para saber por dónde has pasado. Y no ejecutar nada destructivo hasta entender la situación.
gestor-tareas fue solo la excusa
Ana Ferrer en Ubuntu, Bruno Salas en macOS, Carla Vidal en Windows 11 y Diego Rueda con su fork llevan diez módulos resolviendo problemas: el submódulo componentes-ui, los finales de línea que rompían las diferencias, la contraseña que llevaba meses en el historial, el reset --hard a las once de la noche, los tickets GT-NNN que atan cada commit a su porqué.
Nada de eso importa. gestor-tareas no existe. Lo que existe es el modelo mental que te has construido resolviendo sus problemas.
El día que llegues a un repositorio con veinte años de historia, cincuenta mil ficheros, un flujo que no habías visto y una convención de commits que te parecerá rara, no vas a reconocer nada. Pero vas a saber preguntar:
- ¿Qué forma tiene este grafo? →
git log --oneline --graph --all - ¿Cómo trabaja este equipo? →
git log --format=%s -40,git rev-list --count --merges HEAD - ¿Quién integra de verdad? →
git log --format='%cn' -300 | sort | uniq -c | sort -rn - ¿Por qué esta línea es así? →
git blame -w -My el mensaje del commit - ¿Cuándo se rompió? →
git bisect - ¿Dónde estoy y cómo he llegado? →
git status,git reflog - ¿Qué está desplegado? →
git merge-base --is-ancestor,git describe
Esas preguntas funcionan en cualquier repositorio del mundo. Eso es lo que te llevas.
Errores Comunes y Consejos
Error 1: adoptar lo experimental en producción. SHA-256 sin interoperabilidad convierte tu repositorio en una isla. reftable puede romper herramientas externas. Distingue siempre entre "existe" y "es adoptable".
Error 2: creer que el modelo de datos va a cambiar. No va a cambiar. La función de hash puede cambiar; el direccionamiento por contenido, el DAG y las tres zonas, no. No dejes de aprenderlos "por si acaso quedan obsoletos".
Error 3: quedarse en checkout por costumbre. switch y restore son más claros y más seguros, y separan operaciones inofensivas de operaciones destructivas. Cámbiate; y aprende a leer checkout porque está en toda la documentación existente.
Error 4: aceptar mensajes de commit generados sin revisarlos. El asistente ve el diff, no tu cabeza. El porqué solo lo puedes escribir tú, y es lo único que aporta valor dentro de seis meses.
Error 5: ejecutar comandos sugeridos sin entenderlos. Especialmente reset --hard, push --force, clean -fd y filter-repo. Cuanto menos reversible es una operación, más exige entenderla antes.
Error 6: no leer nunca las notas de versión. Es donde está la opción que llevas dos años echando de menos.
Consejo 1: haz git help -g ahora mismo, y lee gitcore-tutorial. Después de este curso te resultará legible, y es lo que consolida el modelo mental definitivamente.
Consejo 2: ten un repositorio de laboratorio. /tmp/laboratorio, desechable. Prueba en él todo lo que no tengas claro antes de hacerlo en un repositorio real. Cuesta cinco segundos crearlo y ha salvado muchas tardes.
Consejo 3: activa hoy lo que no tiene inconvenientes.
git config --global core.commitGraph true
git config --global fetch.writeCommitGraph true
git config --global merge.conflictStyle zdiff3
git config --global rerere.enabled true
git config --global push.default simple
git config --global pull.ff onlyConsejo 4: cuando encuentres un comando nuevo, pregunta lo mismo siempre. ¿Qué objetos crea? ¿Qué referencias mueve? ¿Es reversible? Con esas tres respuestas entiendes cualquier comando de Git.
Consejo 5: enseña lo que sabes. Es el mejor filtro para descubrir lo que creías entender y no entendías.
Ejercicios
Ejercicio 1: separar lo maduro de lo experimental
Un compañero vuelve de una conferencia y propone estos cambios para gestor-tareas. Para cada uno, di si lo adoptarías hoy, y por qué:
A. Migrar el repositorio a SHA-256 "porque SHA-1 está roto".
B. Cambiar el formato de referencias a reftable "porque es más rápido".
C. Activar el commit-graph en todos los repositorios del equipo.
D. Clonar siempre con --filter=blob:none.
E. Prohibir git checkout en el equipo y usar solo switch y restore.
F. Activar sparse-checkout para que cada persona vea solo su área.
Ejercicio 2: construir un commit con fontanería
En un repositorio de pruebas vacío, crea sin usar git add ni git commit:
- Un fichero
notas.txtcon el contenidoAprendiendo la fontanería. - Un segundo fichero
README.mdcon el contenido# Laboratorio. - Un commit que contenga ambos, con el mensaje
Commit construido a mano. - Una rama
mainque apunte a ese commit.
Después, verifica con comandos de porcelana que Git lo ve como un repositorio normal, y explica qué representa cada hash intermedio.
Ejercicio 3: llegar nuevo a un repositorio desconocido
Te incorporas a un proyecto que no conoces: 340.000 commits, 12 años de historia, 28.000 ficheros, 4,2 GB. Nadie tiene tiempo de explicarte nada y tu primera tarea es corregir un error en un fichero que no sabes cuál es.
Escribe la secuencia de comandos que ejecutarías en tu primer día, explicando qué pregunta responde cada uno y en qué orden lo harías.
Soluciones
Solución 1
A. SHA-256 — NO.
El razonamiento de partida es correcto (SHA-1 tiene colisiones demostradas) pero la conclusión no lo es hoy:
- No hay interoperabilidad: un repositorio SHA-256 no puede intercambiar objetos con
git.ejemplo.es, ni con las plataformas, ni con el fork de Diego.gestor-tareasquedaría aislado. - Git ya incorpora detección de colisiones, que mitiga el ataque conocido.
- El riesgo real para un repositorio de aplicación es bajo: fabricar una colisión exige construir ambos contenidos a propósito.
Qué haría: conocerlo, crear un repositorio de pruebas con --object-format=sha256 para ver el modelo, y esperar a que exista interoperabilidad. Si el equipo quiere reforzar la integridad hoy, la respuesta útil es firmar los commits y las etiquetas (08-05), que es efectivo y compatible con todo.
B. reftable — NO.
gestor-tareas tiene unas pocas decenas de referencias. reftable resuelve problemas que aparecen con decenas de miles: coste de escritura, concurrencia, límites del sistema de ficheros. Aquí no aportaría nada medible.
Y tiene un coste: herramientas externas que lean .git/refs/ directamente pueden fallar, y no es el formato por defecto.
Qué haría: conocerlo, y saber que si algún día trabajo en un repositorio con muchísimas referencias, existe. La pregunta correcta es la de la lección 10-04: ¿he medido que esto duele?
C. commit-graph — SÍ, sin dudarlo.
Es la recomendación más fácil de todas:
- Es una caché derivada y regenerable: si se borra, no se pierde nada.
- No cambia el formato de almacenamiento ni el comportamiento de ningún comando.
- Mejora
log,blamey las consultas de alcanzabilidad, y en historiales grandes muchísimo. - No tiene ningún inconveniente conocido.
En gestor-tareas, con 412 commits, la mejora será imperceptible. Pero es un buen hábito global y se nota en cuanto trabajes en algo grande.
D. --filter=blob:none siempre — DEPENDE, con matices.
En gestor-tareas (2 MB): innecesario. Y tiene un coste real: introduce dependencia de la red en operaciones que ahora son locales. git log -p de historia antigua sin conexión fallaría.
En repositorios grandes: sí, claramente.
En CI: sí, casi siempre, combinado con fetch-depth: 0. Es la configuración recomendada de la 10-04.
Qué haría: no como norma universal, sino como regla condicionada: "en repositorios de más de 1 GB o en CI, clon parcial". Y documentarlo.
E. switch y restore — SÍ, con un matiz.
Adoptarlos, sí:
git switchsepara cambiar de rama de descartar ficheros, y esa separación evita pérdidas de trabajo reales.- Exige
--detachexplícito para el HEAD desprendido. git restore --stagedsustituye un uso confuso dereset.- Están consolidados.
El matiz está en "prohibir":
- La documentación existente, las respuestas de internet y los guiones antiguos están llenos de
checkout. Prohibirlo no hace que desaparezca del mundo. - Todo el mundo debe saber leerlo, y entender que
git checkout -- ficheroes destructivo. - Los guiones existentes que funcionan no hay que reescribirlos por gusto.
Qué haría: recomendarlos como opción por defecto en el CONTRIBUTING.md y usarlos en los ejemplos internos, sin prohibir nada.
F. sparse-checkout — NO, rotundamente.
Es el peor de los seis y por dos motivos independientes:
gestor-tareastiene nueve ficheros. No hay nada que dispersar.- La motivación es equivocada. "Que cada uno vea solo su área" es un objetivo organizativo, no de rendimiento.
sparse-checkoutes una optimización de rendimiento, no un mecanismo de control de acceso: cualquiera puede ampliar su cono con un comando, y todo el historial está en su disco. Usarlo para eso da una falsa sensación de separación. - Y tendría un coste real: ficheros que "no existen", búsquedas que no encuentran cosas, y confusión permanente.
Qué haría: explicar que si de verdad hace falta separar accesos, la respuesta es repositorios separados con permisos (10-04), no una optimización de rendimiento mal usada.
Patrón de las seis respuestas: las que adoptaría (C, E, y D condicionada) no tienen inconvenientes o resuelven un problema medido. Las que no (A, B, F) son experimentales, resuelven un problema que no tengo, o se están usando para algo que no son. Es exactamente la tabla de madurez del apartado 7.
Solución 2
Paso 1: crear los blobs.
-w escribe el objeto en la base de datos; sin él solo calcularía el hash. Cada hash es el SHA-1 de ese contenido concreto (precedido de una cabecera con el tipo y el tamaño). Si dos personas crean el mismo contenido en cualquier repositorio del mundo, obtienen el mismo hash: eso es el direccionamiento por contenido.
Comprobar que están ahí:
git cat-file -t c4a8f2e9 # blob
git cat-file -s c4a8f2e9 # tamaño en bytes
git cat-file -p c4a8f2e9 # contenidoPaso 2: construir el índice.
git update-index --add --cacheinfo 100644,c4a8f2e91b6d3a70f5c2e8b14d9a6f0c3b7e2d51,notas.txt
git update-index --add --cacheinfo 100644,7f2b9e4c1a8d5f0b3e6c9a2d5f8b1e4c7a0d3f6b,README.md
git ls-files --stage100644 c4a8f2e91b6d3a70f5c2e8b14d9a6f0c3b7e2d51 0 README.md 100644 7f2b9e4c1a8d5f0b3e6c9a2d5f8b1e4c7a0d3f6b 0 notas.txt
100644 es el modo: fichero normal no ejecutable (100755 sería ejecutable, 040000 un directorio, 120000 un enlace simbólico). El 0 es la etapa del índice: 0 significa "sin conflicto" (las etapas 1, 2 y 3 son la base, lo nuestro y lo suyo durante una fusión, lección 03-05).
Fíjate en un detalle que sorprende: los ficheros no están en el disco. El índice los declara, pero la copia de trabajo está vacía. Es la prueba más contundente de que el índice es una zona independiente, no un reflejo del disco.
Paso 3: convertir el índice en un árbol.
100644 blob 7f2b9e4c1a8d5f0b3e6c9a2d5f8b1e4c7a0d3f6b README.md 100644 blob c4a8f2e91b6d3a70f5c2e8b14d9a6f0c3b7e2d51 notas.txt
El árbol es un directorio: asocia nombres a hashes de objetos. Su propio hash resume todo su contenido, y por eso comparar dos árboles por su hash basta para saber si son idénticos. Es exactamente la propiedad que hace posible el índice disperso de la lección 10-04.
Paso 4: crear el commit.
tree 5e9c2f8b4a1d7e0c3f6b9a2d5e8c1f4b7a0d3e6c author Ana Ferrer <[email protected]> 1785926400 +0200 committer Ana Ferrer <[email protected]> 1785926400 +0200 Commit construido a mano
El commit apunta a un árbol (la foto completa del proyecto) y añade metadatos. No tiene línea parent porque es el commit raíz; si le hubiéramos pasado -p <hash>, la tendría. Esa línea parent es todo el DAG.
Paso 5: apuntar la rama.
git update-ref refs/heads/main b3f7a0c5e2d8b1f4a7c0e3d6b9f2a5c8e1d4b7f0
git symbolic-ref HEAD refs/heads/mainPaso 6: verificar con porcelana.
commit b3f7a0c5e2d8b1f4a7c0e3d6b9f2a5c8e1d4b7f0 (HEAD -> main) Author: Ana Ferrer <[email protected]> Date: Sat Aug 1 12:00:00 2026 +0200 Commit construido a mano README.md | 1 + notas.txt | 1 + 2 files changed, 2 insertions(+)
On branch main Changes to be committed: (use "git restore --staged <file>..." to unstage) deleted: README.md deleted: notas.txt
Ese deleted es correcto y muy instructivo: los ficheros existen en el commit y en el índice, pero no en el disco, porque nunca los escribimos allí. Se materializan con:
Qué representa cada hash:
| Hash | Objeto | Qué es |
|---|---|---|
c4a8f2e9 |
blob | El contenido de notas.txt, sin nombre ni permisos |
7f2b9e4c |
blob | El contenido de README.md |
5e9c2f8b |
tree | El directorio raíz: nombres + modos + hashes de los blobs |
b3f7a0c5 |
commit | Un árbol + autor + fecha + mensaje + padres |
refs/heads/main |
referencia | Un fichero (o entrada reftable) con el hash del commit |
Eso es Git entero. Cuatro tipos de objeto y una referencia. Todo lo demás —ramas, fusiones, rebase, stash, bisect, LFS, GitOps— se construye encima de esto.
Solución 3
El orden importa: primero entender la forma del repositorio, luego cómo trabaja el equipo, y solo al final buscar el fichero.
# ========== FASE 1: CLONAR SIN SUFRIR (10-04) ==========
git clone --filter=blob:none https://git.ejemplo.es/proyecto.git
cd proyecto
git config core.commitGraph true
git config core.fsmonitor true
git config core.untrackedCache true
git commit-graph write --reachable --changed-pathsPor qué: 4,2 GB con clon completo son muchos minutos. El clon parcial trae el grafo completo —que es lo que necesito para investigar— con una fracción de la descarga. Y el commit-graph con --changed-paths es imprescindible: sin él, git log sobre un fichero en 340.000 commits será insufrible.
# ========== FASE 2: LA FORMA DEL REPOSITORIO ==========
git rev-list --count --all # ¿cuánto historial?
git ls-files | wc -l # ¿cuántos ficheros?
git count-objects -vH # ¿cuánto pesa y por qué?
git log -1 --format=%ci # ¿está vivo?
git log --reverse --format=%ci | head -1 # ¿desde cuándo?
# ¿Qué directorios de primer nivel hay?
git ls-tree --name-only HEADPor qué: estos seis comandos dan en un minuto el mapa que nadie tiene tiempo de explicarte: escala, estructura y si el proyecto está activo.
# ========== FASE 3: CÓMO TRABAJA EL EQUIPO ==========
# ¿Historial lineal o con merges? (lección 10-01)
git log --oneline --graph -40
git rev-list --count --merges HEAD
git rev-list --count HEAD
# ¿Qué convención de mensajes usan?
git log --format=%s -50
# ¿Quién escribe y quién integra?
git log --format='%an' -500 | sort | uniq -c | sort -rn | head
git log --format='%cn' -500 | sort | uniq -c | sort -rn | head
# ¿Hay convenciones documentadas?
ls CONTRIBUTING.md README.md .editorconfig .gitattributes 2>/dev/null
cat CONTRIBUTING.md 2>/dev/null
# ¿Qué ramas hay vivas?
git branch -r --sort=-committerdate --format='%(refname:short) %(committerdate:relative)' | head -20
# ¿Cómo versionan?
git tag --sort=-v:refname | head -10
git describe --tagsPor qué: antes de tocar nada hay que saber cómo se hacen las cosas aquí. Una propuesta que ignora la convención de mensajes o el flujo de ramas se rechaza, y aprenderlo del historial es más rápido y más fiable que preguntar.
La proporción de merges y la diferencia autor/committer revelan el modelo de trabajo (lección 10-01). El CONTRIBUTING.md, si existe, se lee entero.
# ========== FASE 4: PREPARAR EL ENTORNO ==========
# ¿Hay LFS? (10-03)
cat .gitattributes 2>/dev/null | grep lfs
git lfs install && git lfs ls-files | head
# ¿Hay submódulos? (06-05)
cat .gitmodules 2>/dev/null
# ¿Cómo se compila y se prueba?
cat README.md | head -60
ls Makefile package.json Containerfile .github/workflows/ 2>/dev/null
# Alias útiles para la investigación (06-04)
git config alias.hist "log --graph --oneline --decorate"
git config alias.quien "log --format='%h %an %ar %s'"# ========== FASE 5: ENCONTRAR EL FICHERO DEL ERROR ==========
# Por el texto del mensaje de error que ve el usuario
git grep -n "El importe no puede ser negativo"
# Si el mensaje está en ficheros de traducción, buscar su clave
git grep -n "error.importe.negativo"
# Por nombre aproximado
git ls-files | grep -i importe
# ¿Se ha tocado esa zona últimamente?
git log --oneline -20 -- src/facturacion/Por qué: git grep busca en el contenido versionado y es mucho más rápido que las herramientas del sistema porque solo mira lo que está en el índice, ignorando artefactos de compilación y ficheros ignorados.
# ========== FASE 6: ENTENDER ANTES DE CAMBIAR (06-03, 09-06) ==========
# ¿Quién escribió esa línea y por qué? Ignorando espaciado y movimientos
git blame -w -M -C -L 120,145 src/facturacion/validador.js
# El mensaje del commit: la intención
git log -1 --format=%B <hash-que-devuelve-blame>
# La historia completa de esa función
git log -L :validarImporte:src/facturacion/validador.js
# ¿Hay commits de reformateo que ensucian el blame?
ls .git-blame-ignore-revs 2>/dev/nullPor qué: este es el paso que separa una corrección de un bucle, y es la lección del ejercicio final del módulo 9. Si el comportamiento es intencionado y está justificado por escrito, cambiarlo sin más rompe algo que alguien pidió, y en dos semanas volverá el mismo ticket en sentido contrario.
# ========== FASE 7: SI EL ERROR ES UNA REGRESIÓN (06-02) ==========
git bisect start
git bisect bad HEAD
git bisect good v3.8.0
git bisect run ./pruebas/reproducir.sh
git bisect reset# ========== FASE 8: TRABAJAR SEGÚN LAS CONVENCIONES ==========
git switch -c corregir-validacion-importe origin/main
# ... corregir, con una prueba de regresión ...
git add -p
git commit # con el formato de mensaje que observé en la fase 3
git diff origin/main...HEAD # revisarme a mí mismo antes de proponer
git push -u origin corregir-validacion-importeResumen del método: clonar sin sufrir, entender la forma, entender el proceso, preparar el entorno, encontrar el sitio, entender la intención antes de cambiar nada, y trabajar según las convenciones observadas.
Ninguno de esos comandos es específico de este proyecto. Funcionan en cualquier repositorio del mundo, y esa es exactamente la capacidad que da este curso.
Conclusión
Lo que se mueve, lo que no, y qué hacer
Ya existe y puedes usarlo hoy: switch y restore en lugar de checkout; el commit-graph y git maintenance; los clones parciales y el índice disperso; fsmonitor y untrackedCache; y Git LFS para los binarios. Todo eso está maduro, y lo que no tiene inconvenientes conviene activarlo ya.
Existe pero aún no es adoptable: SHA-256, que resuelve la debilidad conocida de SHA-1 pero no interopera con el ecosistema; y reftable, que sustituye refs/ y packed-refs por un formato binario mucho mejor a gran escala pero que aún no es el predeterminado. Conócelos; no los adoptes todavía.
Es tendencia, sin fechas: mejor experiencia para monorepos, servidores Git especializados que el cliente no ve, herramientas construidas encima de Git en lugar de sustituirlo —el patrón dominante de veinte años—, y mensajes de error cada vez más útiles.
Los asistentes de IA ayudan a redactar, a recordar y a explorar. No eximen de entender el cambio: el porqué no está en el diff, y las operaciones destructivas exigen comprensión antes que sugerencia. En un mundo donde escribir código cuesta menos, entender el historial y saber recuperarse de un error valen más, no menos.
Y lo que no va a cambiar es lo que aprendiste en el módulo 1: el modelo de datos direccionable por contenido, el DAG de commits, la naturaleza distribuida y las tres zonas. La función de hash puede cambiar; las ideas, no. Por eso este curso no caduca.
El final del curso
Empezaste sin saber qué es un repositorio.
Ahora entiendes que Git es una base de datos de objetos inmutables identificados por el hash de su contenido, organizados en un grafo dirigido acíclico, replicada completa en cada clon. Sabes construir historia con intención, ramificar y fusionar, colaborar con otros a través de un servidor, reescribir lo que aún no has publicado —y solo eso—, investigar cuándo y por qué se rompió algo, trabajar con un proceso de revisión e integración continua, escribir mensajes que sirvan dentro de dos años, mantener los secretos fuera y el rendimiento bajo control, salir de cualquier lío usando el reflog y la fontanería, y operar Git en producción con etiquetas que despliegan y artefactos identificados por el hash del commit.
Sobre todo, tienes un modelo mental con el que razonar sobre situaciones que este curso no ha cubierto. Cuando te encuentres un comando desconocido, sabrás preguntar qué objetos crea y qué referencias mueve. Cuando algo no cuadre, sabrás dibujar el grafo. Cuando alguien entre en pánico, sabrás que casi nada se pierde de verdad.
gestor-tareas fue solo la excusa. Ana, Bruno, Carla y Diego no existen, y sus tickets GT-NNN tampoco. Lo que existe es lo que te queda después de haber resuelto sus problemas: el submódulo que se desincronizó, los finales de línea entre tres sistemas operativos, la contraseña en el historial, el reset --hard de las once de la noche, la migración a LFS que reescribió dos años de commits.
Ese es el equipaje. Es transferible a cualquier repositorio, a cualquier empresa y a cualquier flujo de trabajo que te encuentres, hoy y dentro de diez años.
Ahora ve a un repositorio de verdad —el tuyo, el de tu equipo, o el de un proyecto abierto que admires— y úsalo. Ejecuta git log --oneline --graph --all y mira la forma que tiene. Lee git help gitcore-tutorial. Crea un repositorio de laboratorio en /tmp y rompe cosas a propósito para practicar el rescate.
Y cuando un compañero pierda un commit y se le ponga cara de pánico, siéntate a su lado, escribe git reflog, y explícale por qué nada se ha perdido.
Ahí es donde se comprueba que has aprendido Git.
Dominando Git: De Principiante a Avanzado
Módulo 1: Introducción a Git
- ¿Qué es Git?
- Instalando Git
- Terminología Básica de Git
- El Modelo de Datos de Git
- Configurando Git
- Configuración Inicial
Módulo 2: Operaciones Básicas de Git
- Creando un Repositorio
- Clonando un Repositorio
- Flujo de Trabajo Básico de Git
- Preparando y Confirmando Cambios
- Inspeccionando Cambios con git diff
- Visualizando el Historial de Confirmaciones
Módulo 3: Ramas y Fusión
- Entendiendo las Ramas
- Creando y Cambiando Ramas
- Fusionando Ramas
- Estrategias de Fusión
- Resolviendo Conflictos de Fusión
- Gestión de Ramas
Módulo 4: Trabajando con Repositorios Remotos
- Entendiendo los Repositorios Remotos
- Agregando un Repositorio Remoto
- Autenticación con Repositorios Remotos
- Obteniendo y Extrayendo Cambios
- Enviando Cambios
- Rastreando Ramas
Módulo 5: Operaciones Avanzadas de Git
- Rebase
- Rebase Interactivo
- Cherry-Picking de Confirmaciones
- Guardando Cambios Temporales
- Etiquetando Confirmaciones
- Revirtiendo Confirmaciones
Módulo 6: Herramientas y Técnicas de Git
- Usando Git Hooks
- Git Bisect
- Git Blame
- Git Log y Alias
- Submódulos de Git
- Múltiples Copias de Trabajo con git worktree
Módulo 7: Estrategias de Colaboración y Flujo de Trabajo
- Forks y Pull Requests
- Revisiones de Código con Git
- Flujo de Trabajo Git Flow
- GitHub Flow
- Trunk Based Development
- Integración Continua con Git
Módulo 8: Mejores Prácticas y Consejos de Git
- Escribiendo Buenos Mensajes de Confirmación
- Manteniendo un Historial Limpio
- Ignorando Archivos con .gitignore
- Atributos de Fichero con .gitattributes
- Mejores Prácticas de Seguridad
- Consejos de Rendimiento
Módulo 9: Solución de Problemas y Depuración
- Problemas Comunes de Git
- Deshaciendo Cambios
- Resolviendo Divergencias con el Remoto
- Recuperando Confirmaciones Perdidas
- Tratando con Repositorios Corruptos
- Técnicas Avanzadas de Depuración
