Git es un sistema de control de versiones distribuido. Fue creado en 2005 por Linus Torvalds (el mismo que creó Linux) para gestionar el desarrollo del kernel de Linux.

En términos simples: Git guarda un historial completo de todos los cambios que ocurren en tu proyecto. Puedes:

  • Volver a cualquier versión anterior de tu código
  • Trabajar en paralelo en múltiples funcionalidades sin interferir
  • Colaborar con otros desarrolladores de forma ordenada
  • Saber quién cambió qué, cuándo y por qué

Git ≠ GitHub. Git es la herramienta local que corre en tu máquina. GitHub, GitLab y Bitbucket son plataformas en la nube que alojan repositorios Git y añaden herramientas de colaboración.


Conceptos clave

Antes de entrar a los comandos, conviene tener claros estos términos:

TérminoSignificado
Repositorio (repo)Carpeta del proyecto rastreada por Git, incluyendo todo su historial
CommitUna «foto» del estado del proyecto en un momento dado
Branch (rama)Una línea de desarrollo independiente
HEADEl punto actual donde estás trabajando en el historial
Staging areaZona intermedia donde preparas los cambios antes de hacer commit
RemoteUn repositorio alojado en un servidor (GitHub, GitLab, etc.)
CloneCopia local de un repositorio remoto
ForkCopia de un repositorio en tu cuenta de GitHub para modificarlo independientemente
MergeUnir los cambios de una rama a otra
RebaseReescribir el historial de commits sobre una nueva base
ConflictSituación donde dos cambios incompatibles se encuentran al hacer merge

Instalación y configuración

Instalación

Windows: Descarga desde git-scm.com. Incluye Git Bash.

macOS:

# Con Homebrew (recomendado)
brew install git

# O simplemente ejecuta git en la terminal y macOS te pedirá instalarlo
git --version

Linux (Debian/Ubuntu):

sudo apt update && sudo apt install git

Configuración inicial

Se hace una sola vez por máquina:

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

# Editor por defecto (VS Code, Vim, Nano, etc.)
git config --global core.editor "code --wait"   # VS Code
git config --global core.editor "nano"           # Nano

# Nombre de la rama principal
git config --global init.defaultBranch main

# Colores en la terminal
git config --global color.ui auto

# Ver toda la configuración
git config --list

Configuración por proyecto

Si necesitas usar credenciales distintas en un proyecto específico (por ejemplo, trabajo vs. personal), omite --global:

git config user.email "trabajo@empresa.com"

Iniciar un repositorio

Proyecto nuevo

mkdir mi-proyecto
cd mi-proyecto
git init

Esto crea una carpeta oculta .git/ que contiene todo el historial. No la borres.

Proyecto existente en remoto

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

# Clonar en una carpeta con nombre distinto
git clone https://github.com/usuario/repositorio.git mi-carpeta

# Clonar solo una rama específica
git clone -b nombre-rama https://github.com/usuario/repositorio.git

El ciclo de vida de los archivos

Los archivos en Git tienen cuatro estados posibles:

Untracked  →  Staged  →  Committed
    ↑             ↑
 (nuevo)     (git add)    (git commit)
                  ↑
             Modified  (archivo ya rastreado pero con cambios)
  • Untracked: archivo nuevo que Git no conoce todavía
  • Modified: archivo que Git conoce y que ha sido modificado
  • Staged: cambio preparado para el próximo commit
  • Committed: cambio guardado permanentemente en el historial

Comandos esenciales

Verificar estado

git status           # Estado completo
git status -s        # Estado resumido (short)

Agregar al staging area

git add archivo.txt           # Un archivo
git add carpeta/              # Una carpeta completa
git add .                     # Todo lo modificado y nuevo
git add -p                    # Interactivo: elegir qué partes de cada archivo agregar

Hacer un commit

git commit -m "Mensaje descriptivo"

# Agregar al staging y hacer commit en un paso (solo archivos ya rastreados)
git commit -am "Mensaje"

# Abrir el editor para un mensaje más largo
git commit

# Modificar el último commit (antes de hacer push)
git commit --amend -m "Mensaje corregido"
git commit --amend --no-edit   # Mismo mensaje, solo añade los cambios en staging

Ver el historial

git log                        # Historial completo
git log --oneline              # Una línea por commit
git log --oneline --graph      # Con visualización de ramas
git log -5                     # Últimos 5 commits
git log --author="Nombre"      # Filtrar por autor
git log --since="2 weeks ago"  # Filtrar por fecha
git log -- archivo.txt         # Historial de un archivo

Ver diferencias

git diff                       # Cambios no staged
git diff --staged              # Cambios en staging vs. último commit
git diff rama1 rama2           # Diferencia entre dos ramas
git diff abc123 def456         # Diferencia entre dos commits (usar sus hashes)

Ramas (Branches)

Las ramas permiten trabajar en paralelo sin afectar el código principal.

Gestión básica

git branch                     # Listar ramas locales
git branch -a                  # Listar locales y remotas
git branch nueva-rama          # Crear rama
git switch nueva-rama          # Cambiar a esa rama (forma moderna)
git checkout nueva-rama        # Cambiar de rama (forma clásica, aún válida)
git switch -c nueva-rama       # Crear y cambiar en un paso
git checkout -b nueva-rama     # Equivalente clásico

git branch -d rama             # Eliminar rama (segura, solo si fue mergeada)
git branch -D rama             # Eliminar rama forzado
git branch -m nuevo-nombre     # Renombrar la rama actual

Ver información de ramas

git branch -v                  # Ver el último commit de cada rama
git branch --merged            # Ramas ya fusionadas con la actual
git branch --no-merged         # Ramas sin fusionar

Fusionar cambios: Merge y Rebase

Merge

Toma los cambios de una rama y los une a la rama actual. Preserva el historial completo.

# Estando en main, traer los cambios de feature
git switch main
git merge feature/login

# Merge sin fast-forward (siempre crea un commit de merge)
git merge --no-ff feature/login

# Cancelar un merge con conflictos
git merge --abort

Resolver conflictos de merge:

Cuando Git no puede fusionar automáticamente, marca los archivos así:

<<<<<<< HEAD
código de tu rama actual
=======
código de la otra rama
>>>>>>> feature/login

Debes editar el archivo manualmente, quedarte con lo correcto, y luego:

git add archivo-con-conflicto.txt
git commit

Rebase

Mueve o «replanta» una rama sobre otra. Produce un historial más limpio y lineal.

# Estando en feature, rebasear sobre main
git switch feature/login
git rebase main

# Interactivo: reescribir, combinar o reordenar commits
git rebase -i HEAD~3    # Últimos 3 commits

En el rebase interactivo puedes usar:

  • pick — mantener el commit tal cual
  • reword — cambiar el mensaje
  • squash — combinar con el commit anterior
  • drop — eliminar el commit

⚠️ Regla de oro: nunca hagas rebase de ramas que ya están en el remoto y otras personas están usando. Reescribir el historial compartido genera problemas serios.


Repositorios remotos

Configurar remotos

git remote add origin https://github.com/usuario/repo.git
git remote -v                          # Ver remotos configurados
git remote rename origin upstream      # Renombrar un remoto
git remote remove origin               # Eliminar un remoto
git remote set-url origin nueva-url    # Cambiar la URL

Subir y bajar cambios

# Subir cambios
git push origin main
git push -u origin main        # -u establece el upstream (solo la primera vez)
git push                       # Después de -u, basta con esto

# Subir una nueva rama al remoto
git push origin nueva-rama

# Subir y eliminar rama en remoto
git push origin --delete rama-remota

# Forzar push (peligroso, úsalo con cuidado)
git push --force-with-lease    # Más seguro que --force

# Traer cambios
git fetch origin               # Descarga cambios pero NO los aplica
git pull origin main           # Descarga y aplica (fetch + merge)
git pull --rebase              # Descarga y aplica con rebase en lugar de merge

Seguir ramas remotas

# Crear una rama local que sigue a una remota
git switch -t origin/feature/login

# Ver qué ramas locales siguen a cuáles remotas
git branch -vv

Deshacer cambios

Esta es una de las partes más importantes y más confusas de Git.

Antes del staging (working directory)

# Descartar cambios de un archivo (volver al último commit)
git restore archivo.txt           # Forma moderna
git checkout -- archivo.txt       # Forma clásica

# Descartar todos los cambios no staged
git restore .

En el staging area

# Sacar un archivo del staging sin perder los cambios
git restore --staged archivo.txt
git reset HEAD archivo.txt        # Equivalente clásico

Deshacer commits

# Deshacer el último commit, mantener cambios en staging
git reset --soft HEAD~1

# Deshacer el último commit, mantener cambios en working directory
git reset --mixed HEAD~1    # Es el comportamiento por defecto de git reset

# Deshacer el último commit Y borrar los cambios (DESTRUCTIVO)
git reset --hard HEAD~1

# Deshacer usando el hash de un commit específico
git reset --hard abc1234

Revertir un commit (forma segura para ramas compartidas)

A diferencia de reset, revert no borra el historial. Crea un nuevo commit que deshace los cambios:

git revert abc1234        # Revierte ese commit
git revert HEAD           # Revierte el último commit
git revert HEAD~3..HEAD   # Revierte un rango de commits

Recuperar commits «perdidos»

git reflog es tu red de seguridad. Guarda todos los movimientos de HEAD aunque hayas hecho reset:

git reflog
# Encuentra el hash del estado que quieres recuperar, luego:
git reset --hard abc1234

Stash: cambios temporales

Stash guarda tus cambios actuales en una pila temporal para que puedas cambiar de contexto sin hacer un commit incompleto.

git stash                          # Guardar cambios (rastreados)
git stash -u                       # Incluir archivos untracked
git stash push -m "descripción"   # Guardar con nombre

git stash list                     # Ver todos los stashes
git stash pop                      # Aplicar el último y eliminarlo de la pila
git stash apply stash@{2}          # Aplicar uno específico sin eliminarlo
git stash drop stash@{0}           # Eliminar un stash específico
git stash clear                    # Eliminar todos los stashes

# Crear una rama desde un stash
git stash branch nombre-rama stash@{0}

Tags y versiones

Los tags marcan puntos específicos del historial, como versiones de releases.

# Tag ligero (solo un marcador)
git tag v1.0.0

# Tag anotado (recomendado: incluye autor, fecha y mensaje)
git tag -a v1.0.0 -m "Primera versión estable"

# Taggear un commit anterior
git tag -a v0.9.0 abc1234

git tag                            # Listar todos los tags
git show v1.0.0                    # Ver detalles del tag
git push origin v1.0.0             # Subir un tag al remoto
git push origin --tags             # Subir todos los tags
git tag -d v1.0.0                  # Eliminar tag local
git push origin --delete v1.0.0   # Eliminar tag remoto

El archivo .gitignore

.gitignore le dice a Git qué archivos y carpetas debe ignorar. Se coloca en la raíz del proyecto.

# Dependencias
node_modules/
vendor/

# Archivos de entorno y secretos
.env
.env.local
*.pem
secrets.json

# Builds y compilados
dist/
build/
*.o
*.class
*.pyc
__pycache__/

# Archivos del sistema operativo
.DS_Store
Thumbs.db
desktop.ini

# IDEs y editores
.vscode/
.idea/
*.swp
*.swo

# Logs
*.log
logs/

# Ignorar todo en una carpeta excepto un archivo
carpeta/*
!carpeta/.gitkeep

Comandos útiles con gitignore:

# Ver qué archivos están siendo ignorados
git status --ignored

# Ignorar un archivo ya rastreado (primero agréguelo al .gitignore)
git rm --cached archivo.txt

# Limpiar archivos no rastreados e ignorados
git clean -fd          # Elimina archivos y carpetas no rastreados
git clean -fdx         # También elimina los ignorados (peligroso)
git clean -n           # Simulación: muestra qué se eliminaría

Git log avanzado

# Historial gráfico y decorado
git log --oneline --graph --decorate --all

# Buscar en los mensajes de commit
git log --grep="login"

# Buscar commits que introdujeron o eliminaron una cadena de texto
git log -S "nombre-de-función"

# Ver qué cambió en cada commit
git log -p

# Estadísticas resumidas por commit
git log --stat

# Formato personalizado
git log --pretty=format:"%h - %an, %ar : %s"
# %h = hash corto | %an = autor | %ar = fecha relativa | %s = mensaje

Blame: quién cambió qué

git blame archivo.txt              # Línea por línea, con autor y commit
git blame -L 10,25 archivo.txt     # Solo las líneas 10 a 25

Bisect: encontrar el commit que introdujo un bug

git bisect start
git bisect bad                     # El estado actual tiene el bug
git bisect good v1.0.0             # Esta versión estaba bien
# Git irá a la mitad del historial; tú pruebas y marcas:
git bisect good                    # o
git bisect bad
# Git repite hasta encontrar el commit culpable
git bisect reset                   # Salir del modo bisect

Alias útiles

Los alias te ahorran tiempo al reducir comandos largos a abreviaciones:

git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.lg "log --oneline --graph --decorate --all"
git config --global alias.unstage "restore --staged"
git config --global alias.last "log -1 HEAD"
git config --global alias.undo "reset --soft HEAD~1"

Uso:

git lg      # En lugar de git log --oneline --graph --decorate --all
git undo    # En lugar de git reset --soft HEAD~1

Flujos de trabajo (Workflows)

Git Flow

El más estructurado. Ideal para proyectos con releases programadas.

main          ─────────────────────────────────●─────────────
                                               ↑ (release)
develop       ──●──────────────────────────────●────────────
                 ↑                             ↑
feature/x        └──●──●──●──┘ (merged to develop)
hotfix                                   └──●──┘ (merged a main y develop)
  • main: siempre en producción
  • develop: integración continua
  • feature/*: nuevas funcionalidades
  • release/*: preparación de versión
  • hotfix/*: correcciones urgentes en producción

GitHub Flow

Más simple. Ideal para despliegue continuo.

main          ──────────────────────────────●──
                                            ↑
feature/x     ──●──●──●── (Pull Request) ──┘
  1. Crea una rama desde main
  2. Haz commits
  3. Abre un Pull Request
  4. Recibe revisión de código
  5. Merge a main → despliegue automático

Trunk-Based Development

Todos trabajan directamente en main con feature flags para ocultar trabajo en progreso. Ramas de vida muy corta (menos de un día).


Buenas prácticas

Mensajes de commit

Sigue el estándar de Conventional Commits:

tipo(alcance opcional): descripción corta en imperativo

Cuerpo opcional con más detalle.

Footer opcional: BREAKING CHANGE, closes #123

Tipos comunes:

TipoCuándo usarlo
featNueva funcionalidad
fixCorrección de bug
docsSolo documentación
styleFormato, puntos y comas (sin cambio de lógica)
refactorRefactorización sin nueva funcionalidad ni fix
testAgregar o corregir tests
choreTareas de mantenimiento, dependencias
perfMejora de rendimiento

Ejemplos:

feat(auth): agregar inicio de sesión con Google
fix(api): corregir timeout en peticiones lentas
docs: actualizar instrucciones de instalación

Commits

  • Commit frecuente: un commit = un cambio lógico. No acumules días de trabajo en un solo commit.
  • Commits atómicos: cada commit debe funcionar de forma independiente.
  • No commitear archivos generados: builds, dependencias, archivos compilados van en .gitignore.
  • Nunca commitear secretos: claves de API, contraseñas, tokens. Usa variables de entorno.

Ramas

  • Nombres descriptivos en minúsculas con guiones: feature/formulario-contacto, fix/error-login-mobile.
  • Ramas de vida corta: cuanto más dure una rama, más difícil será el merge.
  • Actualiza tu rama regularmente con git pull o git rebase para evitar conflictos grandes.

Colaboración

  • Siempre revisa los cambios antes de hacer push: git diff y git log.
  • Usa Pull Requests / Merge Requests para revisión de código antes de mergear a ramas principales.
  • Nunca hagas git push --force en ramas compartidas (usa --force-with-lease si es absolutamente necesario).

Cheatsheet completo

Configuración

git config --global user.name "Nombre"
git config --global user.email "email"
git config --list

Repositorio

git init                          # Iniciar repo
git clone <url>                   # Clonar repo

Estado y diferencias

git status / git status -s
git diff / git diff --staged
git log --oneline --graph
git blame <archivo>

Staging y commits

git add . / git add -p
git commit -m "msg"
git commit --amend
git commit -am "msg"

Ramas

git branch / git branch -a
git switch -c <rama> / git checkout -b <rama>
git branch -d <rama>
git merge <rama>
git rebase <rama>
git rebase -i HEAD~N

Remotos

git remote add origin <url>
git push -u origin main
git push / git pull
git fetch origin
git push origin --delete <rama>

Deshacer

git restore <archivo>             # Descartar cambios
git restore --staged <archivo>    # Sacar del staging
git reset --soft HEAD~1           # Deshacer commit, mantener staging
git reset --mixed HEAD~1          # Deshacer commit, mantener working dir
git reset --hard HEAD~1           # Deshacer commit y cambios (DESTRUCTIVO)
git revert <hash>                 # Nuevo commit que deshace otro (seguro)
git reflog                        # Historial de todo movimiento de HEAD

Stash

git stash / git stash -u
git stash list
git stash pop / git stash apply stash@{N}
git stash drop / git stash clear

Tags

git tag -a v1.0.0 -m "msg"
git push origin --tags
git tag -d v1.0.0

Utilidades

git clean -fd                     # Eliminar archivos no rastreados
git cherry-pick <hash>            # Aplicar un commit específico a la rama actual
git bisect start/good/bad/reset   # Encontrar commit con bug
git shortlog -sn                  # Ranking de commits por autor

Documentación oficial: git-scm.com/doc — El libro «Pro Git» está disponible gratis online y es la referencia más completa que existe.