Git
Una herramienta esencial para el desarrollo de software
Agenda
- Introducción a Git
- Conceptos básicos y áreas de trabajo
- Configuración y comandos esenciales
- Trabajo con ramas y resolución de conflictos
- Integración con GitHub
- Autenticación (HTTPS y SSH)
- GitHub CLI
- Flujos de trabajo comunes
- Gitflow vs Trunk-based
- Feature branches y Pull Requests
- Feature flags
- Modelando la historia
- Merge vs Rebase
- Reset y reflog
- Conventional Commits
- Demo práctica
- Call to Action: Buenas Prácticas
1. Introducción a Git
"Los sistemas de control de versiones no son sobre archivos, son sobre los cambios a los archivos"
Git es un sistema de control de versiones distribuido diseñado para:
- Rastrear cambios en archivos
- Coordinar el trabajo entre múltiples personas
- Mantener un historial completo del proyecto
- Permitir volver a estados anteriores
Historia Breve
- Creado por Linus Torvalds en 2005 para el desarrollo del kernel de Linux
- Surgió como alternativa a herramientas propietarias y centralizadas
- Hoy es el estándar de la industria para control de versiones
Diferencias con otros sistemas
Sistemas centralizados (SVN, CVS):
- Dependen de un servidor central
- Requieren conexión constante
- Operaciones más lentas
Git (Distribuido):
- Cada desarrollador tiene una copia completa del repositorio
- Permite trabajo sin conexión
- Mayor velocidad y flexibilidad
2. Conceptos básicos de Git
Repositorio:
- Repositorio: Colección de archivos y su historial de cambios
- Local: En tu máquina personal
- Remoto: Alojado en un servidor (GitHub, GitLab, etc.)
Ciclo de trabajo básico:
- Modificar archivos en tu directorio de trabajo
- Seleccionar archivos para la próxima versión (staging)
- Confirmar los cambios (commit)
- Sincronizar con repositorios remotos (push/pull)
Áreas de trabajo en Git
- Working directory: Donde modificas tus archivos
- Staging area (index): Preparación para el próximo commit
- Local repository: Historial de commits en tu máquina
- Remote repository: Versión compartida en el servidor
3. Configuración y comandos esenciales
Configuración inicial
# Configuración global
git config --global user.name "Tu Nombre"
git config --global user.email "tu.email@ejemplo.com"
# Configuración del repositorio actual
git config user.name "Tu Nombre"
git config user.email "tu.email@ejemplo.com"
Iniciar un repositorio
# Crear un nuevo repositorio
git init
# Clonar un repositorio existente
git clone https://github.com/usuario/repositorio.git
Comandos básicos
# Ver estado de archivos
git status
# Añadir archivos al staging area
git add archivo.txt # Archivo específico
git add . # Todos los archivos
# Confirmar cambios
git commit -m "Mensaje descriptivo del cambio"
git commit -a -m "Añadir y confirmar en un paso"
# Ver historial de commits
git log
git log --oneline # Formato resumido
git log --graph # Con representación gráfica
4. Trabajo con ramas (branches)
- Las ramas permiten desarrollar funcionalidades aisladas
- Facilitan el trabajo en paralelo
- Permiten experimentar sin afectar el código principal
Comandos para ramas
# Ver ramas existentes
git branch
# Crear nueva rama
git branch nueva-funcionalidad
# Cambiar a una rama
git checkout nueva-funcionalidad
git switch nueva-funcionalidad # Git moderno
# Crear y cambiar en un paso
git checkout -b nueva-funcionalidad
Fusionar y eliminar ramas
# Fusionar ramas
git checkout main
git merge nueva-funcionalidad
# Eliminar rama
git branch -d nueva-funcionalidad # Si ya está fusionada
git branch -D nueva-funcionalidad # Forzar eliminación
Resolución de conflictos
Los conflictos ocurren cuando Git no puede resolver automáticamente las diferencias entre ramas:
- Git marca los conflictos en los archivos
<<<<<<< HEAD
Cambios en la rama actual
=======
Cambios en la rama que estás fusionando
>>>>>>> rama-a-fusionar
- Edita manualmente los archivos para resolver
- Añade los archivos resueltos con
git add
- Completa el merge con
git commit
5. Integración con GitHub
Autenticación con HTTPS
# Clonar repositorio con HTTPS
git clone https://github.com/usuario/repo.git
# GitHub solicitará credenciales en cada operación remota
# Recomendado: Configurar credential helper
git config --global credential.helper cache # Temporal
git config --global credential.helper store # Permanente
Tokens de acceso personal
- Más seguros que contraseñas
- Se generan en GitHub > Settings > Developer settings > Personal access tokens
- Se usan como contraseña al autenticarse
Autenticación con SSH
-
Generar clave SSH (si no la tienes)
ssh-keygen -t ed25519 -C "tu.email@ejemplo.com"
-
Añadir clave al ssh-agent
eval "$(ssh-agent -s)" ssh-add ~/.ssh/id_ed25519
-
Añadir clave pública a GitHub
- Copiar contenido de
~/.ssh/id_ed25519.pub
- GitHub > Settings > SSH and GPG keys > New SSH key
- Copiar contenido de
-
Clonar usando SSH
git clone git@github.com:usuario/repo.git
GitHub CLI
Herramienta oficial de línea de comandos para GitHub:
Instalación
# Seguir instrucciones según sistema operativo
# https://github.com/cli/cli#installation
Autenticación
gh auth login
Comandos útiles
# Clonar repositorio
gh repo clone usuario/repo
# Crear pull request
gh pr create
# Ver y revisar pull requests
gh pr list
gh pr checkout número
gh pr view número
# Crear issues
gh issue create
Repositorios remotos
# Ver repositorios remotos
git remote -v
# Añadir repositorio remoto
git remote add origin https://github.com/usuario/repo.git
# Eliminar repositorio remoto
git remote remove origin
¿Qué es upstream?
- origin: Apunta a tu fork o copia del repositorio
- upstream: Apunta al repositorio original/principal
# Añadir upstream
git remote add upstream https://github.com/original/repo.git
# Obtener cambios del upstream
git fetch upstream
git merge upstream/main
Comandos para colaboración
# Obtener cambios sin integrarlos
git fetch origin
# Obtener e integrar cambios
git pull origin main
# Enviar cambios locales al remoto
git push origin main
# Establecer tracking para simplificar comandos
git push -u origin feature # Después solo: git push
6. Flujos de trabajo comunes
Gitflow
- main/master: Código de producción estable
- develop: Integraciones para próxima versión
- feature/*: Funcionalidades específicas
- release/x.y: Preparación para lanzamiento
- hotfix/*: Correcciones urgentes
Trunk-based development
- Todos trabajan en la rama principal
- Commits pequeños y frecuentes
- Uso de feature flags para ocultar funcionalidades incompletas
- Integración continua constante
Feature branches y Pull Requests
Proceso típico:
- Crear rama desde main/develop
git checkout -b feature/nueva-funcionalidad
- Desarrollar y commitear cambios
git add .
git commit -m "feat: implementa nueva funcionalidad"
- Enviar rama al remoto
git push -u origin feature/nueva-funcionalidad
- Crear Pull Request en GitHub/GitLab
- Code review, discusión y aprobación
- Merge a la rama principal
Feature Flags
- Permiten activar/desactivar funcionalidades sin cambios de código
- Útiles para pruebas A/B, lanzamientos graduales y integración continua
Ejemplos:
// Simple, basado en variables de entorno
if (process.env.FEATURE_NEW_UI === 'true') {
// Mostrar nueva interfaz
} else {
// Mostrar interfaz antigua
}
// Basado en usuarios
if (userGroups.includes('beta-testers')) {
// Mostrar funcionalidad beta
}
// Porcentaje de usuarios
if (Math.random() < 0.1) { // 10% de usuarios
// Mostrar nueva funcionalidad
}
Feature Flags (implementaciones)
Opciones para gestionar feature flags:
-
Simples:
- Variables de entorno
- Archivos de configuración
-
Avanzadas:
- Libraries: Unleash, LaunchDarkly, Flipper
- Servicios en la nube
// Ejemplo con biblioteca
import { initializeClient } from 'feature-flag-service';
const client = initializeClient('api-key');
if (client.isEnabled('new-payment-method')) {
// Mostrar nuevo método de pago
}
7. Modelando la historia
Merge: El "Registro Histórico"
- Conserva toda la historia, incluyendo la bifurcación y la unión
- Mantiene contexto completo
- Puede generar historiales complicados
git checkout main
git merge feature/nueva-funcionalidad
Rebase: La "Historia Limpia"
- Reescribe la historia para que parezca lineal
- Crea historiales más limpios
- Puede dificultar la colaboración si no se usa correctamente
git checkout feature/nueva-funcionalidad
git rebase main
El puntero HEAD y el estado del repositorio
¿Qué es HEAD?
- HEAD es un puntero especial que indica el commit actualmente activo
- Normalmente HEAD apunta a la última confirmación de la rama actual
- Es esencial para entender dónde estás en el historial de Git
# Ver a qué apunta HEAD
git rev-parse HEAD
# Ver historial con ubicación de HEAD
git log --oneline --decorate
Estados de HEAD
-
HEAD normal: Apunta a una rama
HEAD -> main -> commit A
-
Detached HEAD: Apunta directamente a un commit
HEAD -> commit C (no rama)
- Ocurre al hacer checkout a un commit específico
- Los cambios no se guardan en ninguna rama
- Útil para explorar el historial, peligroso para desarrollo activo
Comandos modernos de Git
git checkout vs git switch vs git restore
git checkout
- Comando multifunción (tradicional):
# Cambiar de rama
git checkout rama-destino
# Crear y cambiar a nueva rama
git checkout -b nueva-rama
# Restaurar archivos desde HEAD
git checkout -- archivo.txt
# Moverse a un commit específico (¡crea detached HEAD!)
git checkout abc123
git switch
- Comando específico para cambiar ramas (Git 2.23+):
# Cambiar de rama
git switch rama-destino
# Crear y cambiar a nueva rama
git switch -c nueva-rama
# Regresar a la rama anterior
git switch -
git restore
- Comando específico para restaurar archivos (Git 2.23+):
# Descartar cambios en working directory
git restore archivo.txt
# Descartar cambios en staging area
git restore --staged archivo.txt
# Restaurar a una versión específica
git restore --source=HEAD~1 archivo.txt
Escenarios de Detached HEAD
¿Cuando ocurre?
- Al hacer checkout a un commit específico:
git checkout abc123
- Al hacer checkout a una etiqueta:
git checkout v1.0.0
Precauciones
- Los cambios y commits realizados en estado detached HEAD pueden perderse
- Git advierte sobre este estado con un mensaje claro
Cómo salir de Detached HEAD
- Sin cambios: Simplemente regresa a una rama
git checkout main
- Con cambios que quieres conservar:
# Crear una nueva rama donde estás
git branch nueva-rama-backup
# Cambiar a la nueva rama
git checkout nueva-rama-backup
Rebase interactivo
Poderosa herramienta para editar la historia antes de integrarla:
git rebase -i HEAD~3 # Editar los últimos 3 commits
Opciones disponibles:
- pick: mantener el commit
- reword: cambiar mensaje
- edit: modificar contenido
- squash: combinar con commit anterior
- fixup: combinar y descartar mensaje
- drop: eliminar commit
Útil para limpiar la historia antes de hacer PR.
Git reset
Permite mover HEAD y la rama actual a un commit específico:
Modos:
- --soft: Mantiene cambios en staging
git reset --soft HEAD~1 # Deshacer último commit, conservar cambios
- --mixed (default): Mantiene cambios en working directory
git reset HEAD~1 # Deshacer último commit y staging
- --hard: Elimina cambios completamente
git reset --hard HEAD~1 # Eliminar último commit y cambios
Git reflog: Salvavidas
Registra todos los movimientos de HEAD, útil para recuperar commits "perdidos":
# Ver historial de referencias
git reflog
# Recuperar commit eliminado
git checkout <hash-del-commit>
git branch nueva-rama # Para preservar el commit recuperado
8. Conventional Commits
Especificación para dar estructura a los mensajes de commit:
<tipo>[ámbito opcional]: <descripción>
[cuerpo opcional]
[notas de pie opcionales]
Tipos principales:
- feat: Nueva funcionalidad
- fix: Corrección de error
- docs: Cambios en documentación
- style: Cambios de formato
- refactor: Cambios que no corrigen ni añaden
- test: Cambios en pruebas
- chore: Tareas de mantenimiento
Beneficios de Conventional Commits
- Generación automática de changelogs
-
Determinación semántica de versiones
- feat: incrementa versión menor (1.0.0 → 1.1.0)
- fix: incrementa versión de parche (1.0.0 → 1.0.1)
- feat! o BREAKING CHANGE: incrementa versión mayor (1.0.0 → 2.0.0)
- Comunicación clara de la naturaleza de los cambios
- Facilita la colaboración y revisión de código
git commit -m "feat(auth): implementa autenticación con Google"
git commit -m "fix(ui): corrige alineación en pantallas pequeñas"
9. Demo práctica
Escenario: Desarrollo de una funcionalidad con feature flag
Paso 1: Configuración inicial
# Configurar Git y clonar repositorio
git config --global user.name "Tu Nombre"
git config --global user.email "tu@email.com"
git clone https://github.com/usuario/proyecto-demo.git
cd proyecto-demo
Paso 2: Crear rama para la funcionalidad
# Crear y cambiar a nueva rama
git checkout -b feature/nueva-api
Demo práctica (continuación)
Paso 3: Implementar con feature flag
// archivo: features.js
const FEATURES = {
NUEVA_API: process.env.FEATURE_NUEVA_API === 'true'
};
// archivo: api.js
if (FEATURES.NUEVA_API) {
// Implementación nueva
} else {
// Implementación antigua
}
Paso 4: Commitear siguiendo conventional commits
git add features.js api.js
git commit -m "feat(api): implementa nueva API con feature flag"
Demo práctica (continuación)
Paso 5: Enviar cambios y crear PR
git push -u origin feature/nueva-api
# Con GitHub CLI
gh pr create --title "Implementa nueva API" --body "Esta PR incluye la nueva API protegida por feature flag"
Paso 6: Después de la aprobación, actualizar y fusionar
git checkout main
git pull
git merge feature/nueva-api
git push
10. Call to Action: Buenas Prácticas
Repository management & CI Automatization
En nuestra organización hemos establecido lineamientos oficiales para:
- Control estricto de versiones
- Flujos de trabajo con Git
- Convenciones de commits
- Proceso CI/CD
- Integración con SonarQube
- Métricas y umbrales de calidad
Consulta el documento completo en nuestro repositorio:
Preguntas frecuentes
-
¿Cuándo usar merge vs. rebase?
- Merge: Para integraciones finales y cuando la historia bifurcada es importante
- Rebase: Para mantener tu rama actualizada antes de un PR
-
¿Cómo recuperar cambios perdidos?
- Usar
git reflog
para encontrar y recuperar commits "perdidos"
- Usar
-
¿Cómo resolver conflictos complejos?
- Herramientas visuales como VSCode, GitKraken
- Resolver por partes pequeñas
¡Gracias!
Recursos adicionales:
Contacto:
Git
By Juan G
Git
- 31