Qué es Git
Git es un sistema de control de versiones distribuido. Guarda el historial completo de cambios de un proyecto — quién cambió qué, cuándo y por qué. GitHub es la plataforma en la nube que aloja repositorios Git y añade colaboración: Pull Requests, revisiones de código y CI/CD.
Configuración Inicial
Antes de hacer el primer commit, Git necesita saber quién eres. Esta información aparece en cada commit del historial — usa tu nombre real y el correo de tu cuenta GitHub.
Verificar:
File → Options → GitAhí aparecen tu nombre y correo configurados.
# Clonar el repositorio desde GitHub git clone https://github.com/vlim/erp-carniceria.git cd erp-carniceria # Verificar estado y ramas disponibles git status # estado del working tree git branch # ramas locales (solo verás main) git branch -a # ramas locales Y remotas # Obtener la rama dev (después de clonar, no existe localmente) git checkout -b dev origin/dev # crea rama dev local vinculada al remoto # Alternativa moderna git switch dev # si ya existe localmente git switch -c dev origin/dev # si no existe aún
dev — no en main. Desde dev crearás tus ramas feature. Nunca desde main.Commits y Staging
El flujo básico de Git es: modificar archivos → agregar al staging area (preparar) → confirmar con commit. El staging te permite elegir exactamente qué cambios van en cada commit.
✅ Marcar = agregar al staging
✏️ Escribir mensaje en el campo
Summary🔵 Clic en Commit to [rama]
Para subir: botón Push origin (arriba)
# Formato: tipo(scope): descripción breve en imperativo # [línea vacía] # Cuerpo opcional (qué y por qué, no cómo) # Tipos principales: feat: # Nueva funcionalidad fix: # Corrección de bug refactor: # Refactorización sin cambio de comportamiento test: # Agregar o modificar tests docs: # Documentación style: # Formato, espacios (sin cambio lógico) chore: # Tareas de mantenimiento, dependencias ci: # Cambios en CI/CD # Ejemplos buenos ✅ git commit -m "feat(ventas): agregar descuento por volumen" git commit -m "fix(auth): corregir expiración de sesión en cajero" git commit -m "refactor(inventario): extraer lógica de stock a servicio" git commit -m "docs: actualizar README con instrucciones de Docker" # Ejemplos malos ❌ # git commit -m "cambios" # git commit -m "arreglos varios" # git commit -m "WIP" # git commit -m "fixed stuff"
Arquitectura de Ramas VLIM
En VLIM usamos tres tipos de ramas con roles muy definidos. Nadie hace push directo a main ni a dev — todo pasa por Pull Request. Esta regla se enforcea con Branch Protection en GitHub.
| Rama | Rol | Quién hace push | Regla |
|---|---|---|---|
| main | 🔴 Producción — código estable siempre listo para deploy | Nadie directamente | Solo PR desde dev al cierre del Sprint |
| dev | 🔵 Integración — todas las features del Sprint se van aquí | Nadie directamente | Solo PR desde feature/* |
| feature/nombre | 🟢 Trabajo individual — una tarea, un bug, una mejora | El desarrollador dueño | Se crea desde dev, se elimina al mergearse |
feature/nombre-de-la-tarea → nueva funcionalidadfix/descripcion-del-bug → corrección de bugrefactor/modulo-afectado → refactorizaciónhotfix/descripcion → corrección urgente en producciónUsa solo minúsculas y guiones. Sin espacios, sin tildes, sin caracteres especiales.
Ejemplos:
feature/modulo-ventas, fix/validacion-stock, hotfix/login-cajeroFeature → PR → dev
El ciclo completo de un desarrollador VLIM: desde recibir una tarea hasta que su código queda integrado en dev. Cada paso está cubierto tanto en GitHub Desktop como en la terminal.
dev2. Clic en Fetch origin (arriba a la derecha)
3. Si hay cambios: clic en Pull origin
2. Escribir el nombre:
feature/modulo-ventas3. Verificar que dice "From:
dev"4. Clic Create Branch
1. Marcar los archivos relevantes ✅
2. Escribir Summary:
feat(ventas): agregar pantalla de cobro3. Descripción opcional para más detalle
4. Clic Commit to feature/modulo-ventas
o Push origin (los siguientes pushes)
Aparece arriba a la derecha de la ventana.
2. Abre GitHub Web automáticamente
3. Base:
dev ← Compare: feature/modulo-ventas4. Llenar título y descripción
5. Asignar reviewer
6. Clic Create Pull Request
## ¿Qué hace este PR? Descripción clara de los cambios implementados. ## Tipo de cambio - [ ] feat: Nueva funcionalidad - [ ] fix: Corrección de bug - [ ] refactor: Refactorización ## ¿Cómo probar? 1. Ejecutar `docker compose up` 2. Ir a /ventas 3. Registrar una venta de prueba ## Checklist - [ ] Los tests pasan localmente - [ ] No hay console.log de debug - [ ] Las variables de entorno necesarias están documentadas - [ ] El código sigue las convenciones del proyecto ## Screenshots (si aplica)
dev2. Clic Fetch origin + Pull origin
3. Branch → Delete Branch para eliminar la feature branch
GitHub también te ofrece borrar la rama directamente en el PR mergeado.
Cierre de Sprint
Al finalizar cada Sprint, el Tech Lead crea un PR de dev → main. Este merge toca producción — se hace con revisión, con --no-ff para preservar el historial, y se etiqueta con un tag de versión. El deploy automático (cap. 09) se dispara solo al detectar el merge en main.
# ── Paso 1: Actualizar ramas locales ────────────────── git checkout main git pull origin main git checkout dev git pull origin dev # ── Paso 2: Verificar historial de dev ──────────────── git log --oneline --graph origin/main..origin/dev # Muestra todos los commits que están en dev pero NO en main # Revisa que son los commits esperados del Sprint # ── Paso 3: Opción A — PR en GitHub Web (recomendado) ─ # Crear PR: base main ← compare dev # Asignar al menos 1 reviewer # Revisar los cambios en la pestaña Files changed # Aprobar y hacer merge con "Create a merge commit" (--no-ff) # ── Paso 3: Opción B — merge por consola ────────────── git checkout main git merge --no-ff dev -m "merge: Sprint 5 → main" # --no-ff = "No Fast Forward" — crea un commit de merge visible # El historial queda claro: se ve exactamente cuándo cerró cada Sprint # ── Paso 4: Crear tag de versión ────────────────────── git tag -a v1.5.0 -m "Sprint 5 — módulo de ventas + reportes" git push origin main git push origin v1.5.0 # los tags NO se pushean automáticamente # ── Paso 5: Sincronizar dev con main ────────────────── # Importante: dev debe arrancar el siguiente Sprint desde main git checkout dev git merge main # fast-forward, no hay diferencias git push origin dev # ── Verificar resultado ─────────────────────────────── git log --oneline --graph --all -10 # Deberías ver: # * a3f2bc1 (HEAD -> main, tag: v1.5.0) merge: Sprint 5 → main # |\ # | * 9d1e4f2 feat(ventas): pantalla de cobro # | * 7c2a1b3 fix(auth): expiración de sesión # |/ # * 5b8d9e1 (tag: v1.4.0) merge: Sprint 4 → main
--no-ff el historial muestra claramente cada merge de Sprint — puedes ver cuándo llegó cada feature a producción. Con squash se pierde el historial detallado. Para el cierre de Sprint a main, siempre --no-ff (merge commit). Para features dentro del Sprint, squash en el PR está bien si prefieres un historial más limpio en dev.| Estrategia de merge | Cuándo usarla en VLIM | Resultado en historial |
|---|---|---|
| Merge commit (--no-ff) | feature → dev y dev → main (Sprints) | Historial completo, merge commit visible |
| Squash and merge | Opcional para feature → dev (historial limpio) | N commits → 1 commit en dev |
| Rebase and merge | No recomendado en ramas compartidas | Historial lineal pero reescribe commits |
Proteger Ramas
Branch Protection Rules en GitHub hacen que las reglas sean imposibles de saltarse accidentalmente — incluso para el owner del repositorio. Es la forma de garantizar que nadie rompa producción con un push directo.
── Configuración recomendada para main ───────────────────────────── Branch name pattern: main ✅ Require a pull request before merging └─ Require approvals: 1 (al menos 1 aprobación del Tech Lead) └─ Dismiss stale pull request approvals when new commits are pushed (si el dev sube más commits después de la aprobación, re-requiere review) ✅ Require status checks to pass before merging └─ Require branches to be up to date before merging └─ Status checks: "test" y "build" (de GitHub Actions, cap. 08) ✅ Require conversation resolution before merging └─ Todos los comentarios del PR deben resolverse antes de mergear ✅ Require linear history (opcional — commits limpios) ✅ Do not allow bypassing the above settings └─ Ni admins pueden saltarse las reglas ── Configuración recomendada para dev ────────────────────────────── Branch name pattern: dev ✅ Require a pull request before merging └─ Require approvals: 1 (peer review del equipo) ✅ Require status checks to pass └─ "test" debe pasar (CI corre los tests automáticamente) ── Regla adicional — bloquear push directo a cualquier feature ───── (opcional, más restrictivo) Branch name pattern: main y dev ✅ Block force pushes ✅ Block deletions
git push origin main directamente → GitHub rechaza con error "protected branch hook declined". La única manera de integrar código es por PR aprobado. Los tests de CI deben pasar. Esto hace que sea prácticamente imposible romper producción por accidente.GitHub Actions
GitHub Actions es el CI/CD nativo de GitHub — sin costo adicional para repos privados hasta 2000 min/mes. Los workflows se definen en YAML en el repo, corren en máquinas virtuales de GitHub y se disparan con eventos del repositorio (push, PR, merge, tag).
name: CI — Tests y Build on: pull_request: branches: [dev, main] # corre en todo PR hacia dev o main push: branches: [dev] # también al mergear a dev jobs: test: name: Tests runs-on: ubuntu-latest services: # contenedores disponibles durante el job postgres: image: postgres:16-alpine env: POSTGRES_DB: erp_test POSTGRES_USER: test_user POSTGRES_PASSWORD: test_pass options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 redis: image: redis:7-alpine options: --health-cmd "redis-cli ping" --health-interval 5s steps: - name: Checkout uses: actions/checkout@v4 - name: Setup Node.js 20 uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' # cachea node_modules entre runs - name: Install dependencies run: npm ci - name: Lint run: npm run lint - name: Type check run: npm run typecheck - name: Run tests run: npm test env: NODE_ENV: test DB_HOST: localhost DB_PORT: 5432 DB_NAME: erp_test DB_USER: test_user DB_PASSWORD: test_pass REDIS_HOST: localhost build: name: Build Docker image runs-on: ubuntu-latest needs: test # solo si los tests pasan steps: - uses: actions/checkout@v4 - name: Build Docker image (verificar que compila) run: docker build --target production -t erp-api:ci-test .
Deploy Automático
El deploy a producción se dispara automáticamente cuando un PR se mergea a main — es decir, al cierre de cada Sprint. El workflow construye la imagen Docker, la publica al registry y despliega en el servidor via SSH, todo sin intervención manual.
name: Deploy a Producción — Cierre de Sprint on: push: branches: [main] # se dispara cuando llega un merge a main workflow_dispatch: # también permite correrlo manualmente desde GitHub env: REGISTRY: ghcr.io IMAGE: ghcr.io/${{ github.repository_owner }}/erp-api jobs: # ── Job 1: Build y push de imagen Docker ──────────── build-and-push: name: Build y Push imagen runs-on: ubuntu-latest outputs: image-tag: ${{ steps.meta.outputs.version }} steps: - uses: actions/checkout@v4 - name: Setup BuildKit uses: docker/setup-buildx-action@v3 - name: Login al GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} # automático, no requiere config - name: Extraer metadatos (tag automático) id: meta uses: docker/metadata-action@v5 with: images: ${{ env.IMAGE }} tags: | type=sha,prefix=sha- # sha-a1b2c3d type=raw,value=latest # latest siempre apunta a main type=semver,pattern={{version}} # si hay tag v1.5.0 - name: Build y Push uses: docker/build-push-action@v5 with: context: . target: production push: true tags: ${{ steps.meta.outputs.tags }} cache-from: type=gha cache-to: type=gha,mode=max # ── Job 2: Deploy en el servidor ──────────────────── deploy: name: Deploy a servidor runs-on: ubuntu-latest needs: build-and-push # espera a que la imagen esté publicada environment: production # entorno con aprobación manual opcional steps: - name: Deploy via SSH uses: appleboy/[email protected] with: host: ${{ secrets.DEPLOY_HOST }} # IP del servidor username: ${{ secrets.DEPLOY_USER }} # usuario SSH key: ${{ secrets.DEPLOY_SSH_KEY }} # llave privada SSH script: | cd /opt/erp echo "${{ secrets.GITHUB_TOKEN }}" | \ docker login ghcr.io -u ${{ github.actor }} --password-stdin docker compose pull api worker docker compose up -d --no-deps api worker docker compose exec -T api node dist/migrate.js # migraciones docker image prune -f echo "✅ Deploy Sprint completado: $(date)" - name: Notificar Slack (opcional) if: always() uses: rtCamp/action-slack-notify@v2 env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} SLACK_MESSAGE: > ${{ job.status == 'success' && '✅ Deploy exitoso' || '❌ Deploy falló' }} — Sprint mergeado a main
# Ir a: Repo → Settings → Secrets and variables → Actions → New repository secret DEPLOY_HOST # IP o dominio del servidor: "192.168.1.100" DEPLOY_USER # Usuario SSH: "ubuntu" o "deploy" DEPLOY_SSH_KEY # Llave privada SSH (contenido de ~/.ssh/id_ed25519) SLACK_WEBHOOK # URL de webhook de Slack (opcional) # GITHUB_TOKEN es automático — GitHub lo genera por job, no requiere config # Generar llave SSH dedicada para el deploy (no usar tu llave personal) ssh-keygen -t ed25519 -C "github-actions-deploy" -f ~/.ssh/deploy_key -N "" # Copiar la llave pública al servidor: cat ~/.ssh/deploy_key.pub >> ~/.ssh/authorized_keys # en el servidor # Copiar la llave PRIVADA a GitHub Secrets como DEPLOY_SSH_KEY: cat ~/.ssh/deploy_key
Conflictos y Resolución
Un conflicto ocurre cuando dos ramas modificaron la misma línea del mismo archivo. Git no sabe cuál versión conservar — tienes que decidirlo tú. No son un error, son parte normal del trabajo en equipo.
# Git marca los conflictos así en el archivo: <<<<<<< HEAD (dev — tu rama actual) const precio = calcularConIVA(base); ======= const precio = calcularConDescuento(base, descuento); >>>>>>> feature/descuentos (la rama entrante) # Tu decisión: eliminar los marcadores y dejar el código correcto # Opción A — conservar solo HEAD (lo tuyo) const precio = calcularConIVA(base); # Opción B — conservar solo la rama entrante const precio = calcularConDescuento(base, descuento); # Opción C — combinar ambos cambios (la más común) const precio = calcularConIVA(calcularConDescuento(base, descuento));
1. Clic en Open in Visual Studio Code (o el editor configurado)
2. VS Code muestra los conflictos con botones: Accept Current Change / Accept Incoming Change / Accept Both
3. Elegir la opción correcta en cada conflicto
4. Guardar el archivo
5. Volver a Desktop → los archivos resueltos se marcan ✅
6. Clic en Continue Merge
2. Ramas cortas — no tengas una feature branch abierta por 2 semanas.
3. Divide el trabajo para que distintos devs toquen distintos archivos.
4. Comunica en el equipo cuando vas a hacer cambios en archivos compartidos (config, tipos globales, etc.).
Buenas Prácticas
Las buenas prácticas de Git no son burocracia — son las que hacen que el historial sea útil cuando algo falla en producción a las 2am. Con ellas puedes saber en 30 segundos qué cambió, cuándo y quién.
| Práctica | Por qué | En VLIM |
|---|---|---|
| Commits pequeños y frecuentes | Más fácil revisar, revertir y encontrar bugs con git bisect | Al menos 1 commit por sub-tarea lógica |
| Conventional Commits | Historial legible, changelogs automáticos, semver automático | feat/fix/refactor/docs/chore obligatorio |
| Ramas de vida corta | Menos conflictos, más integración continua real | Max 5-7 días, idealmente 1-2 días |
| Nunca --force en ramas compartidas | Reescribir historial rompe el repo de otros | --force solo permitido en tu feature branch personal |
| .gitignore completo | Evitar subir node_modules, .env, archivos de build | Usar plantilla de Node.js + ajustes del proyecto |
| Nunca secrets en el repo | GitHub indexa todos los commits — los secrets quedan expuestos para siempre | Variables en GitHub Secrets + .env.example en repo |
# Dependencias node_modules/ .pnp .pnp.js # Build dist/ build/ *.tsbuildinfo # Entorno — NUNCA al repositorio .env .env.* !.env.example # .env.example SÍ va al repo (template sin valores reales) # Logs *.log logs/ npm-debug.log* # Cobertura de tests coverage/ .nyc_output/ # Sistema operativo .DS_Store Thumbs.db *.swp # Docker docker-compose.override.yml # config local de cada dev # IDEs .vscode/settings.json # settings personales (NO extensiones recomendadas) .idea/ *.suo # Uploads locales en desarrollo uploads/ tmp/
Comandos de Emergencia
Errores que cometen todos en algún momento — y cómo salir de ellos. La mayoría son reversibles si actúas rápido antes de hacer push.
# ── "Hice commit en la rama equivocada" ─────────────── # Ejemplo: commiteé en dev en vez de en mi feature branch git log --oneline -3 # obtener el SHA del commit accidental git checkout feature/mi-tarea # ir a la rama correcta git cherry-pick <SHA> # aplicar el commit aquí git checkout dev git reset --soft HEAD~1 # deshacer el commit en dev (guarda los cambios) git stash # guardar temporalmente los cambios # ── "Necesito deshacer el último commit (sin publicar)" ─ git reset --soft HEAD~1 # deshace el commit, guarda los cambios en staging git reset HEAD~1 # deshace commit y staging, guarda en working tree git reset --hard HEAD~1 # ⚠️ deshace todo, PIERDE los cambios del commit # ── "Subí algo que no debía (ya hice push)" ─────────── # NUNCA uses --force en dev o main. Usa revert: git revert <SHA> # crea un nuevo commit que deshace el anterior git push origin feature/mi-tarea # seguro, no reescribe historial # ── "Borrré un archivo sin querer" ──────────────────── git checkout HEAD -- archivo.ts # restaurar desde el último commit git restore archivo.ts # alternativa moderna # ── "Necesito pausar mi trabajo para revisar un bug urgente" ── git stash # guardar cambios sin commitear git stash push -m "WIP: pantalla de cobro" # con nombre descriptivo # ... resolver el bug en otra rama ... git stash pop # recuperar los cambios guardados git stash list # ver stashes guardados # ── "Qué cambió exactamente en este commit" ─────────── git show <SHA> # ver diff completo del commit git show <SHA> --stat # solo qué archivos cambiaron git blame archivo.ts # quién modificó cada línea git log -S "calcularIVA" # buscar commits que tocaron esta función # ── "El PR en GitHub dice que hay conflictos" ───────── git checkout feature/mi-tarea git fetch origin git merge origin/dev # traer los últimos cambios de dev # resolver conflictos (ver cap. 10) git push # el PR se actualiza automáticamente # ── "Hice git reset --hard y perdí commits" ─────────── git reflog # historial de TODO lo que HEAD apuntó git checkout <SHA-del-reflog> # recuperar desde el reflog (tienes ~30 días)
git push --force o git push -f, git reset --hard después de push, git rebase en commits ya publicados. Estos reescriben el historial — el repo de todos los demás quedará inconsistente y tendrán que hacer reset a mano. En tu feature branch personal (no publicada) sí puedes usarlos.Referencia Rápida
Todos los comandos del día a día ordenados por categoría. Imprímela o tenla a mano durante las primeras semanas.
# ── Inicio del día ───────────────────────────────────── git checkout dev && git pull origin dev # actualizar dev git checkout feature/mi-tarea # cambiar a mi rama git merge dev # traer últimos cambios de dev a mi rama # ── Trabajo diario ───────────────────────────────────── git status # ver qué cambió git diff # ver cambios línea a línea git add . # agregar todo al staging git add <archivo> # agregar archivo específico git commit -m "feat(scope): descripción" # commit con mensaje git push # subir a GitHub # ── Ramas ────────────────────────────────────────────── git branch # listar ramas locales git checkout -b feature/nombre # crear y cambiar a nueva rama git checkout dev # cambiar a dev git branch -d feature/nombre # borrar rama local (después del merge) git push origin --delete feature/nombre # borrar rama remota # ── Historial ────────────────────────────────────────── git log --oneline # historial compacto git log --oneline --graph --all # historial con árbol de ramas git show <SHA> # ver un commit específico git log --author="Ana" --since="1 week ago"# filtrar por autor y fecha # ── Cierre de Sprint (Tech Lead) ─────────────────────── git checkout main && git pull origin main git checkout dev && git pull origin dev git checkout main git merge --no-ff dev -m "merge: Sprint N → main" git tag -a vX.Y.Z -m "Sprint N completado" git push origin main && git push origin vX.Y.Z git checkout dev && git merge main && git push origin dev # ── GitHub CLI (instalación opcional) ───────────────── # brew install gh / winget install GitHub.cli gh pr create --web # crear PR desde terminal gh pr list # ver PRs abiertos gh pr checkout 42 # bajar el PR #42 localmente gh workflow run deploy.yml # triggear workflow manualmente gh run list # ver últimos runs de Actions
1.
git pull origin dev → actualizar antes de empezar2.
git checkout -b feature/nombre → crear rama desde dev3. Trabajar →
git add . && git commit -m "feat: ..."4.
git push -u origin feature/nombre → subir a GitHub5. Crear PR en GitHub Web: feature → dev, pedir review
6. Al cierre del Sprint: Tech Lead hace PR dev → main → deploy automático 🚀