Guía básica de GIT

Conceptos Básicos de Git

¿Qué es Git?

Git es un sistema de control de versiones distribuido que permite rastrear cambios en archivos a lo largo del tiempo. Fue creado por Linus Torvalds en 2005 y se ha convertido en el estándar de la industria para el control de versiones.

¿Cómo Funciona Git?

Git funciona mediante snapshots (instantáneas) de tu proyecto. Cada vez que haces un commit, Git toma una foto del estado de todos tus archivos en ese momento y almacena una referencia a esa instantánea. Si un archivo no ha cambiado, Git solo guarda un enlace al archivo anterior idéntico.

Conceptos Fundamentales

1. Repositorio (Repository)

Un repositorio es un directorio que contiene tu proyecto y todo el historial de versiones. Puede ser:

  • Local: En tu máquina
  • Remoto: En un servidor (GitHub, GitLab, Bitbucket, etc.)

2. Commit

Un commit es una instantánea de tu proyecto en un momento específico. Cada commit tiene:

  • Un hash único (SHA-1) que lo identifica
  • Un mensaje que describe los cambios
  • Un autor y fecha
  • Referencias a commits anteriores (padres)

3. Branch (Rama)

Una rama es una línea de desarrollo independiente. Te permite trabajar en diferentes características sin afectar la rama principal. La rama por defecto generalmente se llama main o master.

4. Working Directory (Directorio de Trabajo)

Es donde estás trabajando actualmente. Contiene los archivos que puedes ver y editar.

5. Staging Area (Área de Preparación)

También conocida como "index", es un área intermedia donde preparas los cambios antes de hacer commit. Los archivos pasan de "untracked" o "modified" a "staged".

6. HEAD

HEAD es un puntero que apunta al commit actual en la rama en la que estás trabajando.

Estados de los Archivos en Git

  1. Untracked (Sin seguimiento): Archivos nuevos que Git no está rastreando
  2. Modified (Modificado): Archivos que han sido cambiados pero no están en staging
  3. Staged (En preparación): Archivos modificados que están listos para commit
  4. Committed (Confirmado): Cambios guardados en el repositorio local

Flujo de Trabajo Básico

Working Directory → git add → Staging Area → git commit → Repository
     (modificado)              (staged)          (committed)

Lo Más Importante de Git

  1. Distribuido: Cada desarrollador tiene una copia completa del historial
  2. Ramas: Permiten trabajo paralelo sin conflictos
  3. Commits Atómicos: Cada commit representa un cambio lógico completo
  4. Historial Completo: Git guarda todo el historial, permitiendo revertir cambios
  5. Integridad: Usa checksums SHA-1 para garantizar la integridad de los datos

Diferencias entre Git Merge y Git Rebase

Git Merge

¿Qué hace? git merge combina los cambios de una rama en otra, creando un commit de merge que tiene dos padres. Preserva el historial completo de ambas ramas.

Cuándo usarlo:

  • Cuando trabajas en una rama compartida (como main o develop)
  • Cuando quieres preservar el historial exacto de cómo se desarrolló el proyecto
  • En proyectos donde el historial es importante para auditoría

Ventajas:

  • ✅ Preserva el historial completo
  • ✅ No reescribe commits existentes
  • ✅ Seguro para ramas compartidas
  • ✅ Muestra claramente cuándo se integraron las ramas

Desventajas:

  • ❌ Puede crear un historial más complejo con muchos commits de merge
  • ❌ El historial puede volverse difícil de seguir

Ejemplo:

# Estás en la rama main
git checkout main
git merge feature-branch

Resultado visual:

*---*---*---*---* (main)
     \         /
      *---*---* (feature-branch)

Git Rebase

¿Qué hace? git rebase toma los commits de tu rama y los "re-aplica" sobre otra rama, creando un historial lineal. Reescribe el historial de commits.

Cuándo usarlo:

  • Cuando trabajas en una rama local que no ha sido compartida
  • Cuando quieres mantener un historial limpio y lineal
  • Antes de hacer merge a la rama principal

Ventajas:

  • ✅ Historial lineal y limpio
  • ✅ Más fácil de leer y seguir
  • ✅ Evita commits de merge innecesarios

Desventajas:

  • ❌ Reescribe el historial (cambia los hashes de los commits)
  • ❌ NUNCA debe usarse en ramas compartidas/publicadas
  • ❌ Puede ser más complejo resolver conflictos

Ejemplo:

# Estás en feature-branch
git checkout feature-branch
git rebase main

Resultado visual:

*---*---*---*---*---*---* (main + feature-branch lineal)

Comparación Visual

Antes del merge/rebase:

main:        A---B---C
                    \
feature:             D---E

Después de merge:

main:        A---B---C-------F (merge commit)
                    \       /
feature:             D---E

Después de rebase:

main:        A---B---C
                    \
feature:             D'---E' (commits reescritos)

¿Cuándo Usar Cada Uno?

SituaciónUsar
Rama compartida/publicadaMerge
Rama local personalRebase
Quieres historial completoMerge
Quieres historial limpioRebase
Trabajo en equipoMerge
Trabajo individualRebase

Rebase Interactivo

Puedes usar git rebase -i para editar, combinar o eliminar commits antes de aplicarlos:

git rebase -i HEAD~3  # Rebase interactivo de los últimos 3 commits

Cómo Hacer un Pull Request (PR)

Un Pull Request (PR) es una solicitud para integrar cambios de una rama a otra. Es el mecanismo estándar para revisar código antes de integrarlo.

Proceso Paso a Paso

1. Preparar tu Entorno Local

# Asegúrate de estar en la rama principal y actualizada
git checkout main
git pull origin main

2. Crear una Nueva Rama

# Crea y cambia a una nueva rama para tu feature
git checkout -b feature/nombre-de-tu-feature
 
# O si prefieres separar los comandos:
git branch feature/nombre-de-tu-feature
git checkout feature/nombre-de-tu-feature

Convenciones de nombres:

  • feature/nombre: Para nuevas características
  • fix/nombre: Para correcciones de bugs
  • hotfix/nombre: Para correcciones urgentes
  • refactor/nombre: Para refactorizaciones

3. Hacer tus Cambios

Edita los archivos necesarios en tu editor de código.

4. Revisar tus Cambios

# Ver qué archivos has modificado
git status
 
# Ver los cambios específicos
git diff

5. Agregar Archivos al Staging

# Agregar archivos específicos
git add archivo1.js archivo2.js
 
# Agregar todos los archivos modificados
git add .
 
# Agregar todos los archivos (incluyendo eliminados)
git add -A

6. Hacer Commit

# Commit con mensaje descriptivo
git commit -m "feat: agregar funcionalidad de autenticación"
 
# O commit con mensaje más detallado
git commit -m "feat: agregar funcionalidad de autenticación
 
- Implementar login con email y contraseña
- Agregar validación de formularios
- Incluir manejo de errores"

Convenciones de mensajes de commit:

  • feat: Nueva característica
  • fix: Corrección de bug
  • docs: Cambios en documentación
  • style: Cambios de formato (no afectan código)
  • refactor: Refactorización de código
  • test: Agregar o modificar tests
  • chore: Tareas de mantenimiento

7. Sincronizar con la Rama Principal (Opcional pero Recomendado)

Antes de hacer push, es buena práctica actualizar tu rama con los últimos cambios de main:

# Opción 1: Rebase (historial más limpio)
git fetch origin
git rebase origin/main
 
# Opción 2: Merge (más seguro si otros han visto tu rama)
git fetch origin
git merge origin/main

8. Hacer Push de tu Rama

# Primera vez que haces push de esta rama
git push -u origin feature/nombre-de-tu-feature
 
# Push subsecuentes
git push

9. Crear el Pull Request en GitHub/GitLab

En GitHub:

  1. Ve al repositorio en GitHub
  2. Verás un banner que dice "Compare & pull request"
  3. Haz clic y completa:
    • Título: Descripción breve y clara
    • Descripción: Explica qué cambios hiciste y por qué
    • Reviewers: Selecciona quién debe revisar
    • Labels: Agrega etiquetas relevantes
  4. Haz clic en "Create pull request"

En GitLab:

  1. Ve al repositorio en GitLab
  2. Haz clic en "Merge requests" → "New merge request"
  3. Selecciona tu rama fuente y la rama destino
  4. Completa el título y descripción
  5. Haz clic en "Create merge request"

10. Responder a Comentarios y Hacer Cambios

Si hay comentarios o solicitudes de cambios:

# Haz los cambios necesarios
# Luego agrega y haz commit
git add .
git commit -m "fix: corregir problema señalado en review"
 
# Haz push (el PR se actualiza automáticamente)
git push

11. Después de que se Apruebe el PR

Una vez aprobado y mergeado:

# Vuelve a la rama principal
git checkout main
 
# Actualiza con los últimos cambios
git pull origin main
 
# Elimina la rama local (opcional)
git branch -d feature/nombre-de-tu-feature
 
# Elimina la rama remota (opcional)
git push origin --delete feature/nombre-de-tu-feature

Mejores Prácticas para PRs

  1. Mantén PRs pequeños: Es más fácil revisar cambios pequeños
  2. Un PR = Una característica: No mezcles múltiples features
  3. Describe claramente: Explica el qué, por qué y cómo
  4. Incluye tests: Si es aplicable, agrega o actualiza tests
  5. Actualiza documentación: Si cambias funcionalidad, actualiza docs
  6. Revisa tu propio código: Antes de pedir review, revísalo tú primero

Cheatsheet de Comandos Git

Configuración Inicial

# Configurar nombre de usuario
git config --global user.name "Tu Nombre"
 
# Configurar email
git config --global user.email "tu@email.com"
 
# Ver configuración
git config --list
 
# Configurar editor por defecto
git config --global core.editor "code --wait"  # VS Code

Comandos Básicos

git init

Inicializa un nuevo repositorio Git en el directorio actual.

git init

git clone

Clona un repositorio remoto a tu máquina local.

git clone https://github.com/usuario/repo.gitgit clone https://github.com/usuario/repo.git mi-carpeta # Clonar en carpeta específica

git status

Muestra el estado de tu working directory y staging area.

git statusgit status -s # Versión corta

git add

Agrega archivos al staging area.

git add archivo.js              # Agregar archivo específico
git add archivo1.js archivo2.js # Agregar múltiples archivos
git add .                       # Agregar todos los archivos modificados en el directorio actual
git add -A                      # Agregar todos los archivos (incluyendo eliminados)
git add *.js                    # Agregar todos los archivos .js
git add -p                      # Agregar cambios de forma interactiva (patch mode)

git commit

Guarda los cambios del staging area en el repositorio.

git commit -m "Mensaje del commit"           # Commit con mensaje
git commit -m "Título" -m "Descripción"      # Commit con título y descripción
git commit                                   # Abre editor para escribir mensaje
git commit -a                                # Agrega todos los archivos modificados y hace commit (salta staging)
git commit --amend                           # Modifica el último commit
git commit --amend -m "Nuevo mensaje"        # Cambia el mensaje del último commit
git commit --amend --no-edit                 # Agrega cambios al último commit sin cambiar mensaje

git log

Muestra el historial de commits.

git log                                    # Historial completo
git log --oneline                          # Historial en una línea por commit
git log --graph                            # Muestra gráfico de ramas
git log --graph --oneline --all            # Gráfico compacto de todas las ramas
git log -5                                 # Últimos 5 commits
git log --since="2 weeks ago"             # Commits desde hace 2 semanas
git log --author="Nombre"                 # Commits de un autor específico
git log --grep="palabra"                  # Buscar commits por mensaje
git log archivo.js                        # Historial de un archivo específico

git diff

Muestra las diferencias entre versiones.

git diff                           # Cambios en working directory (no staged)
git diff --staged                  # Cambios en staging area
git diff HEAD                      # Todos los cambios (staged + unstaged)
git diff commit1 commit2           # Diferencias entre dos commits
git diff commit1..commit2          # Mismo que arriba
git diff branch1..branch2          # Diferencias entre dos ramas

Trabajo con Ramas

git branch

Gestiona ramas.

git branch                          # Lista todas las ramas locales
git branch -a                       # Lista todas las ramas (locales y remotas)
git branch nombre-rama              # Crea una nueva rama
git branch -d nombre-rama           # Elimina una rama (si está mergeada)
git branch -D nombre-rama          # Elimina una rama (forzado, aunque no esté mergeada)
git branch -m nombre-viejo nuevo   # Renombra una rama
git branch --set-upstream-to=origin/rama rama  # Configura tracking

git checkout

Cambia de rama o restaura archivos.

git checkout nombre-rama            # Cambiar a una rama
git checkout -b nueva-rama          # Crea y cambia a nueva rama
git checkout archivo.js             # Deshace cambios en archivo (working directory)
git checkout -- .                   # Deshace todos los cambios en working directory
git checkout commit-hash            # Cambia a un commit específico (detached HEAD)

git switch (Git 2.23+)

Comando moderno para cambiar de rama (más intuitivo que checkout).

git switch nombre-rama              # Cambiar a una rama
git switch -c nueva-rama             # Crea y cambia a nueva rama

Merge y Rebase

git merge

Combina ramas.

git merge nombre-rama                # Mergea nombre-rama en la rama actual
git merge --no-ff nombre-rama       # Fuerza un commit de merge (no fast-forward)
git merge --ff-only nombre-rama     # Solo permite fast-forward
git merge --abort                    # Cancela un merge en progreso

git rebase

Re-aplica commits sobre otra rama.

git rebase nombre-rama               # Rebase la rama actual sobre nombre-rama
git rebase -i HEAD~3                 # Rebase interactivo de últimos 3 commits
git rebase --continue                # Continúa después de resolver conflictos
git rebase --abort                   # Cancela el rebase
git rebase --skip                    # Salta el commit actual en rebase

Trabajo con Remotos

git remote

Gestiona repositorios remotos.

git remote                           # Lista remotos
git remote -v                        # Lista remotos con URLs
git remote add nombre url            # Agrega un remoto
git remote remove nombre             # Elimina un remoto
git remote rename viejo nuevo        # Renombra un remoto
git remote set-url nombre nueva-url  # Cambia la URL de un remoto

git fetch

Descarga cambios del remoto sin mergear.

git fetch                            # Descarga cambios de origin
git fetch origin                     # Descarga cambios de origin específicamente
git fetch origin nombre-rama         # Descarga una rama específica
git fetch --all                      # Descarga de todos los remotos

git pull

Descarga y mergea cambios del remoto.

git pull                             # Pull de origin (fetch + merge)
git pull origin nombre-rama          # Pull de una rama específica
git pull --rebase                    # Pull con rebase en lugar de merge
git pull --ff-only                   # Solo permite fast-forward

git push

Sube cambios al repositorio remoto.

git push                             # Push a la rama actual
git push origin nombre-rama          # Push de una rama específica
git push -u origin nombre-rama       # Push y configura tracking (primera vez)
git push --all                       # Push de todas las ramas
git push --tags                      # Push de todos los tags
git push --force                     # Fuerza el push (¡CUIDADO!)
git push --force-with-lease          # Force push más seguro

Deshacer Cambios

# Deshacer cambios en working directory
git checkout -- archivo.js
git restore archivo.js              # Comando moderno (Git 2.23+)
 
# Quitar archivos del staging (mantiene cambios)
git reset HEAD archivo.js
git restore --staged archivo.js     # Comando moderno
 
# Deshacer el último commit (mantiene cambios)
git reset --soft HEAD~1
 
# Deshacer el último commit (elimina cambios del staging)
git reset --mixed HEAD~1
git reset HEAD~1                    # --mixed es el default
 
# Deshacer el último commit (elimina todo)
git reset --hard HEAD~1             # ¡CUIDADO! Pierdes cambios
 
# Deshacer cambios de forma segura
git stash                           # Guarda cambios temporalmente
git stash pop                       # Restaura cambios guardados

Stash (Guardar Cambios Temporalmente)

git stash                            # Guarda cambios temporalmente
git stash save "mensaje"             # Guarda con mensaje
git stash list                       # Lista todos los stashes
git stash pop                        # Aplica y elimina el último stash
git stash apply                      # Aplica el último stash (sin eliminarlo)
git stash apply stash@{0}            # Aplica un stash específico
git stash drop stash@{0}             # Elimina un stash específico
git stash clear                      # Elimina todos los stashes

Tags

git tag                              # Lista todos los tags
git tag v1.0.0                       # Crea un tag ligero
git tag -a v1.0.0 -m "Versión 1.0"  # Crea un tag anotado
git tag -d v1.0.0                    # Elimina un tag local
git push origin v1.0.0               # Push de un tag
git push --tags                      # Push de todos los tags
git checkout v1.0.0                  # Cambia a un tag específico

Búsqueda y Filtrado

# Buscar en el código
git grep "texto"                     # Busca texto en todos los archivos
git grep -n "texto"                  # Con números de línea
git grep --name-only "texto"         # Solo nombres de archivos
 
# Buscar en el historial
git log --all --full-history -- "archivo.js"  # Historial completo de un archivo
git log -S "texto"                    # Commits que agregaron o eliminaron texto
git log -p -S "texto"                # Con el diff completo

Limpieza

git clean -n                         # Muestra qué se eliminaría (dry-run)
git clean -f                         # Elimina archivos no rastreados
git clean -fd                        # Elimina archivos y directorios no rastreados
git clean -i                         # Modo interactivo

Diagrama Visual de Git

Arquitectura General de Git

┌─────────────────────────────────────────────────────────────┐
│                    REPOSITORIO REMOTO                        │
│                  (GitHub/GitLab/Bitbucket)                   │
│                                                               │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐                   │
│  │   main   │  │ develop  │  │ feature │                   │
│  └──────────┘  └──────────┘  └──────────┘                   │
└─────────────────────────────────────────────────────────────┘
                          ↕ (push/pull)
┌─────────────────────────────────────────────────────────────┐
│                    REPOSITORIO LOCAL                         │
│                                                               │
│  ┌─────────────────────────────────────────────────────┐    │
│  │              .git/ (Base de Datos)                  │    │
│  │  ┌──────────┐  ┌──────────┐  ┌──────────┐         │    │
│  │  │ Objects  │  │   Refs   │  │  Config  │         │    │
│  │  │ (Commits)│  │ (Branches)│  │          │         │    │
│  │  └──────────┘  └──────────┘  └──────────┘         │    │
│  └─────────────────────────────────────────────────────┘    │
│                          ↕                                   │
│  ┌─────────────────────────────────────────────────────┐    │
│  │            STAGING AREA (Index)                      │    │
│  │         Archivos preparados para commit              │    │
│  └─────────────────────────────────────────────────────┘    │
│                          ↕                                   │
│  ┌─────────────────────────────────────────────────────┐    │
│  │         WORKING DIRECTORY                            │    │
│  │      Archivos que estás editando                     │    │
│  └─────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────┘

Flujo de Estados de Archivos

┌──────────────┐
│  UNTRACKED   │  (Archivo nuevo, Git no lo rastrea)
└──────┬───────┘
       │ git add
       ↓
┌──────────────┐
│   STAGED     │  (Archivo en staging area, listo para commit)
└──────┬───────┘
       │ git commit
       ↓
┌──────────────┐
│  COMMITTED   │  (Cambios guardados en el repositorio)
└──────────────┘
       │
       │ (modificar archivo)
       ↓
┌──────────────┐
│   MODIFIED   │  (Archivo modificado, no en staging)
└──────┬───────┘
       │ git add
       ↓
┌──────────────┐
│   STAGED     │  (De nuevo en staging)
└──────────────┘

Estructura de Commits y Ramas

                    ┌─────────┐
                    │ Commit  │
                    │   A     │
                    └────┬────┘
                         │
                    ┌────▼────┐
                    │ Commit  │
                    │   B     │
                    └────┬────┘
                         │
         ┌───────────────┼───────────────┐
         │               │               │
    ┌────▼────┐     ┌────▼────┐     ┌────▼────┐
    │ Commit  │     │ Commit  │     │ Commit  │
    │   C     │     │   D     │     │   E     │
    │ (main)  │     │(feature)│     │(hotfix) │
    └────┬────┘     └────┬────┘     └────┬────┘
         │               │               │
         └───────────────┼───────────────┘
                         │
                    ┌────▼────┐
                    │ Commit  │
                    │   F     │
                    │ (merge) │
                    └─────────┘

Comparación: Merge vs Rebase

ANTES (Estado Inicial):

main:     A────B────C
                  \
feature:           D────E

DESPUÉS DE MERGE:

main:     A────B────C────────F (merge commit)
                  \         /
feature:           D────E───┘

DESPUÉS DE REBASE:

main:     A────B────C
                      \
feature:               D'────E' (commits reescritos)

Flujo Completo de Trabajo con Git

1. CLONAR/CREAR REPOSITORIO
   ↓
2. CREAR RAMA
   git checkout -b feature/nueva-funcionalidad
   ↓
3. TRABAJAR EN ARCHIVOS
   (Editar archivos en Working Directory)
   ↓
4. AGREGAR AL STAGING
   git add archivos
   ↓
5. HACER COMMIT
   git commit -m "mensaje"
   ↓
6. SINCRONIZAR CON REMOTO
   git fetch origin
   git rebase origin/main (o merge)
   ↓
7. HACER PUSH
   git push origin feature/nueva-funcionalidad
   ↓
8. CREAR PULL REQUEST
   (En GitHub/GitLab)
   ↓
9. REVISIÓN Y APROBACIÓN
   ↓
10. MERGE A MAIN
    ↓
11. ACTUALIZAR LOCAL
    git checkout main
    git pull origin main

Áreas de Git (Three-Tree Architecture)

┌─────────────────────────────────────────────────────────┐
│                    WORKING DIRECTORY                     │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐             │
│  │ archivo1 │  │ archivo2 │  │ archivo3 │             │
│  │ (modif.) │  │ (nuevo)  │  │ (sin     │             │
│  │          │  │          │  │ cambios) │             │
│  └──────────┘  └──────────┘  └──────────┘             │
└─────────────────────────────────────────────────────────┘
                    │ git add
                    ↓
┌─────────────────────────────────────────────────────────┐
│                    STAGING AREA                          │
│  ┌──────────┐  ┌──────────┐                            │
│  │ archivo1 │  │ archivo2 │                            │
│  │ (staged) │  │ (staged) │                            │
│  └──────────┘  └──────────┘                            │
└─────────────────────────────────────────────────────────┘
                    │ git commit
                    ↓
┌─────────────────────────────────────────────────────────┐
│                    REPOSITORIO                           │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐             │
│  │ archivo1 │  │ archivo2 │  │ archivo3 │             │
│  │ (commit) │  │ (commit) │  │ (commit) │             │
│  └──────────┘  └──────────┘  └──────────┘             │
└─────────────────────────────────────────────────────────┘

HEAD y Referencias

┌─────────────────────────────────────────┐
│  .git/refs/heads/main                    │
│  → apunta a commit ABC123                │
└─────────────────────────────────────────┘
                    │
                    ↓
┌─────────────────────────────────────────┐
│  HEAD → apunta a refs/heads/main         │
│  (estás en la rama main)                 │
└─────────────────────────────────────────┘
                    │
                    ↓
┌─────────────────────────────────────────┐
│  Commit ABC123                           │
│  - Hash: abc123def456...                 │
│  - Mensaje: "feat: nueva funcionalidad"  │
│  - Padre: xyz789...                      │
│  - Tree: tree456...                      │
└─────────────────────────────────────────┘

Resumen de Mejores Prácticas

✅ Hacer

  • Haz commits pequeños y frecuentes
  • Escribe mensajes de commit claros y descriptivos
  • Mantén ramas actualizadas con la rama principal
  • Usa git pull --rebase para mantener historial limpio
  • Revisa tus cambios con git diff antes de commitear
  • Haz push regularmente de tu trabajo
  • Usa ramas para features nuevas
  • Elimina ramas después de mergearlas

❌ No Hacer

  • No hagas commit de archivos de configuración local
  • No hagas git push --force a ramas compartidas
  • No hagas git rebase en ramas compartidas/publicadas
  • No hagas commits de archivos binarios grandes
  • No ignores el .gitignore
  • No hagas commits con mensajes vagos como "fix" o "update"
  • No mezcles múltiples features en un solo commit
  • No hagas push directamente a main o master

Recursos Adicionales

On this page