Git tiene fama de difícil, y en parte la tiene merecida: su vocabulario es raro y sus mensajes de error no siempre ayudan. Pero el trabajo diario cabe en unas quince órdenes, y casi toda la confusión desaparece en cuanto entiendes que un cambio puede estar en cuatro sitios distintos. Esta guía va por ahí, y todo lo que aparece se ejecutó de verdad con Git 2.47 antes de publicarlo.
Lo que vas a encontrar
1. Las cuatro zonas
Esta es la idea que hay que entender antes que ninguna orden. Un archivo tuyo puede estar en cuatro estados a la vez, y casi todas las preguntas de principiante («¿por qué no se ha subido?», «¿dónde está mi cambio?») se contestan sabiendo en cuál de los cuatro está.
Lo que cuesta al principio es la segunda caja, el área de preparación, que en inglés verás como staging area o index. Parece un paso de más: ¿por qué no se guarda directamente lo que hay en disco? Porque permite elegir. Si has tocado seis archivos pero solo tres pertenecen al mismo arreglo, preparas esos tres y haces un commit limpio, en vez de un revoltijo.
2. Empezar un repositorio
Antes de nada, decir quién eres
Git firma cada commit con un nombre y un correo. Si no los configuras, la primera vez que intentes guardar algo se quejará:
git config --global user.name "Ana" git config --global user.email "ana@ejemplo.com" git config --global init.defaultBranch main
El --global lo deja puesto para todos tus repositorios. La tercera línea evita el aviso de que la rama por defecto se llamaba master y ahora se recomienda main.
git init — empezar de cero
mkdir tienda && cd tienda git init
salidaInitialized empty Git repository in /home/ana/tienda/.git/
Eso crea una carpeta oculta .git con toda la historia. Si la borras, pierdes el repositorio pero no tus archivos; si borras todo menos .git, puedes recuperar los archivos. Ahí está todo.
git clone — traerse uno que ya existe
git clone https://github.com/usuario/proyecto.git
Descarga la historia completa, crea la carpeta, deja los archivos listos y además configura el remoto origin apuntando a donde lo trajiste. Es init más remote add más pull, en un paso.
3. El ciclo de todos los días
Son cuatro órdenes, y se repiten en bucle: mirar, preparar, guardar, comprobar.
git status — la orden que más se teclea
Recién creado el repositorio, con un README.md sin guardar:
git status
salidaOn branch main No commits yet Untracked files: (use "git add <file>..." to include in what will be committed) README.md nothing added to commit but untracked files present (use "git add" to track)
Git es muy hablador y eso ayuda: casi siempre te dice entre paréntesis qué orden usar a continuación. Cuando ya te sabes el camino, git status --short da lo mismo en dos letras por archivo:
git add productos.csv git status --short
salidaA productos.csv ?? ventas.log
| Marca | Qué significa |
|---|---|
?? |
Git no sabe nada de este archivo. Nunca se ha añadido |
A |
Nuevo y ya preparado para el próximo commit |
M |
Modificado y preparado. La M va en la primera columna |
M |
Modificado pero sin preparar. La M va en la segunda |
MM |
Preparaste un cambio y luego seguiste editando |
D |
Borrado |
UU |
Conflicto sin resolver |
La clave de esas dos columnas: la primera es el área de preparación y la segunda es el disco. Por eso MM no es un error, es un archivo que preparaste y después volviste a tocar.
git add y git commit
git add README.md git commit -m "Primer commit: README"
salida[main (root-commit) 5c9a6b2] Primer commit: README 1 file changed, 3 insertions(+) create mode 100644 README.md
Ese 5c9a6b2 es el identificador del commit, los primeros caracteres de un código largo. Sirve para referirse a él en cualquier otra orden.
| Forma | Qué prepara o guarda |
|---|---|
git add archivo |
Ese archivo |
git add . |
Todo lo que hay de aquí hacia abajo, nuevos incluidos |
git add -p |
Te pregunta trozo a trozo. Útil para partir un cambio grande |
git commit -m "…" |
Guarda lo preparado con ese mensaje |
git commit -am "…" |
Prepara y guarda de golpe, pero solo archivos ya conocidos |
-a no incluye archivos nuevos. git commit -am recoge las modificaciones de lo que Git ya sigue, pero ignora lo que aparece como ??. Es la causa habitual de «hice commit y el archivo no está». Si hay archivos nuevos, git add primero.git diff — qué ha cambiado exactamente
Tras subir un precio y añadir una línea:
git diff
salidadiff --git a/productos.csv b/productos.csv index 18005be..a0b9baf 100644 --- a/productos.csv +++ b/productos.csv @@ -1,3 +1,4 @@ nombre;precio -camiseta;19.90 +camiseta;21.90 gorra;12.50 +bufanda;9.00
Las líneas con - son las que había y las de + las que hay ahora; modificar una línea aparece como quitar una y poner otra. Y aquí está la trampa que confunde a todo el mundo:
git add productos.csv git diff
salida(sin salida)
git diff a secas compara el disco con el área de preparación. En cuanto haces add, los dos coinciden y no hay nada que enseñar. Para ver lo que sí vas a guardar hace falta la otra forma:
git diff --staged
| Orden | Compara |
|---|---|
git diff |
Disco contra área de preparación: lo que aún no has preparado |
git diff --staged |
Área de preparación contra el último commit: lo que vas a guardar |
git diff HEAD |
Disco contra el último commit: todo lo que ha cambiado |
git diff rama1 rama2 |
Dos ramas entre sí |
4. Qué no guardar
Un archivo .gitignore en la raíz dice qué no debe seguir Git. Una línea por patrón:
*.log node_modules/ __pycache__/ .env build/ *.sqlite3
Cuenta como un archivo más del proyecto, así que se añade y se guarda en un commit como cualquier otro: lo que tú ignoras lo ignora también quien clone el repositorio.
.env con contraseñas que entra en un commit no se arregla borrándolo en el commit siguiente, porque sigue en la historia y cualquiera que clone el repositorio puede recuperarlo. Si pasa, da por comprometida esa credencial y cámbiala; limpiar la historia es un trabajo aparte y mucho más incómodo..gitignore llega tarde. Solo afecta a lo que Git todavía no conoce. Para que deje de seguirlo sin borrarlo del disco: git rm --cached archivo, y después un commit.5. Deshacer: la parte difícil
Aquí es donde Git se gana su fama, porque hay cinco órdenes distintas y la que necesitas depende de en qué zona está lo que quieres deshacer. Vamos por casos.
Descartar un cambio del disco
Has tocado un archivo, no te gusta y quieres volver a como estaba:
git status --short git restore productos.csv git status --short
salida M productos.csv (limpio)
git restore sobre un archivo sin preparar tira el trabajo sin pasar por ninguna parte: no hay commit que lo guarde ni papelera de donde sacarlo. Es la única orden de esta guía que destruye algo que Git nunca llegó a ver.Sacar algo del área de preparación
Hiciste git add de algo que no querías incluir. El cambio no se pierde, solo retrocede una zona:
git restore --staged borrador.txt git status --short
salida?? borrador.txt
Corregir el último commit
El mensaje tenía una errata, o se te olvidó incluir un archivo. --amend reemplaza el último commit en vez de añadir otro:
git commit --amend -m "Sube el precio de la camiseta y anade .gitignore" git log --oneline
salida9af611a Sube el precio de la camiseta y anade .gitignore e4d77a7 Anade el catalogo de productos 5c9a6b2 Primer commit: README
Fíjate en que siguen siendo tres commits, no cuatro: el anterior ha desaparecido y en su lugar hay otro, con otro identificador. Eso último importa y lo retomamos en el aviso del final de esta sección.
Deshacer commits: las tres caras de reset
La misma orden hace tres cosas distintas según la opción, y la diferencia está exactamente en hasta qué zona retrocede. Partiendo de dos commits:
git log --oneline
salidaf60a94d Commit B 6cfc382 Commit A
git reset --soft HEAD~1 git log --oneline git status --short
salida6cfc382 Commit A A b.txt
El commit ha desaparecido, pero su contenido sigue preparado, listo para volver a guardarlo mejor. Si añadimos un paso más:
git reset git status --short
salida?? b.txt
Ahora ya no está preparado, pero el archivo sigue en el disco. Y la tercera:
git reset --hard HEAD~1 git log --oneline ls
salidaHEAD is now at 6cfc382 Commit A 6cfc382 Commit A a.txt
El archivo b.txt ya no está. --hard arrasa las tres zonas de golpe.
| Orden | Quita el commit | Vacía la preparación | Borra del disco |
|---|---|---|---|
git reset --soft |
sí | no | no |
git reset (mixed) |
sí | sí | no |
git reset --hard |
sí | sí | sí |
git revert — deshacer sin reescribir
Las anteriores borran historia. revert hace lo contrario: deja el commit donde está y añade otro encima que lo anula.
git revert --no-edit HEAD git log --oneline
salida[main 7e315fc] Revert "Sube el precio de la camiseta y anade .gitignore" 2 files changed, 1 insertion(+), 3 deletions(-) 7e315fc Revert "Sube el precio de la camiseta y anade .gitignore" 9af611a Sube el precio de la camiseta y anade .gitignore e4d77a7 Anade el catalogo de productos 5c9a6b2 Primer commit: README
Parece más aparatoso, porque la historia se alarga en vez de acortarse, y es justo eso lo que lo hace seguro.
git stash — aparcar lo que tienes a medias
Estás con algo sin terminar y te piden mirar otra cosa. stash guarda tu trabajo en un cajón aparte y te deja el repositorio limpio:
git stash git status --short
salidaSaved working directory and index state WIP on main: 564c449 Reapply "Sube el precio…" (limpio)
git stash list git stash pop
salidastash@{0}: WIP on main: 564c449 Reapply "Sube el precio…"
Changes not staged for commit:
modified: productos.csv
Dropped refs/stash@{0} (d2f6ca9e7777f12c0047f6175845437ee61991fd)
pop lo devuelve y vacía el cajón; git stash apply lo devuelve pero lo conserva guardado.
reset y --amend reescriben la historia: cambian o eliminan commits que ya existían. Si esos commits todavía no han salido de tu máquina, perfecto. Si ya los has subido con push y alguien más los tiene, reescribirlos obliga a un push --force que romperá el repositorio de tus compañeros. Para deshacer algo ya compartido, revert.| Lo que quieres deshacer | La orden |
|---|---|
| Un cambio en el disco, sin preparar | git restore archivo |
Un git add que no querías |
git restore --staged archivo |
| El mensaje del último commit | git commit --amend |
| El último commit, para rehacerlo mejor | git reset --soft HEAD~1 |
| Todo lo local, volver al último commit | git reset --hard HEAD |
| Un commit que ya está compartido | git revert <commit> |
| Nada; solo aparcarlo un rato | git stash |
6. Ramas
Una rama es una línea de trabajo paralela. Te separas de main, haces lo tuyo sin molestar a nadie, y cuando funciona lo devuelves.
git switch -c descuentos
salidaSwitched to a new branch 'descuentos'
El -c es de crear. Sin él, git switch descuentos se cambia a una rama que ya existe. Para ver cuáles hay, con un asterisco en la actual:
git branch
salida* descuentos main
Terminado el trabajo, se vuelve a main y se fusiona:
git switch main git merge descuentos
salidaSwitched to branch 'main' Updating 564c449..2e3967a Fast-forward productos.csv | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
Ese fast-forward significa que main no se había movido mientras trabajabas, así que Git no ha tenido que inventar nada: simplemente ha adelantado la etiqueta. Cuando las dos ramas han avanzado, crea un commit de fusión con dos padres, como la M del esquema.
| Orden | Qué hace |
|---|---|
git switch rama |
Cambia a una rama existente |
git switch -c rama |
La crea y se cambia a ella |
git switch - |
Vuelve a la rama anterior |
git branch |
Lista las ramas locales |
git branch -d rama |
Borra una rama ya fusionada |
git merge rama |
Trae esa rama a la actual |
git checkout, no estaba mal. checkout hacía de todo: cambiar de rama, restaurar archivos y moverse a un commit concreto, y por eso era confuso. Desde la versión 2.23 ese trabajo está repartido en git switch para las ramas y git restore para los archivos. checkout sigue funcionando, pero las dos nuevas son más claras.7. Conflictos
Un conflicto no es un error ni algo que hayas hecho mal: es Git diciendo que dos ramas tocaron las mismas líneas y que la decisión es tuya.
git merge rebajas
salidaAuto-merging ficha.txt CONFLICT (content): Merge conflict in ficha.txt Automatic merge failed; fix conflicts and then commit the result.
Abres el archivo y te encuentras esto dentro:
ficha.txt<<<<<<< HEAD precio: 24.90 ======= precio: 14.90 >>>>>>> rebajas stock: 40
Observa que stock: 40 está fuera de las marcas: Git solo pide ayuda en las líneas que no sabe resolver, el resto lo fusiona solo. Tú editas, dejas el contenido que quieras —puede ser una de las dos versiones, o una tercera cosa—, borras las tres líneas de marcas y cierras:
git add ficha.txt git commit -m "Fusiona rebajas: precio intermedio" git log --oneline --graph
salida* f7f6816 Fusiona rebajas: precio intermedio |\ | * 5834f54 Rebaja el precio * | 258088c Sube el precio por temporada |/ * ec9b9a7 Ficha inicial
Ahí se ven las dos ramas separándose y volviendo a juntarse. Y si en mitad del lío prefieres no seguir, git merge --abort deja todo exactamente como estaba antes de empezar.
8. Trabajar con un remoto
Hasta aquí todo ha pasado en tu máquina. Un remoto es una copia del repositorio en otro sitio, que por convención se llama origin.
git remote add origin https://github.com/usuario/tienda.git git remote -v
salidaorigin https://github.com/usuario/tienda.git (fetch) origin https://github.com/usuario/tienda.git (push)
El primer envío lleva un -u que emparenta tu rama local con la del remoto. Solo hace falta la primera vez:
git push -u origin main
salida * [new branch] main -> main branch 'main' set up to track 'origin/main'.
A partir de ahí basta con git push, y además git status empieza a decirte cómo vas respecto al remoto:
git fetch origin git status -sb
salidaFrom /home/ana/servidor 2e3967a..b8c0202 main -> origin/main ## main...origin/main [behind 1]
Ese behind 1 dice que hay un commit en el remoto que tú no tienes. Y aquí está la diferencia que más se pregunta:
| Orden | Qué hace |
|---|---|
git fetch |
Descarga lo nuevo pero no toca tus archivos. Puedes mirarlo antes |
git pull |
fetch y además lo fusiona con tu rama, en un paso |
git push |
Sube tus commits al remoto |
Con fetch hecho, se puede ver exactamente qué va a entrar antes de aceptarlo:
git log --oneline HEAD..origin/main
salidab8c0202 Anade mochila
git pull
salidaUpdating 2e3967a..b8c0202 Fast-forward productos.csv | 1 + 1 file changed, 1 insertion(+)
push es rechazado con un mensaje sobre non-fast-forward, no es que hayas roto nada: alguien subió algo mientras tú trabajabas. Se arregla con git pull y volviendo a empujar. Lo que no hay que hacer es responder con --force, que borraría el trabajo de la otra persona.9. Mirar la historia
git log a secas saca un párrafo por commit y llena la pantalla. La forma que se usa de verdad es esta, y merece la pena aprendérsela:
git log --oneline --graph --decorate -4
salida* 2e3967a (HEAD -> main, descuentos) Anade columna de descuento * 564c449 Reapply "Sube el precio de la camiseta y anade .gitignore" * 7e315fc Revert "Sube el precio de la camiseta y anade .gitignore" * 9af611a Sube el precio de la camiseta y anade .gitignore
El --decorate es lo que añade entre paréntesis dónde apuntan las etiquetas: ahí se ve que HEAD, main y descuentos están en el mismo commit.
Dos formas más que resuelven preguntas concretas. La historia de un solo archivo:
git log --oneline -- productos.csv
Y quién escribió cada línea, con el commit y la fecha al lado:
git blame productos.csv
salida2e3967a3 (Ana 2026-10-05 19:00:12 +0000 1) nombre;precio;descuento 2e3967a3 (Ana 2026-10-05 19:00:12 +0000 2) camiseta;21.90;10 2e3967a3 (Ana 2026-10-05 19:00:12 +0000 3) gorra;12.50;0 2e3967a3 (Ana 2026-10-05 19:00:12 +0000 4) bufanda;9.00;25
Etiquetas
Una etiqueta marca un punto de la historia con un nombre, normalmente una versión publicada:
git tag -a v1.0 -m "Primera version publicada" git tag
salidav1.0
Las etiquetas no se suben con un push normal; hay que pedirlo: git push origin v1.0, o git push --tags para todas.
10. Configuración que merece la pena
Tres ajustes que ahorran tiempo desde el primer día:
git config --global pull.rebase false git config --global core.editor "nano" git config --global alias.lg "log --oneline --graph --decorate -15"
El primero fija qué hace pull cuando hay que mezclar, y quita un aviso que Git repite si no lo has decidido. El segundo evita que se abra vim cuando Git te pide un mensaje, que es el momento en que mucha gente se queda atrapada sin saber salir. El tercero crea un atajo: a partir de ahí, git lg enseña el gráfico de la historia.
:wq y Intro para guardar y salir, o :q! para salir sin guardar.Para ver todo lo que tienes configurado y de qué archivo sale cada cosa: git config --list --show-origin.
11. La chuleta
| Quiero… | Orden |
|---|---|
| Saber cómo está todo | git status --short |
| Ver qué he cambiado | git diff |
| Ver qué voy a guardar | git diff --staged |
| Guardar lo preparado | git commit -m "…" |
| Corregir el último commit | git commit --amend |
| Descartar un cambio del disco | git restore archivo |
Quitar un add |
git restore --staged archivo |
| Deshacer el último commit, conservando el trabajo | git reset --soft HEAD~1 |
| Deshacer un commit ya compartido | git revert <commit> |
| Aparcar lo que tengo a medias | git stash y luego git stash pop |
| Crear una rama y cambiarme | git switch -c rama |
| Volver a la rama anterior | git switch - |
| Traer una rama a la actual | git merge rama |
| Cancelar una fusión con conflictos | git merge --abort |
| Ver qué hay de nuevo sin aplicarlo | git fetch y git log HEAD..origin/main |
| Traer y mezclar | git pull |
| Subir | git push |
| Ver la historia de un vistazo | git log --oneline --graph --decorate |
| Saber quién escribió una línea | git blame archivo |
Todas las órdenes y todas las salidas de esta página se ejecutaron con Git 2.47.3 sobre Debian 13 en un contenedor limpio antes de publicarla, con un usuario normal; están copiadas de esa ejecución, no redactadas. Los conflictos y los errores son reales, provocados a propósito. Los identificadores de commit que aparecen son los de esa sesión y serán distintos en tu máquina. El logotipo de la portada es de Jason Long, bajo licencia CC BY 3.0. Si esto te sirve, en la misma sección están los comandos de Linux y la guía de Docker.