La v0.19 funciona y aguanta los errores, pero para llegar hasta ella has tocado almacen.py, modelo.py, interfaz.py y __main__.py a la vez. Si mañana descubres que la validación de dias rompe algo, ¿cómo vuelves atrás? ¿Y cómo sabes exactamente qué cambiaste el martes? La respuesta que usa todo el mundo desde hace veinte años es Git: un sistema que guarda la historia completa del proyecto, permite volver a cualquier punto anterior, deja probar ideas sin miedo y hace posible que varias personas trabajen sobre el mismo código sin pisarse. Esta lección te enseña Git desde cero: el modelo mental de las tres zonas, los comandos del día a día, cómo se escribe un buen mensaje de commit, qué no se versiona nunca, cómo se abren y se fusionan ramas —y cómo se resuelve un conflicto sin pánico—, cómo se deshace lo hecho y qué son GitHub y GitLab. Al final, TareaFácil vivirá en un repositorio con su historial.

Contenido

  1. El problema: proyecto_final_v3_bueno_definitivo
  2. Instalar y configurar Git
  3. El modelo mental: tres zonas
  4. Los comandos del día a día
  5. Qué es un commit y cómo se escribe su mensaje
  6. .gitignore: lo que nunca se versiona
  7. Ramas: trabajar sin miedo
  8. Conflictos: qué son y cómo se resuelven
  9. Deshacer: restore, revert y reset
  10. Remotos: GitHub, GitLab y los pull requests
  11. Etiquetas y versionado
  12. TareaFácil v0.20: el proyecto bajo Git
  13. Errores comunes y consejos
  14. Ejercicios
  15. Conclusión

  1. El problema: proyecto_final_v3_bueno_definitivo

Todo el mundo ha vivido esta escena: una carpeta con informe.docx, informe_v2.docx, informe_v2_revisado.docx, informe_final.docx e informe_final_BUENO.docx. Con código es peor, porque además hay que saber qué línea cambió entre dos versiones y por qué. Copiar carpetas falla en todo: ocupa espacio, no dice qué cambió, no explica el motivo, no permite mezclar el trabajo de dos personas y no hay forma de recuperar solo una parte.

Un sistema de control de versiones (VCS) resuelve exactamente eso: guarda instantáneas del proyecto con su fecha, su autor y una explicación, y permite comparar, volver atrás y combinar cambios. Hay dos familias. Los centralizados (Subversion, CVS) guardan la historia en un único servidor: sin conexión no se puede trabajar y si el servidor cae, se acabó. Los distribuidos (Git, Mercurial) dan a cada persona una copia completa del historial en su propio ordenador: se trabaja sin conexión, cada clon es una copia de seguridad y solo se sincroniza con el servidor cuando interesa. Git, creado en 2005 para el desarrollo de Linux, es hoy el estándar absoluto.

  1. Instalar y configurar Git

Git se descarga de git-scm.com (en Linux suele venir instalado o se instala con el gestor de paquetes). Para comprobarlo y configurarlo, tres órdenes que solo se ejecutan una vez por ordenador:

git --version                                     # comprueba que esta instalado
git config --global user.name "Marta Ruiz"        # quien firma los commits
git config --global user.email "[email protected]"
git config --global init.defaultBranch main       # nombre de la rama inicial
git config --list                                 # ver toda la configuracion

El nombre y el correo no son un trámite: quedan grabados para siempre en cada commit que hagas, y son lo que aparece cuando alguien pregunta quién tocó una línea. La opción --global los aplica a todos tus proyectos; sin ella, solo al repositorio actual, que es lo que se usa cuando el correo del trabajo y el personal deben separarse.

  1. El modelo mental: tres zonas

Esta es la parte que más cuesta al principio, y todo se aclara si entiendes que un cambio pasa por tres zonas antes de quedar guardado en la historia:

  • Directorio de trabajo: tus ficheros tal y como están ahora en el disco.
  • Zona de preparación (staging area o index): la lista de cambios que quieres incluir en el próximo commit. Es el gran acierto de Git: te deja elegir qué entra y qué no.
  • Repositorio: la carpeta .git, donde viven todos los commits ya confirmados.
flowchart LR
    A[Directorio de trabajo] -->|git add| B[Zona de preparacion]
    B -->|git commit| C[Repositorio local]
    C -->|git push| D[Repositorio remoto]
    D -->|git pull| A
    B -->|git restore --staged| A
Zona Qué contiene Cómo se entra Cómo se sale
Directorio de trabajo Los ficheros del disco Editando git restore fichero
Zona de preparación Lo que irá al próximo commit git add git restore --staged
Repositorio La historia ya confirmada git commit git revert

Gracias a la zona intermedia puedes haber tocado cinco ficheros y confirmar solo dos, dejando el resto para otro commit con su propia explicación. Esa disciplina —un commit, una idea— es lo que convierte el historial en algo útil de leer.

  1. Los comandos del día a día

Con estos diez comandos se cubre el 95 % del trabajo:

Comando Qué hace
git init Crea el repositorio en la carpeta actual (aparece .git)
git status El más usado: qué has cambiado y en qué zona está
git add fichero Pasa un cambio a la zona de preparación (git add . para todo)
git commit -m "mensaje" Confirma lo preparado como una instantánea
git log --oneline Historial compacto, un commit por línea
git diff Qué has cambiado y aún no has preparado
git diff --staged Qué hay preparado para el próximo commit
git show <hash> Todo el detalle de un commit concreto
git restore fichero Descarta los cambios no guardados de ese fichero
git rm fichero Borra el fichero y registra el borrado

Así se ve una sesión real en TareaFácil:

$ git status
On branch main
Changes not staged for commit:
        modified:   tareafacil/almacen.py
        modified:   README.md

$ git add tareafacil/almacen.py          # solo este: el README ira en otro commit
$ git commit -m "Sobrevivir a un tareas.json corrupto o ausente"
[main 4f2a9c1] Sobrevivir a un tareas.json corrupto o ausente
 1 file changed, 12 insertions(+), 3 deletions(-)

$ git log --oneline
4f2a9c1 Sobrevivir a un tareas.json corrupto o ausente
9b1e73d Documentar el paquete y anadir README
a07c5e2 Version inicial de TareaFacil

Fíjate en el detalle importante: se ha preparado un solo fichero aunque había dos modificados. El commit resultante cuenta una historia limpia, y el README.md esperará a su propio commit. git status es tu brújula: ejecútalo antes y después de cada operación hasta que el modelo mental te salga solo. Y antes de confirmar, git diff te enseña exactamente qué vas a guardar:

$ git diff
diff --git a/tareafacil/almacen.py b/tareafacil/almacen.py
@@ -38,7 +38,10 @@ def cargar_tareas(ruta=RUTA_JSON):
-    with open(ruta, encoding="utf-8") as f:
-        return Agenda.from_dict(json.load(f))
+    try:
+        with open(ruta, encoding="utf-8") as f:
+            return Agenda.from_dict(json.load(f))
+    except FileNotFoundError:
+        return Agenda()

Las líneas con - son las que desaparecen y las que llevan +, las que entran; la cabecera @@ -38,7 +38,10 @@ indica en qué parte del fichero estamos. Leer un diff es la forma más rápida de revisar tu propio trabajo antes de confirmarlo.

  1. Qué es un commit y cómo se escribe su mensaje

Un commit es cuatro cosas a la vez: una instantánea del proyecto completo, un mensaje que explica el porqué, un autor con su fecha y un padre, el commit anterior. Esa cadena de padres es la historia, y cada commit se identifica con un hash, un código como 4f2a9c1 que sirve para referirse a él en cualquier comando.

El mensaje es la parte que más se descuida y la que más valor aporta dentro de seis meses. Las reglas aceptadas en todos los proyectos son tres: asunto corto (menos de 50 caracteres), en imperativo y sin punto final —«Añade», «Corrige», «Elimina», como si completaras la frase «este commit...»—, y si hace falta, una línea en blanco y un cuerpo que explique el porqué, nunca el qué (el qué ya lo dice el diff).

Mensaje malo Por qué Mensaje bueno
cambios No dice nada Anade validacion de prioridad en Tarea
arreglado ¿Qué estaba roto? Corrige el progreso que superaba el 100%
asdf Ruido puro Extrae pedir_prioridad a interfaz.py
Cambié interfaz.py y almacen.py y también... Demasiadas cosas juntas Dos commits, uno por idea
git commit -m "Apartar el JSON corrupto en lugar de perderlo" -m "Un fichero danado paraba el arranque. Ahora se renombra a .json.bak y se
sigue con una agenda vacia, para que Marta pueda revisarlo despues."

El segundo -m crea el cuerpo. Ese texto es exactamente lo que agradecerás cuando dentro de un año te preguntes por qué existe un fichero .json.bak en la carpeta.

  1. .gitignore: lo que nunca se versiona

No todo lo que hay en la carpeta debe entrar en el repositorio. Un fichero llamado .gitignore, en la raíz del proyecto, dice qué debe ignorar Git:

# Entorno virtual y cache de Python
.venv/
__pycache__/
*.pyc

# Datos locales y registros: cada uno tiene los suyos
tareas.json
tareas.json.bak
tareas.csv
tareafacil.log

# Configuracion del editor y del sistema
.vscode/
.DS_Store

# NUNCA credenciales
.env
*.key

Las cuatro categorías son siempre las mismas: lo que se puede regenerar (__pycache__, el .venv, que se reconstruye con requirements.txt), los datos de cada usuario (el tareas.json de Marta no es el de Luis), la configuración personal del editor y, sobre todo, los secretos.

Esto último merece un aviso serio: no subas nunca contraseñas, claves de API ni datos personales a un repositorio. Y no basta con borrarlas después en un commit posterior, porque siguen estando en el historial y cualquiera puede recuperarlas; si el repositorio es público, hay robots que rastrean claves filtradas en cuestión de minutos. La regla es simple: las credenciales van en un fichero .env ignorado desde el principio, y si alguna se escapa, se revoca inmediatamente. Lo mismo vale para los datos personales de clientes reales.

  1. Ramas: trabajar sin miedo

Una rama es una línea de desarrollo paralela. Sirve para trabajar en algo —una funcionalidad nueva, un experimento, una corrección— sin tocar la versión que funciona, y para que dos personas avancen a la vez sin estorbarse. En Git son tan baratas que se usan constantemente.

git branch                          # ver las ramas (la actual lleva *)
git switch -c exportar-pdf          # crear una rama y cambiar a ella
... trabajas y haces commits ...
git switch main                     # volver a la principal
git merge exportar-pdf              # traer aqui el trabajo de la rama
git branch -d exportar-pdf          # borrarla cuando ya esta fusionada

git switch es la forma moderna; verás mucho git checkout en documentación antigua, que hace lo mismo (y más cosas, lo que lo hacía confuso).

gitGraph
    commit id: "Version inicial"
    commit id: "Documentar paquete"
    branch exportar-pdf
    commit id: "Anadir exportacion PDF"
    commit id: "Ajustar margenes"
    checkout main
    commit id: "Corregir progreso"
    merge exportar-pdf
    commit id: "Version 0.20"

En el diagrama, main siguió avanzando mientras la rama exportar-pdf hacía su trabajo, y el merge unió las dos historias en un commit de fusión. Mientras la rama existía, main estuvo siempre en un estado funcional: eso es lo que significa «trabajar sin miedo».

  1. Conflictos: qué son y cómo se resuelven

Un conflicto aparece cuando dos ramas han cambiado las mismas líneas del mismo fichero y Git no puede decidir cuál vale. No es un error ni una catástrofe: es Git pidiéndote que decidas tú. Al fusionar verás algo así:

Auto-merging tareafacil/interfaz.py
CONFLICT (content): Merge conflict in tareafacil/interfaz.py
Automatic merge failed; fix conflicts and then commit the result.

Y dentro del fichero, las líneas en disputa aparecen marcadas:

<<<<<<< HEAD
ANCHO = 52                      # lo que hay en la rama actual (main)
=======
ANCHO = 60                      # lo que trae la rama que fusionas
>>>>>>> exportar-pdf

La resolución tiene tres pasos, y ninguno es misterioso: abre el fichero y deja el contenido correcto, borrando las tres líneas de marcas (<<<<<<<, =======, >>>>>>>); prepara el fichero con git add tareafacil/interfaz.py; y cierra la fusión con git commit. Si te has liado, git merge --abort deja todo como estaba antes de intentarlo. El consejo práctico para tener pocos conflictos: ramas cortas, commits pequeños y fusionar a menudo.

  1. Deshacer: restore, revert y reset

Git permite deshacer casi cualquier cosa, pero no todas las formas son igual de seguras:

Orden Qué hace ¿Segura en trabajo compartido?
git restore fichero.py Descarta cambios no confirmados de ese fichero
git restore --staged fichero.py Lo saca de la zona de preparación
git revert <hash> Crea un commit nuevo que deshace otro anterior Sí: la recomendada
git reset --soft <hash> Mueve la rama atrás, conservando los cambios Solo en local
git reset --hard <hash> Mueve la rama atrás y borra los cambios Peligrosa
$ git log --oneline
e5f80b2 Mostrar el resumen de tareas por responsable
4f2a9c1 Sobrevivir a un tareas.json corrupto o ausente

$ git revert 4f2a9c1                # deshace ese commit, sin borrarlo
$ git log --oneline
8d10c4a Revert "Sobrevivir a un tareas.json corrupto o ausente"
e5f80b2 Mostrar el resumen de tareas por responsable
4f2a9c1 Sobrevivir a un tareas.json corrupto o ausente

Fíjate en que el commit original sigue ahí: revert no lo borra, añade encima otro que aplica exactamente los cambios contrarios. La diferencia clave es esa: revert añade historia, reset la reescribe. Si el commit ya está compartido con otras personas, reescribir la historia les rompe el repositorio, así que la respuesta correcta es casi siempre git revert. Y git reset --hard merece un respeto especial: borra trabajo sin preguntar y no hay papelera. Úsalo solo en tu ordenador, sobre commits que nadie más ha visto, y después de comprobar con git status que no te dejas nada.

  1. Remotos: GitHub, GitLab y los pull requests

Un remoto es una copia del repositorio alojada en otro sitio, normalmente en un servicio como GitHub o GitLab. Sirve de copia de seguridad, de punto de encuentro del equipo y de escaparate: hoy un repositorio público es parte del currículum de cualquier programador.

Comando Qué hace
git clone <url> Descarga un repositorio completo con todo su historial
git remote add origin <url> Conecta tu repositorio local con uno remoto (origin es el nombre habitual)
git push -u origin main Sube tus commits al remoto (la primera vez, con -u)
git fetch Trae los cambios del remoto sin mezclarlos con tu trabajo
git pull fetch + merge: los trae y los integra en tu rama

Y una pieza más que verás en cuanto trabajes con otros: un pull request (o merge request en GitLab) es una petición formal de fusionar tu rama en la principal. Abre una página donde el equipo ve los cambios línea a línea, comenta y aprueba antes de integrar. Es el mecanismo con el que se revisa el código en prácticamente todos los proyectos, y funciona exactamente sobre las ramas que ya sabes crear.

  1. Etiquetas y versionado

Una etiqueta (tag) es un nombre permanente para un commit concreto, y su uso natural es marcar las versiones publicadas —justo los números que vienes viendo desde 08-01:

git tag -a v0.20 -m "Proyecto bajo control de versiones"
git tag                            # listar las etiquetas
git show v0.20                     # ver a que commit corresponde
git push origin v0.20              # las etiquetas se suben aparte

A diferencia de una rama, una etiqueta no se mueve: v0.20 señalará ese commit para siempre, así que dentro de un año podrás recuperar exactamente el código que se entregó. Aquí es donde el versionado semántico de 08-01 se hace tangible: v0.19, v0.20, v1.0 dejan de ser una convención mental para convertirse en puntos concretos y recuperables del historial.

  1. TareaFácil v0.20: el proyecto bajo Git

Vamos a poner el paquete bajo control de versiones desde cero, con tres commits que cuentan una historia y una rama para una mejora:

$ cd ~/proyectos/tareafacil
$ git init
Initialized empty Git repository in /home/marta/proyectos/tareafacil/.git/

$ printf '.venv/\n__pycache__/\n*.pyc\ntareas.json\ntareafacil.log\n' > .gitignore
$ git add .gitignore
$ git commit -m "Anadir .gitignore con entorno, cache y datos locales"

$ git add tareafacil/ README.md
$ git status                        # comprobar que NO entra tareas.json
$ git commit -m "Anadir el paquete tareafacil documentado (v0.18)"

$ git add tareafacil/almacen.py tareafacil/modelo.py tareafacil/interfaz.py
$ git commit -m "Gestionar errores de carga y de validacion (v0.19)"
$ git tag -a v0.19 -m "El programa deja de romperse"

El orden no es casual: el .gitignore va primero, antes de añadir nada más, para que el tareas.json con los datos reales no entre nunca en el historial. Ahora, la mejora en una rama:

$ git switch -c resumen-por-responsable
$ ... editar agenda.py e interfaz.py ...
$ git add tareafacil/agenda.py tareafacil/interfaz.py
$ git commit -m "Mostrar el resumen de tareas por responsable en el menu"
$ git switch main
$ git merge resumen-por-responsable
Updating 7c3d1a9..e5f80b2
Fast-forward
 tareafacil/agenda.py  | 14 ++++++++++++++
 tareafacil/interfaz.py |  8 ++++++++
$ git branch -d resumen-por-responsable

$ git log --oneline --graph
* e5f80b2 (HEAD -> main) Mostrar el resumen de tareas por responsable
* 7c3d1a9 (tag: v0.19) Gestionar errores de carga y de validacion (v0.19)
* 9b1e73d Anadir el paquete tareafacil documentado (v0.18)
* a07c5e2 Anadir .gitignore con entorno, cache y datos locales

Fast-forward significa que main no había avanzado mientras trabajabas, así que Git simplemente adelantó el puntero: ni siquiera hizo falta un commit de fusión. TareaFácil v0.20 tiene ya historial, autoría, mensajes que explican el porqué, una etiqueta y la capacidad de volver a cualquier punto anterior.

Errores Comunes y Consejos

  • Subir el entorno virtual o los datos. Crea el .gitignore antes del primer git add .; sacar algo del historial después es mucho más incómodo.
  • Subir contraseñas o datos personales. Quedan en el historial aunque los borres luego. Usa un .env ignorado y revoca cualquier clave que se escape.
  • Commits gigantes. «Cambios de la semana» con 40 ficheros no sirve para nada. Un commit, una idea.
  • Mensajes vacíos (cambios, fix, asdf). Escribe en imperativo qué hace el commit y, si no es obvio, por qué.
  • Trabajar siempre en main. Para cualquier cosa que no sea trivial, abre una rama: si sale mal, la borras y no ha pasado nada.
  • Usar git reset --hard para «limpiar». Borra trabajo sin preguntar. En algo compartido, usa git revert.
  • Consejo: git status y git diff antes de cada commit. Mirar lo que estás a punto de confirmar evita el 90 % de los sustos y de los ficheros colados por error.

Ejercicios

Ejercicio 1: Mensajes de commit

Reescribe estos cuatro mensajes siguiendo las reglas vistas, e indica en cuál de ellos partirías el trabajo en más de un commit:

  1. arreglos varios
  2. Se ha modificado el fichero interfaz.py para que ahora el menú muestre también la opción de exportar y de paso he corregido un fallo en el cálculo del progreso
  3. wip
  4. añadida función

Ejercicio 2: .gitignore para un proyecto nuevo

Marta arranca informes, un programa que lee el tareas.json de TareaFácil, guarda plantillas en plantillas/, genera PDF en salida/, usa un entorno virtual .venv y necesita una clave de la API de correo. Escribe su .gitignore explicando cada línea y di qué debe versionarse.

Ejercicio 3: Una rama con conflicto

Describe, comando a comando, esta situación completa: creas la rama menu-corto, cambias ANCHO = 52 por ANCHO = 48 en interfaz.py y haces commit; mientras tanto, en main, otra persona cambió esa misma línea a ANCHO = 60 y confirmó. Fusiona, resuelve el conflicto dejando ANCHO = 48 y cierra la operación.

Soluciones

Solución 1.

Original Reescrito
arreglos varios Corrige el redondeo del progreso en Tarea.progreso
El largo del punto 2 Dos commits: Anade la opcion de exportar al menu y Corrige el calculo del progreso
wip Extrae pedir_prioridad a interfaz.py (y si de verdad está a medias, no se confirma en main: se queda en su rama)
añadida función Anade resumen_por_responsable a Agenda

El caso interesante es el segundo: mezcla dos ideas independientes, y eso tiene una consecuencia práctica muy concreta. Si mañana hay que deshacer la corrección del progreso, con un solo commit se llevaría por delante también la opción del menú. Un commit por idea es lo que hace que git revert sea una operación quirúrgica y no una demolición.

Solución 2.

# Entorno virtual: se reconstruye con requirements.txt
.venv/

# Cache de Python: se regenera sola
__pycache__/
*.pyc

# Datos de entrada y resultados: cada usuario tiene los suyos
tareas.json
salida/

# Credenciales: NUNCA al repositorio
.env

Sí debe versionarse todo lo que es el proyecto y no un producto suyo: el código fuente, el README.md, el requirements.txt, la carpeta plantillas/ —porque las plantillas son parte del programa, no un resultado— y un .env.example con las claves vacías, que documenta qué variables hacen falta sin revelar ninguna. La regla que resume todo: versiona lo que escribes; ignora lo que se genera, lo que es personal y lo que es secreto.

Solución 3.

$ git switch -c menu-corto
$ ... cambiar ANCHO a 48 en tareafacil/interfaz.py ...
$ git add tareafacil/interfaz.py
$ git commit -m "Reducir el ancho del menu a 48 columnas"

$ git switch main                       # main ya tiene el cambio a 60
$ git merge menu-corto
Auto-merging tareafacil/interfaz.py
CONFLICT (content): Merge conflict in tareafacil/interfaz.py

$ ... abrir el fichero, dejar solo 'ANCHO = 48' y borrar <<<<<<<, ======= y >>>>>>>
$ git add tareafacil/interfaz.py        # 'add' es la forma de decir "resuelto"
$ git commit -m "Fusionar menu-corto: se mantiene ANCHO en 48"
$ git branch -d menu-corto

Tres detalles que conviene fijar. El conflicto no ha roto nada: hasta que no confirmes, el repositorio está en un estado intermedio del que se sale con git commit o del que se huye con git merge --abort. git add es la señal de «ya está resuelto», no una operación distinta. Y hay que revisar el fichero entero antes de confirmar, porque es fácil dejarse una marca >>>>>>> olvidada que convertiría el módulo en código con error de sintaxis.

Conclusión

Un sistema de control de versiones sustituye las carpetas _v3_bueno_definitivo por un historial real: instantáneas con fecha, autor y explicación, con la posibilidad de comparar, volver atrás y combinar el trabajo de varias personas. Git es distribuido, así que cada clon contiene la historia completa. Se configura una vez con git config --global user.name y user.email, que firman todos tus commits. Su modelo mental son tres zonas —directorio de trabajo, zona de preparación y repositorio—, y el recorrido de un cambio es siempre addcommit → (push). El día a día cabe en diez comandos: init, status, add, commit -m, log --oneline, diff, show, restore y rm, con git status como brújula permanente. Un commit es instantánea, mensaje, autor y padre, y su mensaje se escribe en imperativo, corto y explicando el porqué, con un commit por idea. El .gitignore deja fuera el entorno virtual, __pycache__, los datos locales, la configuración del editor y —esto sin excepciones— las credenciales, que permanecen en el historial aunque las borres después. Las ramas (branch, switch -c, merge, -d) permiten trabajar sin tocar la versión buena, y un conflicto no es una catástrofe: se edita el fichero dejando el contenido correcto, se borran las marcas <<<<<<<, ======= y >>>>>>>, se hace git add y se confirma. Para deshacer, restore con lo no confirmado y revert con lo ya confirmado —añade historia en vez de reescribirla—, dejando reset --hard para lo estrictamente local. Los remotos (clone, remote add, push, pull, fetch) llevan el proyecto a GitHub o GitLab, donde un pull request permite revisar el código antes de integrarlo. Y las etiquetas (git tag -a v1.0) fijan para siempre los números del versionado semántico.

TareaFácil es ahora la v0.20: un repositorio con su .gitignore, tres commits que explican qué se hizo y por qué, una etiqueta v0.19 y una rama fusionada y borrada. Puedes experimentar sin miedo, porque nada se pierde. Y sin embargo, hay algo que Git no puede decirte: si el código que acabas de confirmar funciona. Cada vez que tocas Agenda.ordenadas() o la validación de Tarea, sigues arrancando el menú y probando opciones a mano, una por una, rezando por no haber roto nada de lo que ya funcionaba. Eso es lento, es aburrido y se hace mal. En Pruebas automatizadas construirás la red de seguridad que faltaba: una carpeta tests/ con pruebas que comprueban solas, en un segundo, que todo sigue en su sitio.

Fundamentos de la Programación

Módulo 1: Introducción a la Programación

Módulo 2: Conceptos Básicos

Módulo 3: Estructuras de Control

Módulo 4: Funciones y Procedimientos

Módulo 5: Estructuras de Datos

Módulo 6: Algoritmos Básicos

Módulo 7: Objetos y Organización del Código

Módulo 8: Buenas Prácticas y Herramientas

Módulo 9: Proyecto Final y Cierre del Curso

© Copyright 2026. Todos los derechos reservados