¿Cómo se fusiona git después del trabajo de selección?
Imaginemos que tenemos una master
sucursal.
Luego creamos unnewbranch
git checkout -b newbranch
y haga dos nuevos compromisos para newbranch
: compromiso1 y compromiso2
Luego cambiamos a master y hacemoscherry-pick
git checkout master
git cherry-pick hash_of_commit1
Al analizarlo, gitk
vemos que commit1 y su versión seleccionada tienen hashes diferentes, por lo que técnicamente son dos commits diferentes.
Finalmente nos fusionamos newbranch
en master
:
git merge newbranch
y ver que estos dos commits con diferentes hashes se fusionaron sin problemas aunque implican que se deben aplicar dos veces los mismos cambios, por lo que uno de ellos debería fallar.
¿Git realmente hace un análisis inteligente del contenido de las confirmaciones mientras las fusiona y decide que los cambios no deben aplicarse dos veces o que estas confirmaciones se marcan internamente como vinculadas entre sí?
Respuesta corta
No te preocupes, Git se encargará.
Respuesta larga
A diferencia de, por ejemplo, SVN 1 , Git no almacena confirmaciones en formato delta, sino que se basa en instantáneas 2,3 . Si bien SVN intentaría ingenuamente aplicar cada confirmación fusionada como un parche (y fallaría, por la razón exacta que usted describió), Git generalmente es capaz de manejar este escenario.
Al fusionarse, Git intentará combinar las instantáneas de ambas confirmaciones HEAD en una nueva instantánea. Si una parte del código o un archivo es idéntico en ambas instantáneas (es decir, porque ya se seleccionó una confirmación), Git no lo tocará.
Fuentes
1 Skip-Deltas en Subversion
2 Conceptos básicos de Git
3 El modelo de objetos de Git
Después de dicha fusión, es posible que haya seleccionado confirmaciones en el historial dos veces.
Solución para evitar esto, cito un artículo que recomienda que las ramas con confirmaciones duplicadas (seleccionadas) usen rebase antes de fusionar:
git merge después de git cherry-pick: evitar confirmaciones duplicadas
Imaginemos que tenemos la rama master y una rama b:
o---X <-- master \ b1---b2---b3---b4 <-- b
Ahora necesitamos urgentemente las confirmaciones b1 y b3 en master, pero no las confirmaciones restantes en b. Entonces, lo que hacemos es verificar la rama maestra y seleccionar las confirmaciones b1 y b3:
$ git checkout master $ git cherry-pick "b1's SHA" $ git cherry-pick "b3's SHA"
El resultado sería:
o---X---b1'---b3' <-- master \ b1---b2---b3---b4 <-- b
Digamos que hacemos otra confirmación en master y obtenemos:
o---X---b1'---b3'---Y <-- master \ b1---b2---b3---b4 <-- b
Si ahora fusionáramos la rama b con la maestra:
$ git merge b
Obtendríamos lo siguiente:
o---X---b1'---b3'---Y--- M <-- master \ / b1----b2----b3----b4 <-- b
Eso significa que los cambios introducidos por b1 y b3 aparecerían dos veces en la historia. Para evitar eso, podemos rebase en lugar de fusionar:
$ git rebase master b
Lo que daría como resultado:
o---X---b1'---b3'---Y <-- master \ b2'---b4' <-- b
Finalmente:
$ git checkout master $ git merge b
Nos da:
o---X---b1'---b3'---Y---b2'---b4' <-- master, b
EDITAR Correcciones supuestas por el comentario de David Lemon