-
1. Inicio - Sobre el Control de Versiones
-
2. Fundamentos de Git
-
3. Ramificaciones en Git
-
4. Git en el Servidor
- 4.1 Los Protocolos
- 4.2 Configurando Git en un servidor
- 4.3 Generando tu clave pĆŗblica SSH
- 4.4 Configurando el servidor
- 4.5 El demonio Git
- 4.6 HTTP Inteligente
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 Git en un alojamiento externo
- 4.10 Resumen
-
5. Git en entornos distribuidos
-
6. GitHub
-
7. Herramientas de Git
- 7.1 Revisión por selección
- 7.2 Organización interactiva
- 7.3 Guardado rƔpido y Limpieza
- 7.4 Firmando tu trabajo
- 7.5 Buscando
- 7.6 Reescribiendo la Historia
- 7.7 Reiniciar Desmitificado
- 7.8 Fusión Avanzada
- 7.9 Rerere
- 7.10 Haciendo debug con Git
- 7.11 Submódulos
- 7.12 Agrupaciones
- 7.13 Replace
- 7.14 Almacenamiento de credenciales
- 7.15 Resumen
-
8. Personalización de Git
-
9. Git y Otros Sistemas
- 9.1 Git como Cliente
- 9.2 Migración a Git
- 9.3 Resumen
-
10. Los entresijos internos de Git
-
A1. ApƩndice A: Git en otros entornos
- A1.1 Interfaces grƔficas
- A1.2 Git en Visual Studio
- A1.3 Git en Eclipse
- A1.4 Git con Bash
- A1.5 Git en Zsh
- A1.6 Git en Powershell
- A1.7 Resumen
-
A2. ApƩndice B: Integrando Git en tus Aplicaciones
- A2.1 Git mediante LĆnea de Comandos
- A2.2 Libgit2
- A2.3 JGit
-
A3. ApƩndice C: Comandos de Git
- A3.1 Configuración
- A3.2 Obtener y Crear Proyectos
- A3.3 Seguimiento BƔsico
- A3.4 Ramificar y Fusionar
- A3.5 Compartir y Actualizar Proyectos
- A3.6 Inspección y Comparación
- A3.7 Depuración
- A3.8 Parcheo
- A3.9 Correo Electrónico
- A3.10 Sistemas Externos
- A3.11 Administración
- A3.12 Comandos de FontanerĆa
3.6 Ramificaciones en Git - Reorganizar el Trabajo Realizado
Reorganizar el Trabajo Realizado
En Git tenemos dos formas de integrar cambios de una rama en otra: la fusión (merge) y la reorganización (rebase). En esta sección vas a aprender en qué consiste la reorganización, cómo utilizarla, por qué es una herramienta sorprendente y en qué casos no es conveniente utilizarla.
Reorganización BÔsica
Volviendo al ejemplo anterior, en la sección sobre fusiones Procedimientos BÔsicos de Fusión puedes ver que has separado tu trabajo y realizado confirmaciones (commit) en dos ramas diferentes.

La manera mƔs sencilla de integrar ramas, tal y como hemos visto, es el comando git merge
.
Realiza una fusión a tres bandas entre las dos últimas instantÔneas de cada rama (C3 y C4) y el ancestro común a ambas (C2); creando una nueva instantÔnea (snapshot) y la correspondiente confirmación (commit).

Sin embargo, tambiƩn hay otra forma de hacerlo: puedes capturar los cambios introducidos en C4 y reaplicarlos encima de C3.
Esto es lo que en Git llamamos reorganizar (rebasing, en inglƩs).
Con el comando git rebase
, puedes capturar todos los cambios confirmados en una rama y reaplicarlos sobre otra.
Por ejemplo, puedes lanzar los comandos:
$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command
Haciendo que Git vaya al ancestro común de ambas ramas (donde estÔs actualmente y de donde quieres reorganizar), saque las diferencias introducidas por cada confirmación en la rama donde estÔs, guarde esas diferencias en archivos temporales, reinicie (reset) la rama actual hasta llevarla a la misma confirmación que la rama de donde quieres reorganizar, y finalmente, vuelva a aplicar ordenadamente los cambios.

En este momento, puedes volver a la rama master
y hacer una fusión con avance rÔpido (fast-forward merge).
$ git checkout master
$ git merge experiment

master
AsĆ, la instantĆ”nea apuntada por C4'
es exactamente la misma apuntada por C5
en el ejemplo de la fusión.
No hay ninguna diferencia en el resultado final de la integración, pero el haberla hecho reorganizando nos deja un historial mÔs claro.
Si examinas el historial de una rama reorganizada, este aparece siempre como un historial lineal: como si todo el trabajo se hubiera realizado en series, aunque realmente se haya hecho en paralelo.
Habitualmente, optarĆ”s por esta vĆa cuando quieras estar seguro de que tus confirmaciones de cambio (commits) se pueden aplicar limpiamente sobre una rama remota; posiblemente, en un proyecto donde estĆ©s intentando colaborar, pero no lleves tĆŗ el mantenimiento.
En casos como esos, puedes trabajar sobre una rama y luego reorganizar lo realizado en la rama origin/master
cuando lo tengas todo listo para enviarlo al proyecto principal.
De esta forma, la persona que mantiene el proyecto no necesitarÔ hacer ninguna integración con tu trabajo; le bastarÔ con un avance rÔpido o una incorporación limpia.
Cabe destacar que, la instantÔnea (snapshot) apuntada por la confirmación (commit) final, tanto si es producto de una reorganización (rebase) como si lo es de una fusión (merge), es exactamente la misma instantÔnea; lo único diferente es el historial. La reorganización vuelve a aplicar cambios de una rama de trabajo sobre otra rama, en el mismo orden en que fueron introducidos en la primera, mientras que la fusión combina entre sà los dos puntos finales de ambas ramas.
Algunas Reorganizaciones Interesantes
También puedes aplicar una reorganización (rebase) sobre otra cosa ademÔs de sobre la rama de reorganización.
Por ejemplo, considera un historial como el de Un historial con una rama puntual sobre otra rama puntual.
Has ramificado a una rama puntual (server
) para aƱadir algunas funcionalidades al proyecto, y luego has confirmado los cambios.
DespuƩs, vuelves a la rama original para hacer algunos cambios en la parte cliente (rama client
), y confirmas tambiƩn esos cambios.
Por Ćŗltimo, vuelves sobre la rama server
y haces algunos cambios mƔs.

Imagina que decides incorporar tus cambios del lado cliente sobre el proyecto principal para hacer un lanzamiento de versión; pero no quieres lanzar aún los cambios del lado servidor porque no estÔn aún suficientemente probados.
Puedes coger los cambios del cliente que no estƔn en server (C8
y C9
) y reaplicarlos sobre tu rama principal usando la opción --onto
del comando git rebase
:
$ git rebase --onto master server client
Esto viene a decir: āActiva la rama client
, averigua los cambios desde el ancestro comĆŗn entre las ramas client
y server
, y aplicalos en la rama master
ā.
Puede parecer un poco complicado, pero los resultados son realmente interesantes.

Y, tras esto, ya puedes avanzar la rama principal (ver Avance rƔpido de tu rama master
, para incluir los cambios de la rama client
):
$ git checkout master
$ git merge client

master
, para incluir los cambios de la rama client
Ahora supongamos que decides traerlos (pull) tambiƩn sobre tu rama server
.
Puedes reorganizar (rebase) la rama server
sobre la rama master
sin necesidad siquiera de comprobarlo previamente, usando el comando git rebase [rama-base] [rama-puntual]
, el cual activa la rama puntual (server
en este caso) y la aplica sobre la rama base (master
en este caso):
$ git rebase master server
Esto vuelca el trabajo de server
sobre el de master
, tal y como se muestra en Reorganizando la rama server
sobre la rama master
.

server
sobre la rama master
DespuƩs, puedes avanzar rƔpidamente la rama base (master
):
$ git checkout master
$ git merge server
Y por Ćŗltimo puedes eliminar las ramas client
y server
porque ya todo su contenido ha sido integrado y no las vas a necesitar mƔs, dejando tu registro tras todo este proceso tal y como se muestra en Historial final de confirmaciones de cambio:
$ git branch -d client
$ git branch -d server

Los Peligros de Reorganizar
Ahhā¦ā, pero la dicha de la reorganización no la alcanzamos sin sus contrapartidas, las cuales pueden resumirse en una lĆnea:
Nunca reorganices confirmaciones de cambio (commits) que hayas enviado (push) a un repositorio pĆŗblico.
Si sigues esta recomendación, no tendrÔs problemas. Pero si no lo haces, la gente te odiarÔ y serÔs despreciado por tus familiares y amigos.
Cuando reorganizas algo, estƔs abandonando las confirmaciones de cambio ya creadas y estƔs creando unas nuevas; que son similares, pero diferentes.
Si envĆas (push) confirmaciones (commits) a alguna parte, y otros las recogen (pull) de allĆ; y despuĆ©s vas tĆŗ y las reescribes con git rebase
y las vuelves a enviar (push); tus colaboradores tendrƔn que refusionar (re-merge) su trabajo y todo se volverƔ tremendamente complicado cuando intentes recoger (pull) su trabajo de vuelta sobre el tuyo.
Veamos con un ejemplo como reorganizar trabajo que has hecho pĆŗblico puede causar problemas. ImagĆnate que haces un clon desde un servidor central, y luego trabajas sobre Ć©l. Tu historial de cambios puede ser algo como esto:

Ahora, otra persona trabaja tambiĆ©n sobre ello, realiza una fusión (merge) y lleva (push) su trabajo al servidor central. TĆŗ te traes (fetch) sus trabajos y los fusionas (merge) sobre una nueva rama en tu trabajo, con lo que tu historial quedarĆa parecido a esto:

A continuación, la persona que habĆa llevado cambios al servidor central decide retroceder y reorganizar su trabajo; haciendo un git push --force
para sobrescribir el registro en el servidor.
Tu te traes (fetch) esos nuevos cambios desde el servidor.

Ahora los dos estƔn en un aprieto.
Si haces git pull
crearĆ”s una fusión confirmada, la cual incluirĆ” ambas lĆneas del historial, y tu repositorio lucirĆ” asĆ:

Si ejecutas git log
sobre un historial asĆ, verĆ”s dos confirmaciones hechas por el mismo autor y con la misma fecha y mensaje, lo cual serĆ” confuso.
Es mĆ”s, si luego tu envĆas (push) ese registro de vuelta al servidor, vas a introducir todas esas confirmaciones reorganizadas en el servidor central.
Lo que puede confundir aún mÔs a la gente.
Era mĆ”s seguro asumir que el otro desarrollador no querĆa que C4
y C6
estuviesen en el historial; por ello habĆa reorganizado su trabajo de esa manera.
Reorganizar una Reorganización
Si te encuentras en una situación como esta, Git tiene algunos trucos que pueden ayudarte. Si alguien de tu equipo sobreescribe cambios en los que se basaba tu trabajo, tu reto es descubrir qué han sobreescrito y qué te pertenece.
AdemĆ”s de la suma de control SHA-1, Git calcula una suma de control basada en el parche que introduce una confirmación. A esta se le conoce como āpatch-idā.
Si te traes el trabajo que ha sido sobreescrito y lo reorganizas sobre las nuevas confirmaciones de tu compaƱero, es posible que Git pueda identificar quĆ© parte correspondĆa especĆficamente a tu trabajo y aplicarla de vuelta en la rama nueva.
Por ejemplo, en el caso anterior, si en vez de hacer una fusión cuando estĆ”bamos en Alguien envió (push) confirmaciones (commits) reorganizadas, abandonando las confirmaciones en las que tu habĆas basado tu trabajo ejecutamos git rebase teamone/master
, Git harĆ” lo siguiente:
-
Determinar el trabajo que es especĆfico de nuestra rama (C2, C3, C4, C6, C7)
-
Determinar cuƔles no son fusiones confirmadas (C2, C3, C4)
-
Determinar cuƔles no han sido sobreescritas en la rama destino (solo C2 y C3, pues C4 corresponde al mismo parche que C4')
-
Aplicar dichas confirmaciones encima de
teamone/master
Asà que en vez del resultado que vimos en Vuelves a fusionar el mismo trabajo en una nueva fusión confirmada, terminaremos con algo mÔs parecido a Reorganizar encima de un trabajo sobreescrito reorganizado..

Esto solo funciona si C4 y el C4' de tu compaƱero son parches muy similares. De lo contrario, la reorganización no serĆ” capaz de identificar que se trata de un duplicado y agregarĆ” otro parche similar a C4 (lo cual probablemente no podrĆ” aplicarse limpiamente, pues los cambios ya estarĆan allĆ en algĆŗn lugar).
TambiƩn puedes simplificar el proceso si ejecutas git pull --rebase
en vez del tradicional git pull
. O, en este caso, puedes hacerlo manualmente con un git fetch
primero, seguido de un git rebase teamone/master
.
Si sueles utilizar git pull
y quieres que la opción --rebase
esté activada por defecto, puedes asignar el valor de configuración pull.rebase
haciendo algo como esto git config --global pull.rebase true
.
Si consideras la reorganización como una manera de limpiar tu trabajo y tus confirmaciones antes de enviarlas (push), y si sólo reorganizas confirmaciones (commits) que nunca han estado disponibles pĆŗblicamente, no tendrĆ”s problemas. Si reorganizas (rebase) confirmaciones (commits) que ya estaban disponibles pĆŗblicamente y la gente habĆa basado su trabajo en ellas, entonces prepĆ”rate para tener problemas, frustrar a tu equipo y ser despreciado por tus compaƱeros.
Si tu compañero o tú ven que aun asà es necesario hacerlo en algún momento, asegúrense que todos sepan que deben ejecutar git pull --rebase
para intentar aliviar en lo posible la frustración.
Reorganizar vs. Fusionar
Ahora que has visto en acción la reorganización y la fusión, te preguntarÔs cuÔl es mejor. Antes de responder, repasemos un poco qué representa el historial.
Para algunos, el historial de confirmaciones de tu repositorio es un registro de todo lo que ha pasado. Un documento histórico, valioso por sĆ mismo y que no deberĆa ser alterado. Desde este punto de vista, cambiar el historial de confirmaciones es casi como blasfemar; estarĆas mintiendo sobre lo que en verdad ocurrió. ĀæY quĆ© pasa si hay una serie desastrosa de fusiones confirmadas? Nada. AsĆ fuĆ© como ocurrió y el repositorio deberĆa tener un registro de esto para la posteridad.
La otra forma de verlo puede ser que, el historial de confirmaciones es la historia de cómo se hizo tu proyecto.
TĆŗ no publicarĆas el primer borrador de tu novela, y el manual de cómo mantener tus programas tambiĆ©n debe estar editado con mucho cuidado.
Esta es el Ɣrea que utiliza herramientas como rebase
y filter-branch
para contar la historia de la mejor manera para los futuros lectores.
Ahora, sobre si es mejor fusionar o reorganizar: verÔs que la respuesta no es tan sencilla. Git es una herramienta poderosa que te permite hacer muchas cosas con tu historial, y cada equipo y cada proyecto es diferente. Ahora que conoces cómo trabajan ambas herramientas, serÔ cosa tuya decidir cuÔl de las dos es mejor para tu situación en particular.
Normalmente, la manera de sacar lo mejor de ambas es reorganizar tu trabajo local, que aĆŗn no has compartido, antes de enviarlo a algĆŗn lugar; pero nunca reorganizar nada que ya haya sido compartido.