tag - Git: tirando de una rama rediseñada
qué tipos de etiquetas existen en git (3)
Desarrollo al mismo tiempo en dos máquinas virtuales, para fines de configuración. Como resultado, con frecuencia rebase en una máquina y necesito que los cambios aparezcan en la otra sin dificultad.
Supongamos que mi rama se llama feature/my-feature-branch
. Después de terminar la rebase en la primera máquina virtual, hago una búsqueda de git en la segunda. El siguiente mensaje aparece:
$ git status
On branch feature/my-feature-branch
Your branch and ''origin/feature/my-feature-branch'' have diverged,
and have 21 and 24 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
Bueno, no hagas ningún truco, porque luego terminas con un compromiso de fusión sin sentido después de un poco de alboroto.
En cambio, ejecuta
git rebase -i origin/feature/my-feature-branch
Una vez que aparece el editor de texto, elimine todos los commits y reemplácelo con lo siguiente (esto hace que la rebase se complete sin que se mantenga ningún commit).
exec echo test
Si tiene confirmaciones que deben mantenerse, entonces se pueden aplicar aquí. En cualquier caso, la rebase se completará, y ahora ambas máquinas están sincronizadas de nuevo, como lo demuestra:
$ git pull
Already up-to-date.
$ git push
Everything up-to-date
Déjame describir mi situación:
Mr Blond y Mr Orange están trabajando en la rama A que se ramifica fuera de la rama principal en commit M1. La rama A tiene 2 confirmaciones: A1 y A2.
M1
/
/
A1 - A2
Mientras tanto, el Sr. Orange se comprometió y presionó 2 confirmaciones más en la rama principal, M2 y M3.
M1 - M2 - M3
/
/
A1 - A2
El Sr. Blond saca del control remoto, y luego de un tiempo decide volver a establecer la base en la rama principal:
M1 - M2 - M3
/ /
/ /
A1 - A2 A1` - A2`
Ahora A1` y A2` son los commits reestadiados que existen localmente en Mr. blond''s, y A1 y A2 existen de forma remota. El Sr. Blond empuja sus compromisos, usando -f para forzar sus cambios y "reescribir" la historia. Ahora el repositorio remoto se ve así:
M1 - M2 - M3
/
/
A1` - A2`
Pero el Sr. Orange trabajó en la rama A también. Su repositorio local todavía se ve así:
M1 - M2 - M3
/
/
A1 - A2
¿Qué necesita hacer el Sr. Orange para sincronizarse con una sucursal en el repositorio remoto?
Una extracción normal no funcionará. Will will -f forzar los cambios desde el control remoto localmente? Sé que eliminar la versión local de A y volver a traerla del repositorio remoto funcionará, pero esa no parece ser una buena forma de lograrlo.
Mi recomendación (o "lo que haría si fuera el señor Orange") es comenzar con git fetch
. Ahora tendré esto en mi repositorio, que es lo que el Sr. Rubio tuvo después de su rebase y justo antes de ejecutar "git push -f".
M1 - M2 - M3
/ /
/ /
A1 - A2 A1'' - A2''
La única diferencia importante es que haré que mi etiqueta local A
apunte a rev A2, y la remota remueva los remotes/origin/A
apuntando a A2 ''(Mr Blond lo hizo al revés, la etiqueta local A
apuntando a A2'' y remotes/origin/A
apuntando a A2).
Si he estado trabajando en mi copia de la rama llamada "A" tendré esto en su lugar:
M1 ---- M2 ---- M3
/ /
/ /
A1 - A2 - A3 A1'' - A2''
(con mi etiqueta local apuntando a A3 en lugar de A2, o A4 o A5, etc., dependiendo de cuántos cambios haya aplicado). Ahora todo lo que tengo que hacer es volver a ajustar mi A3 (y A4 si es necesario, etc.) en A2 '' . Una forma directa obvia:
$ git branch -a
master
* A
remotes/origin/master
remotes/origin/A
$ git branch new_A remotes/origin/A
$ git rebase -i new_A
y luego suelte las revoluciones A1 y A2 por completo, ya que las modificadas están en new_A como A1 ''y A2''. O:
$ git checkout -b new_A remotes/origin/A
$ git format-patch -k --stdout A3..A | git am -3 -k
(El método git am -3 -k
se describe en la página de manual de git-format-patch
).
Estos requieren averiguar lo que tengo que el Sr. Blond no tenía antes de hacer su rebase
, es decir, identificar A1, A2, A3, etc.
Si el segundo enfoque tiene éxito, termino con:
M1 ---- M2 ---- M3
/ /
/ /
A1 - A2 - A3 A1'' - A2'' - A3''
donde mi nombre de rama new_A
apunta a A3 ''(mi rama A
actual aún apunta al antiguo A3). Si utilizo el primer enfoque y tiene éxito, termino con lo mismo, es solo que mi nombre de rama actual A
ahora apuntará a A3 ''(y no tengo ningún nombre para la antigua rama con A1-A2-A3, incluso aunque todavía está en mi repositorio, encontrarlo requiere pasar por reflogs o similar).
(Si mi A3 necesita modificaciones para convertirse en A3 '', tanto el rebase interactivo como el método "git am" requerirán que yo lo haga, por supuesto).
Por supuesto, también es posible simplemente git merge
(como en la respuesta de Gary Fixler), pero eso creará un compromiso de fusión ("M" sin número, a continuación) y mantendrá visibles las revoluciones A1 y A2, dando:
M1 ---- M2 ---- M3
/ /
/ /
A1 - A2 - A3 A1'' - A2'' -- M
/_______________/
Si desea conservar el A1 y A2 originales, esto es algo bueno; si quieres deshacerte de ellos, es algo malo. Entonces, "qué hacer" depende de "lo que quiere que sea el resultado".
Editar para agregar: me gusta más el método de parche de formato, ya que deja mi antiguo nombre de rama A mientras me aseguro de que todo esté bien. Suponiendo que todo funciona y es bueno, aquí están los últimos pasos:
$ git branch -m A old_A
$ git branch -m new_A A
y luego, si old_A puede abandonarse por completo:
$ git branch -D old_A
o, de forma equivalente, comience con la eliminación de la sucursal, luego cambie el nombre de nueva_A a A.
(Editar: consulte también la documentación de git rebase --onto
, con el objetivo de git rebase --onto
A3, etc., en la nueva rama_A).
Si al Sr. Orange no le importa perder sus cambios, puede buscarlo en el servidor, luego puede ingresar a git checkout A2
en su rama local, luego (suponiendo que el control remoto se llame "origen") git reset --hard origin/A2
para restablecer su A2
a donde está el A2
del control remoto.
Si le preocupa perder cambios, puede fusionar los cambios del servidor para resolverlos (desde su propia rama A2
, y suponiendo nuevamente que el control remoto se denomina "origen") con git merge origin/A2
. Esto hará que una nueva confirmación esté en la parte superior de las ramas A2
él y del control remoto con los cambios de ambos fusionados. Entonces esto puede ser devuelto al control remoto.