Las tres zonas de Git
Git no es "una carpeta con copias". Un cambio viaja por tres zonas antes de quedar grabado en la historia del proyecto:
- Working directory (directorio de trabajo): tus archivos tal cual los editas. Aquí los cambios todavía no los conoce Git.
- Staging area (índice): la "sala de embarque". Eliges qué cambios entran
en el próximo commit con
git add. - Historial (repositorio local): la secuencia inmutable de commits. Solo
git commitmueve algo aquí.
git status # ¿qué hay en cada zona?
git add archivo.js # working -> staging (preparas el cambio)
git add . # prepara TODO lo modificado
git commit -m "feat: añade login" # staging -> historial
Idea clave: solo
git commitescribe en el historial.git addno crea un punto de guardado; solo prepara lo que entrará en el siguiente commit.
Un commit es una instantánea identificada por un hash (SHA), con autor, fecha, mensaje y un puntero a su commit padre. Esa cadena de padres es la historia.
Ramas (branches)
Una rama es un puntero ligero a un commit. Crear una rama es casi gratis y
te permite trabajar en paralelo sin tocar main:
git branch # lista las ramas (la actual con *)
git switch -c feature/login # crea y se cambia a una rama nueva
git switch main # vuelve a main
git log --oneline --graph # ve el árbol de commits
HEAD es un puntero a "dónde estás" (normalmente la rama actual).
Integrar trabajo: merge vs rebase
Cuando tu rama y main han avanzado por separado, hay que integrar. Dos
estrategias:
git merge
Crea un commit de fusión que une las dos historias. No reescribe nada: conserva el grafo real de cómo ocurrió el trabajo.
git switch main
git merge feature/login # crea un merge commit que une ambas ramas
git rebase
Reaplica tus commits encima de la punta de main, como si los hubieras
escrito a partir de ahí. El resultado es una historia lineal, sin commits de
fusión.
git switch feature/login
git rebase main # mueve tus commits encima de main (los reescribe)
¿Cuándo cada uno?
- merge para integrar una rama en
main(especialmente al cerrar un PR): preserva el contexto y es seguro en ramas compartidas. - rebase para limpiar tu propia rama antes de abrir el PR (ponerla al
día con
main, agrupar commits). Historia lineal y fácil de leer.
Regla de oro: nunca hagas
rebasede commits que ya has publicado y otros han descargado. Reescribir historia compartida rompe el repo de tus compañeros. Rebasea en privado, mergea en público.
Resolver conflictos
Un conflicto ocurre cuando merge/rebase no puede combinar dos cambios sobre las mismas líneas. Git marca el archivo así:
<<<<<<< HEAD
const saludo = "Hola";
=======
const saludo = "Buenas";
>>>>>>> feature/login
Editas el archivo dejando la versión final (borrando los marcadores), y luego:
git add archivo.js # marca el conflicto como resuelto
git commit # en merge: cierra la fusión
# o, si estabas en rebase:
git rebase --continue
git rebase --abort # cancela y vuelve al estado anterior
Deshacer: revert vs reset
git revert <commit>: crea un commit nuevo que invierte los cambios de otro. No borra historia -> es la forma segura en ramas compartidas.
git revert a1b2c3d # añade un commit que deshace a1b2c3d
git reset: mueve la rama a otro commit, descartando los posteriores del historial. Reescribe historia -> úsalo solo en cambios locales.
git reset --soft HEAD~1 # deshace el último commit, deja los cambios en staging
git reset --mixed HEAD~1 # (por defecto) deshace commit y staging; conserva archivos
git reset --hard HEAD~1 # deshace TODO, incluso tus archivos (peligroso)
Resumen: en algo ya publicado, revert. En commits locales que aún no compartiste, reset.