multiple - how to use cherry pick git
En un conflicto de fusión de Git cherry-pick o rebase, ¿cómo se determinan BASE(también conocido como "el antepasado"), LOCAL y REMOTO? (1)
selección de cereza
A menos que me haya engañado, entonces si haces "git cherry-pick <commit C>", obtendrás:
- LOCAL: el compromiso con el que se está fusionando (es decir, el HEAD de su sucursal)
- REMOTO: la confirmación que está seleccionando (por ejemplo, <confirmación C>)
- BASE: el padre de la confirmación que está seleccionando (es decir, C ^, es decir, el padre de C)
Si no se aclara inmediatamente por qué BASE debería ser C ^, consulte la sección "por qué" a continuación.
Mientras tanto, tomemos un ejemplo y veamos que BASE puede ser, pero a menudo no será un ancestro común durante una selección de cerezas. Supongamos que el gráfico de confirmación se ve así.
E <-- master
|
D
| C <-- foo_feature(*)
|/
B
|
A
y estás en la rama foo_feature (de ahí el asterisco). Si realiza "git cherry-pick <commit D>", entonces la BASE para ese cherry-pick será la B, que es un ancestro común de C y D. (C será LOCAL y D será REMOTO). Sin embargo, si en su lugar haces "git cherry-pick <commit E>, entonces BASE se confirmará D. (C será LOCAL y E será REMOTO).
rebase
Para el contexto de fondo, la rebase es aproximadamente iterada de selección de cerezas. En particular, el tema de rebasado en la parte superior del maestro (es decir, "tema de git checkout; git rebase master") significa aproximadamente:
git checkout master # switch to master''s HEAD commit
git checkout -b topic_rebased # create new branch rooted there
for each commit C in master..topic # for each topic commit not already in master...
git cherry-pick C # bring it over to the new branch
finally, forget what "topic" used to mean and now defined "topic" as the HEAD of topic_rebased.
Las etiquetas que se aplican durante este proceso son extensiones de las reglas normales de selección de cereza:
- LOCAL: el compromiso que estás haciendo en la cima de
- Este es el HEAD de la nueva rama de topic_rebased
- Solo para la primera confirmación, esto será lo mismo que la CABEZA del maestro
- REMOTO: la confirmación que está seleccionando (por ejemplo, <confirmación C>)
- BASE: el padre de la confirmación que está seleccionando (C ^, es decir, el padre de C)
Esto implica algo que debes tener en cuenta sobre LOCAL vs REMOTO, si quieres evitar confusiones:
A pesar de que estaba en el tema de la rama cuando inició la rebase , LOCAL nunca se refiere a un compromiso en la rama del tema mientras se está realizando una rebase. En su lugar, LOCAL siempre se refiere a un compromiso en la nueva rama que se está creando (topic_rebased).
(Si uno no tiene esto en cuenta, durante una fusión desagradable puede comenzar a preguntarse: "Espere, ¿por qué dice que estos son cambios locales ? Juro que fueron cambios realizados en el maestro, no en mi rama").
Para ser más concretos, aquí hay un ejemplo:
Digamos que tenemos gráfico de compromiso
D <-- foo_feature(*)
|
| C <-- master
B |
|/
|
A
y actualmente estamos en la rama foo_feature (indicado por "*"). Si ejecutamos "git rebase master", la rebase procederá en dos pasos:
Primero, los cambios de B se repetirán encima de C. Durante esto, C es LOCAL, B es REMOTO y A es BASE. Tenga en cuenta que A es un ancestro real común de B y C. Después de este primer paso, tiene un gráfico aproximadamente así:
B'' <-- foo_feature
D |
| |
| C <-- master
B /
|/
|
A
(En la vida real, es posible que B y D ya hayan sido podados del árbol en este momento, pero los estoy dejando aquí para facilitar la detección de posibles antepasados comunes).
En segundo lugar, los cambios de D se repetirán encima de B ''. Durante esto, B ''es LOCAL, D es REMOTO y B es BASE. Tenga en cuenta que B no es un antepasado común relevante de nada. (Por ejemplo, no es un antecesor común de los actuales LOCAL y REMOTO, B ''y D. Y no es un ancestro común de las cabezas de rama originales, C y D). Después de este paso, tienes una rama aproximadamente así:
D'' <-- foo_feature
|
B''
D |
| |
| C <-- master
B /
|/
|
A
Para completar, nota al final de la rebase B y D se eliminan de la gráfica, dando como resultado:
D'' <-- foo_feature
|
B''
|
C <-- master
|
A
¿Por qué se define BASE como es?
Como se mencionó anteriormente, tanto para una selección selectiva como para una rebase, BASE es el padre (C ^) de la confirmación de C que se está introduciendo. En el caso general, C ^ no es un ancestro común, entonces ¿por qué llamarlo BASE ? (En una fusión normal, BASE es un ancestro común. Y parte del éxito de git en la fusión se debe a su capacidad para encontrar un buen ancestro común).
Esencialmente, uno hace esto como una forma de implementar la funcionalidad de "parche" a través del algoritmo de combinación de tres vías normal. En particular, obtiene estas propiedades "parcheadas":
- Si <commit C> no modifica una determinada región del archivo, prevalecerá la versión de esa región de su rama. (Esto es, las regiones que el "parche" no requiere cambio no se remendan).
- Si <commit C> modifica una región determinada del archivo y su rama deja esa región sola, entonces prevalecerá la versión de esa región de <commit x>. (Es decir, las regiones a las que el "parche" requiere que se modifiquen los parches).
- Si <commit C> modifica una región determinada del archivo pero su rama también modificó esa región, entonces obtiene un conflicto de combinación.
En un conflicto de combinación de Git normal, las tres versiones de un archivo en juego para la combinación de tres vías son aproximadamente las siguientes:
- LOCAL: la versión de mi rama.
- REMOTO: la versión de la otra rama.
- BASE: la versión del ancestro común de las dos ramas (en particular, el ancestro común de la CABEZA de mi rama y la CABEZA de la otra rama)
Cuando una selección de cerezas de Git genera un conflicto de fusión, no hay un ancestro común, hablando correctamente, entonces, ¿cómo se determinan estas cosas? Lo mismo podría preguntarse sobre rebase.