multiple - git pick specific commit
¿Cómo se fusiona git después del trabajo de selección selectiva? (2)
Imaginemos que tenemos una rama master
.
Entonces creamos una newbranch
git checkout -b newbranch
y hacer dos nuevos commits a newbranch
: commit1 y commit2
Luego cambiamos a master y hacemos cherry-pick
git checkout master
git cherry-pick hash_of_commit1
Al mirar a gitk
, vemos que commit1 y su versión elegida tienen diferentes valores hash, por lo que técnicamente son dos compromisos diferentes.
Finalmente newbranch
en master
:
git merge newbranch
y ver que estos dos commits con hashes diferentes se fusionaron sin problemas, aunque implican que los mismos cambios se deben aplicar dos veces, por lo que uno de ellos debería fallar.
¿Git realmente hace un análisis inteligente del contenido de la confirmación mientras se fusiona y decide que los cambios no se deben aplicar dos veces o estas confirmaciones se marcan internamente como vinculadas entre sí?
Respuesta corta
No te preocupes, Git lo manejará.
Respuesta larga
A diferencia de, por ejemplo, SVN 1 , Git no almacena commits en formato delta, sino que está basado en snapshot 2,3 . Mientras que SVN intentaría ingenuamente aplicar cada commit fusionado como un parche (y fallar, por la razón exacta que describiste), Git generalmente puede manejar este escenario.
Al fusionarse, Git intentará combinar las instantáneas de ambos commits de HEAD en una nueva instantánea. Si una parte del código o un archivo es idéntica en ambas instantáneas (es decir, porque una confirmación ya fue elegida), Git no la tocará.
Fuentes
1 Skip-Deltas en Subversion
2 Conceptos básicos de Git
3 El modelo de objetos Git
Después de dicha combinación, es posible que hayas cometido errores en la historia dos veces.
Solución para evitar esta cita del article que recomienda que las sucursales con confirmaciones duplicadas (recogidas con precisión) utilicen la rebase antes de la fusión:
git merge después de git cherry-picking: evitar commits duplicados
Imagina que tenemos la rama principal y una rama b:
o---X <-- master / b1---b2---b3---b4 <-- b
Ahora necesitamos con urgencia las confirmaciones b1 y b3 en el maestro, pero no las confirmaciones restantes en b. Entonces, lo que hacemos es verificar la rama master y cherry-pick commits 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 otro commit en master y obtenemos:
o---X---b1''---b3''---Y <-- master / b1---b2---b3---b4 <-- b
Si ahora fusionamos la rama b en el maestro:
$ 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 rebasear en lugar de fusionar:
$ git rebase master b
Cuál rendiría:
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