En esta página
Git: commits, ramas y flujos de trabajo
Git es un sistema de control de versiones: guarda el historial de un proyecto para que puedas volver atrás, comparar cambios y trabajar con otras personas sin pisarse. No es una carpeta en la nube ni un botón de "guardar": es una base de datos de estados del proyecto.
Este documento va de menos a más. Primero, qué es un commit y qué es una rama (los dos conceptos sin los cuales nada de lo demás se entiende). Después, cómo usarlos. Al final, dos formas de organizar el trabajo en equipo: GitHub Flow y Git Flow.
El modelo mental
directorio de trabajo → staging area → repositorio → remoto
(tus archivos) (git add) (git commit) (git push)
| Lugar | Qué hay |
|---|---|
| directorio de trabajo | los archivos tal como los ves y editas |
| staging area (índice) | lo que va a entrar en el próximo commit |
| repositorio local | el historial de commits, en .git/ |
| remoto | la copia en GitHub, GitLab o el servidor que uses, para compartir y respaldar |
Cuando guardas un archivo con Ctrl+S, pisas la versión anterior. Git hace lo
contrario: agrega un estado nuevo al historial y deja el anterior intacto.
Eso es lo que permite volver atrás.
Qué es un commit
Un commit es una foto del proyecto completo en un momento dado, con una etiqueta que la identifica. No guarda "solo las líneas que cambiaron": guarda el estado de todos los archivos que estaban en el staging area, más los datos de quién lo hizo y cuándo.
Cada commit contiene:
| Dato | Para qué sirve |
|---|---|
| snapshot | el contenido de los archivos en ese momento |
| autor y fecha | saber quién hizo el cambio y cuándo |
| mensaje | explicar por qué se hizo |
hash (por ejemplo a1b2c3d) | un identificador único para nombrarlo |
| commit padre | el commit anterior, que forma una cadena |
Pensalo como guardar la partida de un videojuego: no modificas la partida anterior, creas una nueva. Si algo sale mal, cargas la anterior.
Los commits se encadenan. La rama en la que estás apunta al último commit, y
ese commit apunta a su padre. HEAD es el nombre que Git le da a "el commit
donde estás parado ahora".
Por qué te conviene commitear
| Ventaja | Qué te resuelve |
|---|---|
| Volver atrás | si rompiste algo, recuperas un estado que funcionaba |
| Entender el pasado | git log y git diff muestran qué cambió y cuándo |
| Probar sin miedo | puedes experimentar sabiendo que hay una red de seguridad |
| Trabajar en paralelo | otras personas pueden partir del mismo historial |
| Respaldar | el remoto guarda una copia fuera de tu máquina |
| Revisar | un cambio chico se lee y se discute mucho mejor que uno gigante |
La regla práctica: commitea seguido y en pasos con sentido. Un commit que mezcla "arreglo el login", "cambio el color del botón" y "actualizo la documentación" no se puede revertir sin arrastrar lo demás.
Qué es una rama
Una rama es un nombre que apunta a un commit. Nada más. No es una copia de la carpeta ni un proyecto paralelo: es una etiqueta móvil que dice "esta línea de trabajo va por aquí".
main A ── B ── C
\
feature D ── E
mainapunta aC.featureapunta aE.- Las dos ramas comparten los commits
A,ByC.
Cuando haces un commit estando en feature, el puntero feature avanza al
commit nuevo. main se queda donde estaba. Por eso crear una rama es
instantáneo: solo se crea un nombre nuevo.
Un merge es unir dos líneas de trabajo: traer los commits de una rama a la otra y crear un commit que las conecta (o reubicar los commits, si se usa rebase).
Por qué te conviene usar ramas
| Ventaja | Qué te resuelve |
|---|---|
| Aislar un cambio | main sigue funcionando mientras pruebas algo |
| Experimentar | si la idea no sirve, borras la rama y listo |
| Revisar mejor | el cambio completo se ve junto, separado del resto |
| Trabajar en paralelo | dos personas no se pisan en la misma línea |
| Revertir sin drama | si el cambio salió mal, se revierte esa rama |
| Ordenar el historial | cada rama cuenta una historia con principio y fin |
main (o master en proyectos viejos) es la rama principal: la que se supone
que siempre funciona. Las demás son temporales y se borran después de integrarse.
Por qué conviene usar Git (y no solo "guardar como")
| Sin Git | Con Git |
|---|---|
trabajo_final_v2_este_si.zip | un historial legible de commits |
| no sabes qué cambió entre versiones | git diff responde en segundos |
| dos personas se pisan los archivos | ramas separadas y merges controlados |
| un error borra horas de trabajo | git reflog recupera casi todo |
| no hay respaldo fuera de tu máquina | el remoto guarda una copia |
| no puedes explicar por qué cambió algo | el mensaje del commit lo explica |
Git no te obliga a trabajar de una sola forma. Te da las piezas; el flujo de trabajo es el acuerdo de cómo usarlas en equipo.
Configuración inicial (una sola vez)
git config --global user.name "Tu Nombre"
git config --global user.email "tu@email.com"
git config --global init.defaultBranch main
git config --global pull.rebase false
Verificá:
git config --list
El nombre y el email quedan dentro de cada commit. Si están mal, todos tus commits muestran la identidad equivocada.
Crear o traer un repositorio
git init # empieza uno nuevo en la carpeta actual
git clone URL # trae uno existente
git clone git@github.com:usuario/repo.git # por SSH
.gitignore le dice a Git qué no trackear. Para un proyecto en C, lo
mínimo:
a.out
*.o
programa
.DS_Store
Si ya commiteaste un archivo que ahora está en
.gitignore, Git lo sigue trackeando. Hay que sacarlo del índice:git rm --cached archivo.
El ciclo diario
git status # ¿qué cambió?
git diff # cambios sin stage
git diff --staged # cambios en stage
git add archivo.c # prepara UN archivo
git add . # prepara todo (revisa con status antes)
git commit -m "Add main" # guarda la foto
git log --oneline --graph # historial resumido
git status es el comando que más vas a usar. Si alguna vez no sabes qué está
pasando, empieza por ahí: te dice en qué rama estás, qué está modificado y qué
está listo para commitear.
Buenos mensajes de commit
| Malo | Mejor |
|---|---|
cambios | Fix off-by-one in pagination |
arreglo | Handle empty input without crashing |
asd | Add helper to print one character |
La convención más usada: imperativo, en inglés, menos de 50 caracteres en la primera línea; si hace falta explicar, deja una línea en blanco y un párrafo.
Add guard clause for invalid sizes
Without it, negative heights make the row condition meaningless
and the loop never ends.
Ramas y merges
git switch -c feature/guard-clause # crea y cambia
git switch main # vuelve a main
git branch # lista ramas
git merge feature/guard-clause # trae los cambios a la rama actual
git branch -d feature/guard-clause # borra la rama ya mergeada
git checkouttodavía funciona, peroswitch(ramas) yrestore(archivos) son más claros y no se confunden entre sí. Usa esos.
Conflictos
Un conflicto aparece cuando dos ramas cambiaron la misma línea. Git no adivina: te deja el archivo marcado así:
<<<<<<< HEAD
return (0);
=======
return (1);
>>>>>>> feature/otra
Se resuelve a mano:
- Editas el archivo y dejas el resultado final (borras las marcas).
git add archivogit commit
Regla de oro: no borres el trabajo del otro sin entenderlo. Si dudas, mira
git log --merge o pregunta antes de elegir.
Remoto: subir y bajar
git remote -v # ¿a dónde apunta?
git remote add origin URL # conecta un repo local con GitHub
git push -u origin main # primera subida (crea el tracking)
git push # las siguientes
git fetch # trae novedades SIN tocar tu rama
git pull # fetch + merge en tu rama actual
fetch y pull no son lo mismo:
| Comando | Qué hace | Cuándo |
|---|---|---|
git fetch | actualiza el remoto, no toca tus archivos | quieres ver antes de mezclar |
git pull | fetch + merge | estás seguro y quieres avanzar |
Antes de elegir un flujo
Un flujo de trabajo es un acuerdo del equipo sobre cómo se usan las ramas, los commits y los remotos. No hay uno universal ni uno "correcto": depende de cómo publicas el software, cuánta gente hay y cada cuánto despliegas.
Dos aclaraciones para que los nombres no confundan:
- Pull Request (PR) o Merge Request (MR): una propuesta para integrar una rama a otra. Muestra el diff completo, permite comentar línea por línea, ejecutar pruebas automáticas y pedir aprobación antes de mezclar.
- Merge: la acción de integrar esa rama. La plataforma puede ofrecer distintas estrategias: merge normal (conserva los commits), squash (los aplasta en uno) o rebase (los reubica).
Git es la herramienta; GitHub, GitLab, Bitbucket y compañía son plataformas que agregan revisión y automatización encima. El flujo se puede aplicar en cualquiera.
GitHub Flow (recomendado para empezar)
Una rama por cambio, un Pull Request, y main siempre desplegable. Es el flujo
más simple que sigue siendo serio: no hay ramas permanentes de más, no hay
ceremonia y cualquiera puede entender dónde está cada cosa.
main ────●──────────●──────────●────►
\ / \ /
●──●──● ●──●──●
feature/a feature/b
Los pasos:
- Actualizá
main:git switch main && git pull - Crea una rama con nombre descriptivo:
git switch -c fix/validar-entrada - Commitea en pasos chicos, cada uno con sentido propio.
- Sube la rama:
git push -u origin fix/validar-entrada - Abre un Pull Request en la plataforma que uses y pide revisión.
- Fusiona cuando esté aprobado y las pruebas pasen. Borra la rama.
Por qué funciona tan bien:
| Ventaja | Qué te resuelve |
|---|---|
| Un solo lugar estable | main siempre se puede desplegar |
| Cambios chicos | se revisan rápido y se revierten fácil |
| Revisión antes de integrar | el error se detecta antes de llegar a producción |
| Historia legible | cada PR cuenta un cambio con su contexto |
| Poco protocolo | no hay que memorizar cinco tipos de rama |
Reglas que hacen que funcione:
| Regla | Por qué |
|---|---|
main siempre funciona | cualquiera puede desplegar en cualquier momento |
| ramas cortas (horas o días, no semanas) | menos conflictos y revisiones más fáciles |
| un PR = un cambio | se revisa mejor y se puede revertir solo |
| el PR explica el por qué | el código ya muestra el qué |
| pruebas verdes antes de mergear | no se discute, se verifica |
Con GitHub CLI (gh) los últimos pasos son más rápidos:
gh pr create --fill # abre el PR con los datos del commit
gh pr checks # estado de las pruebas
gh pr merge --squash # mergea aplastando los commits
Git Flow (para releases versionados)
Tiene más ramas y más ceremonia. Se usa cuando publicas versiones (v1.2.0) y
necesitas congelar una versión mientras sigues desarrollando. La diferencia con
GitHub Flow es que aquí develop es la rama de integración y main queda
reservada a lo que ya está en producción.
| Rama | Para qué | Sale de | Vuelve a |
|---|---|---|---|
main | solo código en producción | — | — |
develop | integración del próximo release | main | main |
feature/* | una funcionalidad | develop | develop |
release/* | estabilizar una versión | develop | main y develop |
hotfix/* | arreglo urgente en producción | main | main y develop |
Qué significa cada una en la práctica:
develop: donde se junta todo lo que va a salir en la próxima versión. No se despliega directamente.feature/*: una funcionalidad o un arreglo que todavía no está listo. Sale dedevelopy vuelve adevelop.release/*: una rama para estabilizar la versión que viene. Ahí solo se corrigen errores, no se agregan funciones nuevas.hotfix/*: un arreglo urgente sobre lo que ya está en producción. Sale demainy vuelve amainy adevelop, para que el arreglo no se pierda en la próxima versión.
main ──●──────────────●─────────●──►
\ / /
release ●──●──●────● /
\ /
develop ────●──●──●──●──●───●────►
\ /
feature ●──●
Cuándo usarlo:
- Producto con versiones y soporte de varias a la vez.
- Equipo grande con QA y fechas de release.
- Necesitas un
hotfixsin arrastrar lo que está a medio hacer.
Cuándo no usarlo:
- Proyectos personales, prototipos o apps que despliegas varias veces por día.
- Equipos chicos: el costo de coordinar cinco tipos de rama supera el beneficio.
Comparación rápida
| GitHub Flow | Git Flow | |
|---|---|---|
| Ramas permanentes | main | main + develop |
| Complejidad | baja | media/alta |
| Frecuencia de deploy | continua | por releases |
| Ideal para | web, apps, equipos chicos | productos versionados |
| Riesgo principal | PRs gigantes | ramas que viven meses |
Empieza con GitHub Flow. Si algún día necesitas versiones con soporte, agregas Git Flow sin tirar nada de lo aprendido.
Deshacer sin romper nada
Esto es lo que más miedo da y lo que menos debería. La clave: distinguir si el commit ya lo viste solo tú o ya está publicado.
| Quiero… | Comando | ¿Seguro en remoto? |
|---|---|---|
| descartar cambios de un archivo | git restore archivo | sí (no toca historia) |
| sacar algo del staging | git restore --staged archivo | sí |
| corregir el último commit | git commit --amend | no si ya lo pusheaste |
| deshacer el último commit, dejando cambios | git reset --soft HEAD~1 | solo local |
| deshacer el último commit y los cambios | git reset --hard HEAD~1 | no: borra trabajo |
| revertir un commit publicado | git revert SHA | sí: crea un commit nuevo |
| recuperar algo "perdido" | git reflog | sí: es tu red de seguridad |
git reflog guarda todo movimiento de HEAD, incluso después de un
reset --hard. Mientras no hayas hecho gc, casi siempre se puede volver.
Guardar trabajo a medias
git stash # guarda cambios sin commitear y limpia el directorio
git stash list # ver la pila
git stash pop # recupera y borra de la pila
git stash apply # recupera sin borrar
Útil cuando tienes que cambiar de rama de urgencia. No es un sustituto de los commits: si el trabajo importa, commitealo en una rama.
Etiquetas y releases
git tag -a v1.0.0 -m "Primera versión"
git push origin v1.0.0
Una etiqueta marca un commit con un nombre legible. Es lo que usa Git Flow para saber qué versión está en producción.
Errores frecuentes
| Mensaje / síntoma | Causa | Solución |
|---|---|---|
not a git repository | estás fuera de la carpeta del repo | cd al repo |
nothing to commit | no hay cambios, o no hiciste add | git status |
non-fast-forward al pushear | el remoto tiene commits que no tienes | git pull y vuelve a pushear |
detached HEAD | miraste un commit viejo sin rama | git switch - o git switch main |
Your branch is behind | te falta traer cambios | git pull |
conflicto en git pull | mismas líneas tocadas | resuelve, add, commit |
| commiteaste un secreto | quedó en la historia | rota la clave; no alcanza con borrar el archivo |
Permission denied (publickey) | SSH mal configurado | ver SSH |
borraste trabajo con reset --hard | no hay papelera | git reflog y vuelve al commit |
Flujo mínimo para empezar
git init
git add .
git commit -m "Add initial project structure"
git remote add origin git@github.com:laura/mi-proyecto.git
git push -u origin main
Y a partir de ahí, por cada cambio:
git switch -c feature/validar-entrada
# trabajas, compilas, pruebas
git add .
git commit -m "Validate input before processing"
git push -u origin feature/validar-entrada
# abres el PR, revisas, mergeas
Ese ciclo —rama, commits chicos, push, PR, merge— es GitHub Flow. Si el equipo usa otra plataforma, cambia el nombre del botón, no el concepto.
Siguiente parada: SSH sin miedo.
Hecho con amor para Laura, por Bogdan.