Tutorial de Git: ramas, fusiones y resolución de conflictos
verificado el 7 septiembre 2026 · 10 min
Crea una rama con git switch -c nom, trabaja en ella y fusiónala con git merge desde la rama de destino. Si hay conflicto, Git inserta marcadores en el archivo: escribe el contenido correcto, borra los marcadores y lanza git add y git commit. git merge --abort lo cancela todo en cualquier momento.
Una rama es una línea de desarrollo paralela. Te permite trabajar en una funcionalidad sin tocar la versión estable, y a tu compañero hacer lo mismo por su lado. Este capítulo cubre el ciclo completo: crear una rama, fusionarla, resolver un conflicto a mano y elegir entre merge y rebase.
git switch en lugar de git checkout
Históricamente, git checkout servía para todo: cambiar de rama, crear una, restaurar un archivo, situarse en un commit concreto. Esa acumulación de papeles es la primera fuente de confusión para quien empieza, y una fuente de accidentes para el resto.
Git 2.23, publicado en agosto de 2019, partió el comando en dos: git switch para moverse entre ramas y git restore para deshacer cambios. Al salir se marcaron como experimentales, ya no lo están en la documentación oficial. Este capítulo los usa y da siempre el equivalente con checkout, que seguirás encontrando durante mucho tiempo en tutoriales y en Stack Overflow.
| Intención | Comando moderno | Forma antigua |
|---|---|---|
| Cambiar de rama | git switch nom | git checkout nom |
| Crear una rama y situarse en ella | git switch -c nom | git checkout -b nom |
| Volver a la rama anterior | git switch - | git checkout - |
| Deshacer los cambios de un archivo | git restore fichier | git checkout -- fichier |
| Sacar un archivo del índice | git restore --staged fichier | git reset HEAD fichier |
Crear una rama y trabajar en ella
git switch -c feature/panierSwitched to a new branch 'feature/panier'La rama arranca en el commit en el que estabas. A partir de ahí puedes modificar, añadir y hacer commits con normalidad: nada de eso aparecerá en main mientras no lo fusiones.
Git no impone ninguna regla sobre los nombres de rama, pero los prefijos feature/, fix/ y hotfix/ son una convención extendida y las interfaces de los servicios de alojamiento los agrupan visualmente.
Para ver en qué punto estás:
git branch # las ramas locales
git branch -vv # con el último commit y la rama remota que sigue
git branch -a # locales y remotas
git switch - # volver a la rama anteriorPara publicar la rama y que el equipo la vea:
git push -u origin feature/panierTraerte la rama de un compañero
En el otro sentido, git fetch actualiza lo que sabes del servidor sin tocar nada en tus ramas:
git fetch origin feature/collegue # una rama concreta
git fetch --all # todos los repositorios remotos
git branch -r # lo que sabes del servidor origin/HEAD -> origin/main
origin/feature/collegue
origin/mainSolo queda cambiarte a ella. Git crea automáticamente la rama local y la enlaza con la del servidor:
git switch feature/colleguebranch 'feature/collegue' set up to track 'origin/feature/collegue'.
Switched to a new branch 'feature/collegue'Cuando Git se niega a cambiar de rama
Es uno de los primeros errores con los que te vas a encontrar:
error: Your local changes to the following files would be overwritten by checkout:
index.html
Please commit your changes or stash them before you switch branches.
AbortingGit protege tu trabajo: el archivo que has modificado no tiene el mismo contenido en la otra rama, y cambiar de rama lo sobrescribiría. Tres soluciones, por orden de preferencia.
Hacer un commit, si el trabajo es coherente. Casi siempre es la respuesta correcta, un commit imperfecto en una rama de trabajo no cuesta nada y se corrige más tarde con los comandos para deshacer que vimos en el capítulo anterior.
Guardarlo aparte, si el trabajo está a medias:
git stash # guarda los cambios aparte
git switch main # …haces lo que tenías que hacer…
git switch -
git stash pop # recupera los cambiosSaved working directory and index state WIP on main: 6d495d9 Page d accueilTirarlo, con git restore ., si los cambios no valían nada. Sin vuelta atrás.
Fusionar una rama
Cuando la funcionalidad esté terminada, sitúate en la rama de destino y fusiona:
git switch main
git merge feature/panierCuando las dos ramas han tocado archivos distintos, Git fusiona solo y no tiene nada que preguntarte. El caso interesante es el otro.
Resolver un conflicto
Esta es la situación reproducida para el capítulo. En feature/panier, la segunda línea de index.html se ha sustituido por un mensaje de carrito vacío. En main, la primera línea se ha modificado para añadir el nombre de la marca. Las dos ramas han tocado el mismo archivo.
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.No se ha roto nada. Git ha fusionado lo que ha podido y te deja decidir el resto. Lo primero, preguntar en qué punto estás:
git statusOn branch main
Your branch is ahead of 'origin/main' by 1 commit.
(use "git push" to publish your local commits)
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: index.html
no changes added to commit (use "git add" and/or "git commit -a")Para obtener solo la lista de archivos pendientes:
git diff --name-only --diff-filter=UAbre el archivo. Git ha insertado marcadores:
<<<<<<< HEAD
<h1>Boutique Gekkode</h1>
<p>Bienvenue sur la boutique.</p>
=======
<h1>Boutique</h1>
<p>Votre panier est vide.</p>
>>>>>>> feature/panierLeerlos es mecánico. Entre <<<<<<< HEAD y ======= está la versión de la rama en la que estás, aquí main. Entre ======= y >>>>>>> está la versión de la rama que estás fusionando.
Te toca escribir el resultado correcto. No tiene por qué ser una u otra: aquí los dos cambios son buenos y deben convivir.
<h1>Boutique Gekkode</h1>
<p>Votre panier est vide.</p>Borra los tres marcadores, no pueden quedarse en el archivo. Después avisa a Git de que está resuelto y termina la fusión:
git add index.html
git commit -m "Fusionne feature/panier dans main"* 0899b0c Fusionne feature/panier dans main
|
| * aacf4c0 Panier : message quand le panier est vide
* | 11ff16b Ajoute le nom de la marque au titre
|/
* 6d495d9 Page d accueilEl commit de fusión tiene dos padres, y el grafo lo deja a la vista.
Cancelarlo todo y empezar de cero
Si el conflicto te supera, no estás obligado a nada:
git merge --abortEl repositorio vuelve exactamente al estado anterior al comando merge. No se pierde nada: puedes volver a intentarlo más tarde o hablarlo con quien escribió la otra rama.
merge o rebase
Los dos integran el trabajo de una rama en otra, pero no de la misma manera.
git merge crea un commit de fusión que enlaza los dos historiales. El historial conserva el rastro exacto de lo que pasó, incluido el hecho de que dos ramas existieron en paralelo. El grafo es fiel, pero se ramifica.
git rebase vuelve a aplicar tus commits encima de la rama de destino, como si hubieras trabajado a partir de su última versión. El historial se queda en línea recta, más fácil de leer, pero se reescribe: tus commits cambian de identificador.
git switch feature/panier
git rebase mainUn rebase puede encontrarse con los mismos conflictos que una fusión, commit a commit. La resolución es idéntica, solo cambia el comando para continuar:
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
error: could not apply 4937109... Promo
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
hint: Disable this message with "git config set advice.mergeConflict false"
Could not apply 4937109... Promogit add index.html
git rebase --continue
# o, para cancelarlo todo
git rebase --abortLa regla de oro cabe en una frase: no hagas nunca rebase de una rama que otras personas ya se han bajado. Reescribir un historial compartido obliga a tus compañeros a reparar el suyo a mano. En tu propia rama de trabajo, antes de proponerla, el rebase es en cambio perfectamente legítimo y deja un historial mucho más legible.
El caso de cada día: alguien ha subido antes que tú
Quieres subir tus cambios y Git se niega:
To /root/o.git
! [rejected] main -> main (fetch first)
error: failed to push some refs to '/root/o.git'
hint: Updates were rejected because the remote contains work that you do notEl servidor tiene commits que tú no tienes. Primero hay que integrarlos. Y ahí, en un repositorio recién creado, Git te hace una pregunta en lugar de actuar:
hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint:
hint: git config pull.rebase false # merge
hint: git config pull.rebase true # rebase
hint: git config pull.ff only # fast-forward only
hint:Desde la versión 2.27, Git se niega a elegir por ti. Responde de una vez por todas, como se propone en el capítulo de instalación:
git config --global pull.rebase trueEl desarrollo pasa entonces a ser este:
git pull --rebase
git pushFrom /root/o
622a60b..38b7dc5 main -> origin/main
Rebasing (1/1)Successfully rebased and updated refs/heads/main.
* 5b45117 Ajoute app.js
* 38b7dc5 Ajoute la doc
* 622a60b DepartTu commit se ha recolocado encima del de tu compañero y el historial se ha quedado lineal, sin ningún commit de fusión de más. Es el ajuste que hay que recomendar a un equipo que empieza.
Un aviso para terminar: no intentes nunca desbloquear un push rechazado con git push --force. Ese comando aplasta el trabajo que hay en el servidor. Si de verdad tienes que forzar, después de un rebase de tu propia rama, usa git push --force-with-lease, que se niega a sobrescribir commits que no habías visto.
Hacer limpieza
Una rama fusionada ya no tiene razón de existir. Si se publicó con -u, empuje primero sus últimos commits: Git se niega a borrar una rama local adelantada respecto a su rama remota, aunque esté fusionada en main.
git push origin feature/panier
git branch -d feature/panierDeleted branch feature/panier (was bc2203a).Sin ese push previo, el mensaje es explícito:
warning: not deleting branch 'feature/panier' that is not yet merged to
'refs/remotes/origin/feature/panier', even though it is merged to HEAD
error: the branch 'feature/panier' is not fully merged
hint: If you are sure you want to delete it, run 'git branch -D feature/panier'
hint: Disable this message with "git config set advice.forceDeleteBranch false"Si la rama no se ha fusionado, Git te frena, y es una red de seguridad muy útil:
error: the branch 'feature/promo' is not fully merged
hint: If you are sure you want to delete it, run 'git branch -D feature/promo'
hint: Disable this message with "git config set advice.forceDeleteBranch false"Para borrar también la rama en el servidor y limpiar las referencias locales que se han quedado obsoletas:
git push origin --delete feature/panier
git fetch --prunegit fetch trae el estado del servidor sin fusionar nada en tus ramas, al contrario que git pull. La opción --prune aprovecha para borrar las ramas remotas que ya no existen, las que tus compañeros han fusionado y eliminado.
Ya sabes colaborar. El último capítulo trata de la organización: qué modelo de ramas adoptar según tu equipo.
Errores frecuentes
git stash, antes de cambiar de rama.git pull se niega a elegir por su cuenta entre fusión y rebase. Zanja la cuestión con git config --global pull.rebase true.git pull --rebase. No uses nunca git push --force para saltártelo: aplasta el trabajo de los demás.<<<<<<<, ======= y >>>>>>> tienen que desaparecer del archivo antes del git add.