Domina el control de versiones: usa `git status` y `git diff` para inspeccionar el estado del trabajo
Introducción
Si te estás iniciando en Git (o si ya lo usás pero querés afianzar los conceptos básicos), dominar dos comandos simples pero poderosos puede marcar la diferencia: git status y git diff. Ambos te permiten ver lo que está pasando en tu repositorio en cada momento, y saber exactamente qué cambios tenés en el directorio de trabajo, cuáles están listos para ser guardados (staged) y cuáles todavía están en el área de trabajo.
Esta guía práctica va paso a paso, con ejemplos de la vida real y la salida exacta que verás en la terminal. No importa si trabajás solo en un pequeño proyecto personal o colaborás en un equipo grande; entender cómo leer git status y git diff te ayudará a evitar commits accidentales, a mantener un historial limpio y a resolver problemas cuando las cosas se complicaran.
Al finalizar, vas a ser capaz de:
- Interpretar la salida de
git statusen diferentes escenarios (archivos sin cambios, modificados, nuevos, eliminados, renombrados, etc.). - Usar
git diffpara examinar cambios sin staged y cambios con staged. - Aplicar banderas útiles (
--porcelain,-s,--cached, etc.) para automatizar tareas o filtrar ruido. - Evitar errores comunes, como cometer cambios no deseados o olvidar archivos importantes que deberían estar en
.gitignore.
Así que tomá una taza de café, abrí una terminal y comenzá a explorar cómo Git te da visibilidad total sobre tu código.
Por qué estos comandos son fundamentales
Git funciona sobre un flujo de trabajo basado en instantáneas: cada commit guarda un momento exacto del árbol de directorios. Lo que hay entre esos momentos son cambios que todavía no han sido fijados en una nueva instantánea. git status es el indicador de tráfico que te avisa qué cambios hay, mientras que git diff es la lupa que te permite inspeccionarlos.
Sin esta visibilidad, podrías:
- Agregar accidentalmente archivos con contenido de depuración o credentials a tu próximo commit.
- Pensar que un cambio ya está listo para el commit cuando todavía está solo en el área de trabajo.
- Perderte al intentar deshacer un cambio que necesitás de vuelta.
- Enfrentar conflictos al fusionar ramas sin darte cuenta de que tenías cambios locales no stageados.
Al dominar estos dos comandos, te asegurás de que siempre sepas lo que estás a punto de comprometer, lo cual es especialmente crítico en equipos donde cada miembro debe estar alineado sobre qué forma del código está siendo versionada.
El flujo de trabajo básico de Git explicado
Antes de bucear en los comandos, repasemos el concepto mental que Git usa:
- Directorio de trabajo – La carpeta en tu disco donde editás archivos. Esto es donde haces cambios en tiempo real.
- Área de staging (índice) – Un área intermedia donde puedes seleccionar qué cambios querés incluir en el próximo commit. Podes tener cambios tanto staged (en el índice) como unstaged (solo en el directorio de trabajo).
- Historial de commits – Una cadena inmutable de instantáneas (commits) que representan el estado de los archivos en el momento en que fueron guardados.
Puedes pasar cambios del área de trabajo al área de staging (git add), desde el área de staging al historial (git commit), o directamente entre ellos usando git reset o git checkout. git status te dice dónde se encuentran tus cambios actualmente; git diff te muestra exactamente qué cambios hay en cada una de esas áreas.
git status: el indicador de tráfico de tu repositorio
Ejecutándolo por primera vez
Abre una terminal dentro de cualquier repositorio Git y simplemente escribe:
$ git statusObtendrás algo como esto (tu salida puede variar ligeramente en color y texto exacto, dependiendo de tu versión de Git y de la configuración):
$ git status
En la rama 'main'
Los siguientes archivos están listos para ser confirmados:
(usa "git rm --cached <archivo>..." para eliminarlos de la lista)
modificado: archivo_ejemplo.txt
Los siguientes archivos han sido agregados pero todavía no están en la lista:
(usa "git add <archivo>..." para agregarlos al área de staging)
nuevo_archivo.py
Los siguientes archivos han sido modificados pero todavía no están en la lista:
(usa "git add <archivo>..." para agregarlos al área de staging)
config.yaml
Los siguientes archivos han sido eliminados pero todavía no están en la lista:
(usa "git rm --cached <archivo>..." para eliminarlos de la lista)
registro_antiguo.log
Los siguientes archivos han sido movidos; ¿ainda no están en la lista? (usa "git add <archivo>..." para agregarlos)
datos/originales.csv → datos/nuevos.csvEsta es la vista predeterminada (o verbose) que Git muestra. Desglosémosla sección por sección:
| Sección | Significado |
|---|---|
| En la rama 'main' | Te indica en qué rama estás actualmente. Saber en qué rama estás ayuda a evitar accidentalmente confirmar cambios en la rama equivocada. |
| Los siguientes archivos están listos para ser confirmados: | Archivos que están staged (es decir, agregados al índice). Aparece un signo de tabulación ( ) antes del nombre, y la palabra modificado: indica que el archivo existe pero su contenido cambió. |
| Los siguientes archivos han sido agregados pero todavía no están en la lista: | Archivos nuevos que Git acaba de detectar (no están bajo control de versiones). La palabra nuevo_archivo.py aparece sin prefijo. |
| Los siguientes archivos han sido modificados pero todavía no están en la lista: | Archivos ya bajo control de versiones, pero con cambios no stageados. El prefijo modificado: señala una diferencia de contenido. |
| Los siguientes archivos han sido eliminados pero todavía no están en la lista: | Archivos eliminados del sistema de archivos pero aún en el índice (es decir, eliminados del historial). El prefijo eliminado: aparece. |
| Los siguientes archivos han sido movidos; ¿ainda no están en la lista? | Git puede detectar renames cuando un archivo es movido dentro del mismo repositorio. El formato antiguo → nuevo indica un movimiento. |
Flags útiles para una salida más concisa
Cuando necesitas una salida que sea fácil de analizar en scripts, podés usar --porcelain. Esto elimina el texto descriptivo y deja solo un formato legible por máquina:
$ git status --porcelain
M archivo_ejemplo.txt
?? nuevo_archivo.py
M config.yaml
D registro_antiguo.log
R datos/originales.csv datos/nuevos.csvCódigos:
M– modificado (staged)??– nuevo sin seguimientoM– modificado (no stageado) cuando está fuera del área de staging (aún aparece comoMen la salida normal)D– eliminado (no stageado)R– renombrado (detección)
También hay un alias corto -s que hace lo mismo que --porcelain.
$ git status -s
M archivo_ejemplo.txt
?? nuevo_archivo.txt
M config.yaml
D registro_antiguo.log
R datos/originales.csv datos/nuevos.csvAhora los signos de espacio indican si un cambio está staged (M, A, D, R) o no ( M, ??, D).
Interpretando colores y configuraciones
Git puede mostrar colores para ayudarte a diferenciar rápidamente entre staged y unstaged. El esquema de colores predeterminado es:
- Verde – cambios listos para ser confirmados (staged).
- Rojo/Naranja – cambios sin stagear.
- Amarillo/Aqua – archivos nuevos o eliminados.
Si tu terminal no muestra colores, podrías tener color.status desactivado en tu configuración de Git. Podés reactivarlo con:
$ git config --global color.status autoO forzar el uso de colores globalmente:
$ git config --global color.ui trueAhora estás listo para una interpretación visual rápida de cada sesión de git status.
git diff: viendo los cambios en detalle
Mientras que git status te dice qué ha cambiado, git diff te muestra cómo ha cambiado. Hay tres variantes primarias que necesitas conocer:
| Comando | Muestra |
|---|---|
git diff |
Cambios no stageados (diferencia entre el directorio de trabajo y el índice). |
git diff --cached (o git diff -c) |
Cambios staged (diferencia entre el índice y el último commit). |
git diff HEAD |
Lo mismo que git diff (área de trabajo vs HEAD) – útil para comparar con la rama actual. |
También podés combinar con referencias como git diff HEAD~1 para comparar con el commit anterior, o git diff branch_name para ver cómo se vería el diff si fusionáramos otra rama.
git diff: cambios sin stagear
Imaginá que editás archivo_ejemplo.txt con un editor de texto. Después de la edición, ejecutás:
$ git diffLa salida te mostrará una unión unificada de diff de una línea con el contexto surrounding:
$ git diff
index 1234567..89abcde 100644
--- a/archivo_ejemplo.txt
+++ b/archivo_ejemplo.txt
@@ -1,5 +1,5 @@
Este es un archivo de ejemplo.
-La primera línea es antigua.
+La primera línea es nueva.
El archivo contiene varias líneas.
-La última línea está cambiada.
+La última línea está actualizada.Explicación:
index 1234567..89abcde– identifica los dos hashes de blobs (la versión almacenada en el índice y la versión actual en el directorio de trabajo).--- a/archivo_ejemplo.txt/+++ b/archivo_ejemplo.txt– las rutas de prefijoa/(antiguo) yb/(nuevo). El prefijob/denota el árbol de trabajo.@@ -1,5 +1,5 @@– el hunk de diff: comienza en la línea 1, 5 líneas en ambos lados.- Las líneas comenzando con
-son eliminadas; las líneas comenzando con+son agregadas.
Si tenés múltiples cambios en el mismo archivo, Git agrupará cambios contiguos en hunks para mantener la salida compacta.
git diff --cached (o git diff -c): cambios staged
Ahora agregá esos cambios al área de staging:
$ git add archivo_ejemplo.txtAhora ejecutá git diff --cached:
$ git diff --cached
index 89abcde..fedcba 100644
--- a/archivo_ejemplo.txt
+++ b/archivo_ejemplo.txt
@@ -1,5 +1,5 @@
Este es un archivo de ejemplo.
-La primera línea es antigua.
+La primera línea es nueva.
El archivo contiene varias líneas.
-La última línea está cambiada.
+La última línea está actualizada.Observa que la diff es idéntica a la anterior (porque solo había un cambio). Pero este diff representa la diferencia entre el índice (staged) y el commit más reciente. Si tenías cambios tanto en staged como sin stagear, git diff y git diff --cached mostrarán dos conjuntos de cambios separados.
Otros sabores útiles de git diff
git diff HEAD– muestra cambios sin stagear contra el commit más reciente (equivalente agit diffcuando no hay cambios staged).git diff HEAD~1– muestra cambios comparando el commit actual con su padre (útil para revisar el diff de un commit individual).git diff --no-ext-diff– fuerza el uso del diff integrado en lugar de programas externos comodiff.git diff --word-diff– muestra cambios en términos de palabras en lugar de líneas, útil para diffs pequeños.git diff --stat– da un resumen rápido de cuántos archivos cambiaron y cuántas líneas, por ejemplo:$ git diff --stat 2 archivos cambiados, 5 inserciones (+), 3 eliminaciones (-)
Estas banderas pueden combinarse; por ejemplo, git diff --cached --stat te da un conteo rápido de cambios staged.
Escenarios paso a paso: comandos y salidas esperadas
A continuación, exploraremos escenarios realistas y mostraremos exactamente qué verás en la terminal después de cada comando. Este enfoque práctico te ayudará a reconocer los patrones.
Escenario 1: Repositorio limpio (sin cambios)
Empezamos con un repositorio recién inicializado que ya tiene algunos commits. Ejecutamos git status:
$ git status
En la rama 'main'
Todo limpioNo hay secciones de archivos. La frase "Todo limpio" indica que el área de trabajo, el área de staging y HEAD están sincronizados.
Escenario 2: Modificar un archivo sin staging
Editá README.md agregando una nueva línea al principio. Luego ejecutá git status:
$ git status
En la rama 'main'
Los siguientes archivos han sido modificados pero todavía no están en la lista:
(usa "git add <archivo>..." para agregarlos al área de staging)
README.mdAhora podés ver el diff:
$ git diff
index 9f7b2c1..3e8a4d5 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,11 @@
# Mi Proyecto
-Esto es el contenido original.
+Esto es el contenido original.
+Linea agregada por el desarrollador.
El proyecto está en desarrollo activo.El - muestra la línea eliminada (originalmente no había nada allí), y + muestra la línea agregada.
Escenario 3: Agregar un nuevo archivo sin staging
Creá un nuevo archivo script.sh con alguna lógica. Ejecutá git status:
$ git status
En la rama 'main'
Los siguientes archivos han sido agregados pero todavía no están en la lista:
(usa "git add <archivo>..." para agregarlos al área de staging)
script.shgit diff no mostrará nada para archivos nuevos porque no hay diff previo; podés inspeccionar el contenido con git diff --cached (no tiene staged aún) o git show --stat. Para ver el diff contra la versión no existiente, podés usar git diff --no-index /dev/null script.sh, pero normalmente solo querés agregar el archivo.
Escenario 4: Eliminar un archivo sin staging
Borrá registro_antiguo.log. Luego ejecutá git status:
$ git status
En la rama 'main'
Los siguientes archivos han sido eliminados pero todavía no están en la lista:
(usa "git rm --cached <archivo>..." para eliminarlos de la lista)
registro_antiguo.logPara ver la diff de eliminación (área de trabajo vs HEAD), podés usar:
$ git diff
index 9f7b2c1..0000000 100644
--- a/registro_antiguo.log
+++ b/registro_antiguo.log
@@ -1,3 +0,0 @@
linea 1
linea 2
linea 3El diff muestra todas las líneas eliminadas. Si quieres stagear la eliminación (para que sea parte del próximo commit), usá git add registro_antiguo.log (o git rm registro_antiguo.log).
Escenario 5: Agregar un archivo al área de staging
Ahora stageá script.sh:
$ git add script.shEjecutá git status nuevamente:
$ git status
En la rama 'main'
Los siguientes archivos están listos para ser confirmados:
(usa "git rm --cached <archivo>..." para eliminarlos de la lista)
nuevo_script.sh
Los siguientes archivos han sido agregados pero todavía no están en la lista:
(usa "git add <archivo>..." para agregarlos al área de staging)
nuevo_script.shNota cómo nuevo_script.sh aparece tanto en la sección "listos para ser confirmados" como en la sección "agregados pero todavía no están en la lista". Esto parece confuso, pero en realidad es porque el nombre del archivo fue renombrado internamente: Git lo detectó como un nuevo archivo, y también lo stageó. La visualización puede variar ligeramente dependiendo de la versión y configuración de Git. Si querés una visualización más clara, podés desactivar los mensajes de rename usando git config --global status.showRenameInfo false.
Ahora git diff --cached mostrará los cambios que se van a commitear (el contenido completo del archivo en este caso, ya que es nuevo):
$ git diff --cached
index 0000000..a1b2c3d 100644
--- /dev/null
+++ b/nuevo_script.sh
@@ -0,0 +1,9 @@
#!/bin/bash
echo "Hola, mundo"
# Un comentario simpleEl diff usa /dev/null como antiguo porque el archivo no existía antes.
Escenario 6: Modificar un archivo y cambiar su estado de staging
Editá README.md nuevamente, y luego stageá el cambio. Después de git add README.md, ejecutá git status:
$ git status
En la rama 'main'
Los siguientes archivos están listos para ser confirmados:
(usa "git rm --cached <archivo>..." para eliminarlos de la lista)
README.mdAhora git diff --cached mostrará solo el diff más reciente (el segundo cambio) porque el diff previo ya está en el commit. git diff mostrará un diff separado si hay cambios adicionales sin stagear.
Escenario 7: Colisiones y conflictos (cuando mergeas)
Imaginá que tenés una rama feature con cambios en archivo_común.txt. Intentás fusionarla a main usando git merge feature. Si archivo_común.txt también tiene cambios no stageados en main, Git reportará un conflicto:
$ git merge feature
Auto-merging archivo_común.txt
CONFLICTO (contenido): Conflicto al fusionar.
Abortando la fusión.Puedes usar git status para ver el conflicto resaltado:
$ git status
En la rama 'main'
Los siguientes archivos tienen conflictos que deben ser resueltos:
(usa "git add <archivo>..." para marcarlos como resueltos)
archivo_común.txtAhora git diff mostrará marcas especiales <<<<<<<, =======, >>>>>>> dentro del archivo, mostrando las versiones en conflicto. Una vez que edites el archivo y lo resolvás, podés ejecutar git add archivo_común.txt para continuar con la fusión.
Buenas prácticas y errores comunes
1. Aprovechá --porcelain para scripts
Si estás escribiendo un script de CI/CD que necesita detectar cambios rápidamente, git status --porcelain da una salida limpia y parseable:
#!/bin/bash
# Detectar cambios no stageados
while IFS= read -r linea; do
caso "${linea:0:2}" in
" M")
echo "Archivo modificado sin stagear: ${linea:3}" ;;
" A")
echo "Nuevo archivo stageado: ${linea:3}" ;;
"??")
echo "Nuevo archivo sin seguimiento: ${linea:3}" ;;
esac
done < <(git status --porcelain)Esto te ayuda a automatizar el stageo o el reporte de cambios sin necesidad de lidiar con el texto descriptivo.
2. Evitá commits de archivos grandes o binarios
git diff mostrará diffs binarios que son esencialmente una visión de textura de las diferencias, lo cual puede ser huge. Para activos binarios como imágenes o archivos compilados, debería haber una entrada en .gitignore o deberían ser almacenados en un registro separado. Si accidentalmente ves cambios binarios, git diff --textconv puede intentar mostrarlos como texto.
3. Mantené .gitignore actualizado
El comando git status mostrará archivos nuevos que coinciden con las reglas de .gitignore como ??. Por ejemplo, si agregás *.log a .gitignore y luego creás debug.log, Git lo marcará como "sin seguimiento", pero no lo incluirá en el próximo commit a menos que lo agregues explícitamente. Esto es bueno para mantener limpio el historial.
4. Uso de git reset para revertir cambios no deseados
Si ves un cambio en git diff que no querés commitear, podés:
- Sacarlo del área de staging sin modificar el archivo:
git reset HEAD <archivo>. - Desechar los cambios del área de trabajo (perder las ediciones):
git checkout -- <archivo>. - Deshacer ambas cosas (si estás en un commit limpio):
git reset --hard HEAD~1(cuidado, esto es destructivo).
5. Comprender que git diff solo muestra diferencias a nivel de línea, no de contenido
Si estás buscando cambios sutiles (por ejemplo, un espacio extra), git diff mostrará la línea con un \ y el cambio. Podés usar git diff --ignore-all-space para ignorar los espacios en blanco si están presentes. Para una comparación más detallada, git diff --word-diff mostrará las palabras cambiadas.
6. Uso de git diff para revisar commits anteriores
Cuando necesités verificar exactamente lo que un commit anterior hizo, git show <hash> mostrará tanto el commit metadata como el diff. También puedes hacer git diff <hash>^ <hash> para obtener el diff entre dos commits.
7. Evitá "difs sucios" en ramas compartidas
Si trabajas en una rama que va a ser fusionada (por ejemplo, develop), es buena práctica asegurar que git status sea limpio antes de empezar a mergear. Si hay cambios sin stagear, puedes temporariamente moverlos a un branch de características o guardarlos con git stash:
$ git stash
$ git statusLuego, después de terminar con el merge, podés recuperarlos con git stash pop.
8. Colores y configuración para una mejor visibilidad
Podés personalizar el color de git status por rama usando git config color.status always. Para las diffs, git config --global diff.color.diff auto (o true) asegurará resaltados para git diff.
9. Evitá depender demasiado de git status para la precisión
Aunque git status es una excelente señal de tráfico, no es infalible. Si eliminaste un archivo pero luego lo recuperaste manualmente, git status podría mostrarlo como eliminado. Siempre vale la pena revisar con git diff y git ls-files para estar seguro.
10. Usa git ls-files --others --exclude-standard para detectar archivos no rastreados
A veces git status oculta archivos nuevos que son ignorados por .gitignore. Para una detección completa, podés ejecutar:
$ git ls-files --others --exclude-standardEsto enumerará todos los archivos no rastreados que Git normalmente omitiría.
Resumen rápido de comandos
| Objetivo | Comando | Salida típica |
|---|---|---|
| Ver estado general | git status |
Resumen legible por humanos con colores |
| Formato parseable | git status --porcelain / -s |
Códigos de dos caracteres (M, A, D, ??, etc.) |
| Diff de cambios sin stagear | git diff |
Unión unificada de diff (líneas eliminadas/agregadas) |
| Diff de cambios staged | git diff --cached o git diff -c |
Igual que git diff pero contra el índice |
| Diff contra último commit | git diff HEAD |
Igual que git diff (si no hay staged) |
| Diff con un commit anterior | git diff HEAD~1 |
Diff del commit padre |
| Ver diff en resumen | git diff --stat |
Resumen de conteo de archivos y líneas |
| Nuevo archivo para staging | git add <archivo> |
Aparece en la sección de staged de git status |
| Deshacer staging de un archivo | git reset HEAD <archivo> |
El archivo aparece en la sección sin stagear |
| Descartar cambios en el área de trabajo | git checkout -- <archivo> |
El archivo vuelve a su estado anterior |
| Guardar cambios temporalmente | git stash |
Las ediciones son eliminadas del área de trabajo, lista para pop |
| Recuperar cambios almacenados | git stash pop o git stash apply |
Las ediciones son restauradas |
| Listar archivos no rastreados | git ls-files --others --exclude-standard |
Nombres de archivos que Git ignora normalmente |
| Mostrar diff de un commit | git show <hash> |
Diff completo con metadata del commit |
Conclusión
Git es una herramienta de poderosísima que funciona mejor cuando entendés su flujo de trabajo interno: el área de trabajo (tu edición en tiempo real) → el área de staging (lo que estás a punto de confirmar) → el historial de commits (tu línea de tiempo inmutable). git status y git diff son las dos ventanas que te dan visibilidad sobre cada uno de esos pasos.
Al leer git status, sabrás qué archivos han sido modificados, cuáles son nuevos, cuáles han sido eliminados, o si ha habido renames. Usando --porcelain o -s, puedes adaptar la salida para scripts, mientras que el modo coloreado hace que la inspección visual sea rápida.
git diff te da el poder de ver exactamente cómo se ven esos cambios, ya sea que estén en el área de trabajo (sin stagear) o en el área de staging (listos para el commit). Dominar banderas como --cached, HEAD~1, --stat y --word-diff te da flexibilidad para revisar commits antiguos, verificar cambios pequeños o generar diffs compactos para revisión.
Con los escenarios paso a paso que cubrimos, deberías sentirte cómodo enfrentando casos típicos: repositorios limpios, archivos sin stagear, nuevos archivos, eliminados, renames, conflictos y más. Al aplicar las buenas prácticas (mantener .gitignore actualizado, usar git stash cuando sea necesario, aprovechar los formatos parseables), evitarás muchos errores comunes que pueden causar diffs sucios o commits no deseados.
Finalmente, recuerda que la visibilidad es clave para un flujo de trabajo de versionado saludable. Si alguna vez estás dudando sobre lo que estás a punto de commitear, simplemente ejecuta:
$ git status
$ git diff --cachedPara asegurarte de que estás comprometido con exactamente lo que querés. Con estos dos comandos bajo tu cinturón, estás listo para navegar cualquier cambio en tu código base con confianza y precisión.
¡Feliz coding y que tus repositorios siempre estén limpios!
DUGLAS MORENO
Comentarios (0)
Sé el primero en comentar.