Centro de Aprendizaje
Git & GitHub
Tomar Quiz →
 curso-git-github --niveles=3 --modulos=7

Git & GitHub Curso Completo

Un recorrido directo y práctico, organizado en tres niveles: fácil para empezar, medio para colaborar y experto para destacar. El curso cierra con un módulo de temas adicionales: SSH, plantillas de issues y PRs, y cómo escribir READMEs que se vean profesionales.

3
Niveles
7
Módulos
~2h
Lectura
+
Temas extra
Índice del curso
Nivel Fácil Lo que necesitas para usar Git todos los días.
Módulo 01 Fácil

Fundamentos de Git

Qué es Git, cómo se configura y cuál es el ciclo básico que vas a repetir miles de veces.

¿Qué es Git?

Git es un sistema de control de versiones distribuido: cada desarrollador tiene una copia completa del historial del proyecto en su máquina. Eso permite trabajar offline, crear ramas locales sin afectar a nadie y tener redundancia natural.

Distribuido vs centralizado: en sistemas centralizados (SVN) hay un solo servidor con el historial. En Git, cada clon es un repositorio completo.

Inicializar un repositorio

git init

Esto crea una carpeta oculta .git con toda la estructura interna del repositorio.

Configuración inicial

Antes del primer commit, configura tu identidad globalmente:

git config --global user.name "Tu Nombre"
git config --global user.email "tu@email.com"

Los estados de un archivo

EstadoDescripción
untrackedGit no lo conoce aún
unmodifiedSin cambios respecto al último commit
modifiedModificado pero sin preparar
stagedPreparado para el próximo commit

El ciclo básico

git status                    # qué cambió
git add archivo.py            # preparar para commit
git commit -m "feat: ..."     # confirmar
git log                       # revisar historial

Variantes útiles de git add

  • git add . — agrega todo lo del directorio actual
  • git add --all — agrega todos los cambios del repo (incluye eliminaciones)
  • git add -p — interactivo, agrega cambios por trozos

Ver diferencias

git diff              # working tree vs staging
git diff --staged     # staging vs último commit

Ignorar archivos: .gitignore

node_modules/
.env
*.log
__pycache__/
.DS_Store
Tip: si un archivo ya estaba rastreado antes de añadirlo a .gitignore, debes eliminarlo del índice con git rm --cached archivo.
Qué deberías poder hacer ahora
  • Inicializar un repo y configurar tu identidad
  • Hacer commits con un buen mensaje
  • Saber qué cambió en tu working tree y en staging
  • Ignorar archivos correctamente con .gitignore
Módulo 02 Fácil

Ramas (branches)

Las ramas son lo que hace a Git tan potente. Son baratas, instantáneas y debes usarlas todo el tiempo.

¿Qué es una rama?

Una rama en Git es simplemente un puntero móvil que apunta a un commit. No es una copia del código ni un directorio: es un archivo de pocos bytes con el hash del último commit de esa línea de desarrollo.

Por eso crear y cambiar ramas es prácticamente instantáneo, incluso en repos enormes.

Listar ramas

git branch          # ramas locales
git branch -a       # locales + remotas
git branch -v       # con el último commit de cada una

Crear y cambiar de rama

# Forma clásica
git checkout -b feature-login

# Forma moderna (Git 2.23+)
git switch -c feature-login
checkout vs switch: desde Git 2.23 existe git switch (solo ramas) y git restore (solo archivos). Son más claros que el viejo checkout, que hacía las dos cosas.

Cambiar a una rama existente

git switch main

Eliminar ramas

git branch -d feature-login   # solo si está fusionada
git branch -D feature-login   # forzar eliminación
Cuidado: -D elimina la rama incluso si tiene commits únicos. Si esos commits no estaban en otro lado, los pierdes (aunque git reflog puede salvarte — lo veremos en el módulo 6).

Renombrar la rama actual

git branch -m nuevo-nombre
Qué deberías poder hacer ahora
  • Crear, listar y eliminar ramas locales
  • Cambiar entre ramas sin perder cambios
  • Entender que una rama es solo un puntero, no una copia
Módulo 03 Fácil

Trabajo con remotos

Sincronizarte con un servidor (GitHub, GitLab, etc.) sin perder cambios en el camino.

Clonar un repositorio

git clone https://github.com/usuario/repo.git

Esto descarga el repo completo: historial, ramas remotas y el remote origin configurado.

Ver y gestionar remotos

git remote -v                              # listar remotos
git remote add origin URL                  # añadir remoto
git remote set-url origin nueva-url        # cambiar URL

Sincronizar: fetch vs pull

ComandoQué hace
git fetchDescarga referencias remotas SIN modificar tu working tree
git pullfetch + merge automático
git pull --rebasefetch + rebase (historial lineal)
Tip: hacer git fetch antes de cualquier operación importante te permite ver qué cambió en el remoto sin sorpresas. Es la forma más segura de sincronizar.

Empujar cambios

git push                          # push a la rama tracked
git push -u origin feature-login  # primera vez, establece tracking

main vs master

Desde 2020, GitHub usa main en vez de master como nombre por defecto. Adopta este cambio en proyectos nuevos.

Qué deberías poder hacer ahora
  • Clonar un repo y configurar remotos
  • Empujar tu rama por primera vez con -u
  • Saber cuándo usar fetch y cuándo pull
Nivel Medio Para colaborar bien con otros y mantener un historial limpio.
Módulo 04 Medio

Merge & Rebase

Integrar trabajo entre ramas. Aquí es donde Git brilla — y donde la mayoría se asusta.

git merge

Combina los cambios de una rama en otra. Hay dos escenarios:

Fast-forward

Si la rama destino no tuvo commits nuevos desde que se creó la rama feature, Git solo mueve el puntero hacia adelante. No crea un commit de merge.

git switch main
git merge feature-login

Merge commit

Si ambas ramas tienen commits nuevos, Git crea un commit especial con dos padres que registra la fusión.

git merge --no-ff feature-login   # forzar merge commit aunque sea ff

git rebase

Rebase "reescribe" la historia: coloca tus commits sobre la punta de otra rama, generando nuevos hashes.

git switch feature-login
git rebase main

El resultado es un historial lineal, sin merge commits, como si hubieras desarrollado tu feature partiendo de la última versión de main.

Regla de oro del rebase: nunca hagas rebase de commits que ya empujaste a una rama compartida. Reescribir historial público causa caos en el equipo.

pull --rebase

Mejor alternativa a git pull en muchos casos:

git pull --rebase

Tus commits locales se aplican encima de los nuevos del remoto, evitando merge commits cuando solo querías sincronizar.

Resolución de conflictos

Cuando Git no puede fusionar automáticamente, marca el conflicto en el archivo:

<<<<<<< HEAD
versión actual de tu rama
=======
versión que viene de la otra rama
>>>>>>> feature-login

Pasos para resolver:

  1. Editar el archivo dejando la versión correcta
  2. Eliminar los marcadores <<<, ===, >>>
  3. git add archivo para marcar como resuelto
  4. git commit (en merge) o git rebase --continue (en rebase)

Si te arrepientes:

git merge --abort
git rebase --abort

Push forzado seguro: --force-with-lease

Si reescribes commits ya empujados (con rebase o amend), necesitas forzar el push. Pero --force puede sobrescribir trabajo ajeno sin avisar. La alternativa segura:

git push --force-with-lease

Solo fuerza el push si nadie más empujó a esa rama desde tu último fetch.

Regla: usa --force-with-lease en lugar de --force siempre que puedas.
Qué deberías poder hacer ahora
  • Distinguir cuándo Git hace fast-forward y cuándo crea merge commit
  • Hacer un rebase sin pánico y resolver conflictos paso a paso
  • Usar --force-with-lease en lugar de --force
Módulo 05 Medio

GitHub Workflow

GitHub añade colaboración sobre Git. Lo esencial para trabajar en equipo: forks, PRs, issues y un buen README.

Forks

Un fork es una copia personal de un repositorio ajeno en tu cuenta. El flujo típico:

  1. Hacer fork del repo en GitHub
  2. Clonar tu fork localmente
  3. Crear una rama, hacer cambios, push a tu fork
  4. Abrir un Pull Request al repo original

Pull Requests

Un Pull Request (PR) es la solicitud formal para integrar cambios de una rama a otra. En GitLab se llama Merge Request, pero el concepto es idéntico.

Un buen PR incluye:

  • Título descriptivo y conciso
  • Descripción del problema y la solución
  • Capturas o ejemplos cuando aplique
  • Checklist de testing
  • Referencias a issues relacionados (Closes #42)

Code Review

GitHub permite comentar línea por línea, sugerir cambios con suggested changes y aprobar o pedir cambios formalmente.

Estrategias de merge en Pull Requests

EstrategiaResultado en main
Create a merge commitConserva todos los commits + un merge commit
Squash and mergeCombina todos los commits del PR en uno solo
Rebase and mergeAplica los commits en main sin merge commit

Squash and merge es la opción más popular: produce un historial limpio en main donde cada commit corresponde a una feature.

Issues, Labels y Milestones

  • Issues: bugs, features y discusiones
  • Labels: categorización (bug, enhancement, good-first-issue)
  • Milestones: agrupar issues hacia un objetivo
  • Projects: tableros tipo Kanban
Tip: escribe Closes #42 en el mensaje del commit o en la descripción del PR. Cuando se fusione, GitHub cerrará automáticamente el issue.

README.md

GitHub renderiza el archivo README.md de la raíz como página de presentación. En el módulo 7 verás cómo escribir uno bueno.

Qué deberías poder hacer ahora
  • Hacer un fork, abrir un PR y participar en code review
  • Saber cuándo usar squash, rebase o merge commit en un PR
  • Vincular PRs con issues para cerrarlos automáticamente
Nivel Experto Recuperar trabajo, manipular el historial y montar un proyecto profesional desde cero.
Módulo 06 Experto

Recuperar & manipular historial

Los comandos que diferencian a un usuario casual de uno profesional: stash, cherry-pick, reset, revert, reflog, tags y rebase interactivo.

git stash — guardar trabajo en progreso

Cuando necesitas cambiar de rama pero tienes cambios sin commitear:

git stash                          # guarda y limpia el working tree
git stash push -m "wip: feature"   # con mensaje
git stash list                     # ver stashes guardados
git stash pop                      # aplica y elimina el último
git stash apply stash@{2}          # aplica uno específico

git cherry-pick — copiar commits específicos

Aplica un commit existente sobre la rama actual:

git cherry-pick abc1234            # un commit
git cherry-pick abc1234..def5678   # un rango

Útil cuando necesitas un fix específico de otra rama sin fusionarla completa.

git reset — mover el puntero

Cambia a qué commit apunta la rama actual. Tiene tres modos:

ModoWorking treeStagingHEAD
--softSin cambiosSin cambiosMovido
--mixed (default)Sin cambiosResetMovido
--hardResetResetMovido
git reset --soft HEAD~1     # deshace el último commit, mantiene cambios staged
git reset HEAD~1            # deshace y unstaged
git reset --hard HEAD~1     # destruye el último commit completo
Peligro: --hard es destructivo. Si los commits no están en remoto y no hay reflog reciente, los pierdes.

git revert — deshacer sin reescribir

Crea un nuevo commit que invierte los cambios de un commit anterior. Es la forma segura de "deshacer" en una rama compartida:

git revert abc1234

git reflog — el seguro de Git

Git mantiene un log de cada cambio de HEAD durante 90 días. Si "perdiste" commits con un reset --hard:

git reflog
# 1a2b3c4 HEAD@{2}: commit: feature en progreso
# 9z8y7x6 HEAD@{3}: reset: moving to HEAD~1

git reset --hard HEAD@{2}    # recuperar

Tags — marcar versiones

Hay dos tipos:

  • Lightweight: solo un puntero a un commit
  • Annotated: objeto Git completo con autor, fecha y mensaje (recomendado para releases)
git tag v1.0                              # lightweight
git tag -a v1.0 -m "Release 1.0"          # annotated (recomendado)
git push origin v1.0                       # subir el tag
git push origin --tags                     # subir todos los tags

Rebase interactivo (git rebase -i)

Permite reescribir el historial commit por commit. Al ejecutarlo, Git abre un editor con la lista de commits:

git rebase -i HEAD~4
ComandoAcción
pickMantiene el commit tal cual
rewordMantiene los cambios pero edita el mensaje
squashCombina con el anterior, fusiona mensajes
fixupComo squash pero descarta el mensaje
dropElimina el commit completo

git bisect — encontrar el commit que rompió algo

Búsqueda binaria automatizada:

git bisect start
git bisect bad                  # el commit actual está roto
git bisect good v1.0            # esta versión funcionaba
# Git hace checkout al punto medio. Pruebas y marcas:
git bisect good                 # o git bisect bad
# ...repetir hasta encontrar el commit culpable
git bisect reset                # finalizar

Inspeccionar el log

git log --oneline                   # una línea por commit
git log --oneline --graph --all     # árbol visual de todas las ramas
git log --author="Ana"              # filtrar por autor
git log --grep="bug"                # buscar en mensajes
Qué deberías poder hacer ahora
  • Recuperar trabajo perdido con git reflog
  • Limpiar tu historial antes de un PR con rebase -i
  • Saber cuándo usar reset, revert o cherry-pick
  • Etiquetar releases con tags anotados
Módulo 07 Experto

Temas adicionales

Lo que rodea a Git pero no es Git: configurar SSH, crear plantillas profesionales de issues y pull requests, y escribir READMEs que se vean serios. Lo que falta para que un proyecto tuyo en GitHub se vea pulido.

1 · Configurar SSH con GitHub

HTTPS funciona pero te pide credenciales todo el tiempo. Con SSH configuras una llave una vez y pushes sin escribir contraseñas. Es lo estándar para trabajo serio.

  1. Comprueba si ya tienes una llave SSH

    ls -al ~/.ssh

    Si ves id_ed25519 o id_rsa, ya tienes una. Puedes saltar al paso 4.

  2. Genera una nueva llave Ed25519 (más moderna y corta que RSA)

    ssh-keygen -t ed25519 -C "tu@email.com"

    Cuando te pregunte la ruta, presiona Enter para usar la default. Te pedirá una passphrase opcional — si la pones, ssh-agent te la pedirá una sola vez por sesión.

  3. Inicia el ssh-agent y añade tu llave

    eval "$(ssh-agent -s)"
    ssh-add ~/.ssh/id_ed25519
  4. Copia tu llave pública al portapapeles

    # Linux
    cat ~/.ssh/id_ed25519.pub | xclip -selection clipboard
    
    # macOS
    pbcopy < ~/.ssh/id_ed25519.pub
    
    # Windows (Git Bash)
    clip < ~/.ssh/id_ed25519.pub
    Nunca compartas id_ed25519 sin .pub. El archivo sin extensión es tu llave privada y debe quedarse en tu máquina.
  5. Añade la llave en GitHub

    GitHub → SettingsSSH and GPG keysNew SSH key. Pega el contenido y dale un título descriptivo (ej. laptop-personal).

  6. Prueba la conexión

    ssh -T git@github.com

    Deberías ver: "Hi usuario! You've successfully authenticated..."

  7. Cambia un repo existente de HTTPS a SSH

    git remote set-url origin git@github.com:usuario/mi-repo.git
    git remote -v   # verificar
Tip: si manejas varias cuentas (personal y trabajo), crea un archivo ~/.ssh/config con un host alias por cada una. Te ahorra dolores de cabeza.
Host github-personal
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_ed25519

Host github-trabajo
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_ed25519_work

Y luego clonas con git@github-personal:usuario/repo.git.

2 · La carpeta .github/

Todas las plantillas y configuraciones de GitHub viven en una carpeta especial llamada .github/ en la raíz del repo. Esta es la estructura que vamos a montar:

mi-proyecto/
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.yml
│   │   ├── feature_request.yml
│   │   └── config.yml
│   └── PULL_REQUEST_TEMPLATE.md
├── src/
├── README.md
└── .gitignore

3 · Plantillas personalizadas de Issues

GitHub muestra un menú con tus plantillas cuando alguien hace click en "New issue". Las modernas usan formato YAML con campos validados (mejor que la versión antigua en Markdown).

Bug report

name: 🐛 Reporte de bug
description: Reporta un comportamiento inesperado
title: "[Bug]: "
labels: ["bug", "triage"]
assignees:
  - tu-usuario

body:
  - type: markdown
    attributes:
      value: |
        Gracias por tomarte el tiempo de reportar este bug.
        Cuanto más detalle, más rápido lo arreglamos.

  - type: textarea
    id: descripcion
    attributes:
      label: ¿Qué pasó?
      description: Describe el bug con claridad
      placeholder: Cuando hago X, esperaba Y pero pasa Z
    validations:
      required: true

  - type: textarea
    id: pasos
    attributes:
      label: Pasos para reproducir
      placeholder: |
        1. Ir a '...'
        2. Hacer click en '....'
        3. Ver el error
    validations:
      required: true

  - type: input
    id: version
    attributes:
      label: Versión
      placeholder: "v1.2.3"
    validations:
      required: true

  - type: dropdown
    id: navegador
    attributes:
      label: Navegador
      options:
        - Chrome
        - Firefox
        - Safari
        - Edge
        - Otro

  - type: textarea
    id: logs
    attributes:
      label: Logs o capturas
      render: shell

Feature request

name: ✨ Solicitud de feature
description: Propón una nueva funcionalidad
title: "[Feature]: "
labels: ["enhancement"]

body:
  - type: textarea
    id: problema
    attributes:
      label: ¿Qué problema resuelve?
      description: Describe el caso de uso o la fricción actual
    validations:
      required: true

  - type: textarea
    id: solucion
    attributes:
      label: Solución propuesta
      description: Cómo te imaginas que debería funcionar
    validations:
      required: true

  - type: textarea
    id: alternativas
    attributes:
      label: Alternativas consideradas
      description: ¿Qué otras opciones evaluaste?

Configuración del menú

El archivo config.yml controla cómo se muestra el menú de plantillas:

blank_issues_enabled: false
contact_links:
  - name: 💬 Discusiones
    url: https://github.com/tu-usuario/tu-repo/discussions
    about: Para preguntas generales y discusiones
  - name: 📧 Contacto directo
    url: mailto:tu@email.com
    about: Asuntos privados o comerciales
Tip: con blank_issues_enabled: false obligas a usar las plantillas. Recibes issues mucho más útiles.

4 · Plantilla personalizada de Pull Request

GitHub usa este archivo automáticamente como descripción inicial de cualquier PR. Aquí lo importante es que el checklist sea realista — no copies plantillas de internet con 30 items que nadie marca.

## Descripción

<!-- ¿Qué hace este PR y por qué? -->

## Tipo de cambio

- [ ] 🐛 Bug fix
- [ ] ✨ Feature
- [ ] 💄 Cambio de UI / estilos
- [ ] ♻️ Refactor (sin cambio funcional)
- [ ] 📝 Documentación
- [ ] 🔧 Configuración / build

## Cómo probarlo

<!-- Pasos concretos para que el reviewer lo verifique -->

1. ...
2. ...

## Capturas / GIFs

<!-- Si aplica -->

## Checklist

- [ ] El código sigue el estilo del proyecto
- [ ] He probado los cambios manualmente
- [ ] He añadido o actualizado tests si aplica
- [ ] He actualizado la documentación si aplica
- [ ] No he subido secretos ni archivos sensibles

## Issues relacionados

Closes #
Bonus: puedes tener varias plantillas de PR en .github/PULL_REQUEST_TEMPLATE/ y elegirlas con un parámetro en la URL: ?template=feature.md.

5 · Cómo escribir un buen README de proyecto

El README es lo primero que ve cualquiera que llegue a tu repo. Debe responder en menos de 30 segundos: qué es, para qué sirve y cómo se usa.

Estructura recomendada

  1. Título + tagline — una línea que explique de qué se trata
  2. Badges — build, versión, licencia (sin abusar)
  3. Captura o GIF — lo más poderoso si es un proyecto visual
  4. Features clave — bullets cortos
  5. Instalación — comandos copiables
  6. Uso básico — el ejemplo más simple posible
  7. Configuración — variables de entorno, opciones
  8. Cómo contribuir — link a CONTRIBUTING.md o párrafo corto
  9. Licencia

Plantilla copiable

# 🚀 Mi Proyecto

> Una línea que explica qué hace y a quién le sirve.

![Build](https://img.shields.io/github/actions/workflow/status/usuario/repo/ci.yml)
![Version](https://img.shields.io/github/v/release/usuario/repo)
![License](https://img.shields.io/github/license/usuario/repo)

![Demo](docs/demo.gif)

## ✨ Características

- 🎯 Característica 1 — una línea concreta
- ⚡ Característica 2 — beneficio claro
- 🔒 Característica 3 — sin marketing barato

## 📦 Instalación

\`\`\`bash
npm install mi-proyecto
\`\`\`

## 🚀 Uso básico

\`\`\`js
import { miFuncion } from 'mi-proyecto';

miFuncion({ opcion: true });
\`\`\`

## ⚙️ Configuración

| Variable | Default | Descripción |
|----------|---------|-------------|
| \`API_URL\`  | \`localhost\` | URL del backend |
| \`DEBUG\`    | \`false\`     | Activa logs verbose |

## 🤝 Contribuir

Lee [CONTRIBUTING.md](CONTRIBUTING.md). Los issues con la etiqueta
\`good-first-issue\` son ideales para empezar.

## 📄 Licencia

[MIT](LICENSE) © Tu Nombre
Tip: los badges los generas en shields.io. No pongas más de 4 — saturan visualmente.

Errores comunes

  • Empezar con la historia personal del autor en lugar de "qué hace el proyecto"
  • Comandos de instalación que asumen un setup que no explicas
  • Capturas obsoletas que ya no coinciden con la UI actual
  • Un wall of text sin headings ni espacios

6 · README de perfil de GitHub

GitHub tiene un truco: si creas un repo con el mismo nombre que tu usuario y le pones un README.md, ese README aparece en la parte superior de tu perfil público.

  1. Crea un repo público llamado exactamente como tu usuario

    Si tu usuario es richardmk, el repo se llama richardmk/richardmk. GitHub te muestra un mensaje especial: "You found a secret! ..."

  2. Marca la casilla "Add a README file" al crearlo

    O créalo después con git push. Solo necesitas un README.md en la raíz.

  3. Edita el contenido y haz push

Qué incluir

  • Una frase que te describa (rol + foco), no un párrafo
  • 2-3 highlights de lo que estás haciendo o aprendiendo
  • Cómo contactarte (LinkedIn, email, web)
  • Stack principal — sin listar todo lo que has tocado alguna vez
  • Stats opcionales con github-readme-stats

Plantilla copiable

### 👋 Hola, soy Richard

🤖 **ML Engineer** trabajando en sistemas de IA escalables.
🔭 Actualmente explorando RAG aplicado a documentación técnica.
🌱 Aprendiendo a escribir mejores READMEs.

📫 Cómo contactarme: [richard.mejia.k@gmail.com](mailto:richard.mejia.k@gmail.com)

---

#### 🛠️ Stack principal

![Python](https://img.shields.io/badge/-Python-3776AB?logo=python&logoColor=white)
![PyTorch](https://img.shields.io/badge/-PyTorch-EE4C2C?logo=pytorch&logoColor=white)
![Docker](https://img.shields.io/badge/-Docker-2496ED?logo=docker&logoColor=white)
![AWS](https://img.shields.io/badge/-AWS-232F3E?logo=amazon-aws&logoColor=white)

#### 📊 Stats

![Stats](https://github-readme-stats.vercel.app/api?username=tu-usuario&show_icons=true&theme=dark)
![Top Langs](https://github-readme-stats.vercel.app/api/top-langs/?username=tu-usuario&layout=compact&theme=dark)
Sobriedad: evita acumular gifs de Mario Bros, contadores de visitas y cinco tipos de stats. Un perfil limpio comunica más profesionalismo que uno saturado.
Tip final: piensa en el README de perfil como una tarjeta de presentación, no como un currículum. Si quieren saber más, ahí están tus repos abajo.
Qué deberías poder hacer ahora
  • Configurar SSH desde cero y manejar varias cuentas con ~/.ssh/config
  • Crear plantillas YAML de issues con campos validados
  • Tener una plantilla de PR útil (no copiada de internet)
  • Escribir un README de proyecto que se entiende en 30 segundos
  • Montar tu README de perfil con el truco del repo usuario/usuario

¿Listo para evaluarte?

Pon a prueba lo aprendido con el cuestionario maestro. Cubre los conceptos esenciales de los 7 módulos.

Comenzar Quiz