2012-04-07 8 views
23

En un Git normal de fusionar los conflictos, las tres versiones de un archivo en juego para las tres vías de combinación son más o menos de la siguiente manera:En un conflicto de fusión Git cherry-pick o rebase, ¿cómo se determinan BASE (también conocido como "el antecesor"), LOCAL y REMOTO?

  • 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 un Git cherry-pick genera un conflicto de combinación , no hay una común Cestor, hablando propiamente, ¿cómo se determinan estas cosas? Lo mismo se podría preguntar sobre rebase.

Respuesta

29

cereza-Pick

A menos que he engañado a mí mismo, a continuación, si lo hace "git cherry-pick < cometer C >", entonces se obtiene:

  • LOCAL: el que se comprometen' re fusión por encima de (es decir, el jefe de la sucursal)
  • REMOTO: el commit que estés cherry picking (es decir < cometer C >)
  • BASE: t el padre de la confirmación que está recogiendo (es decir, C ^, es decir, el padre de C)

Si no está claro por qué BASE debe ser C ^, consulte la sección "por qué" a continuación.

Mientras tanto, vamos a dar un ejemplo, y ver que la base puede ser pero a menudo no habrá un ancestro común durante una cereza-escoge. Supongamos que el gráfico de confirmación se ve así:

E <-- master 
| 
D 
| C <-- foo_feature(*) 
|/ 
B 
| 
A 

y usted está en la rama foo_feature (de ahí el asterisco). Si seleccionas "git cherry-pick < commit D >", entonces BASE para ese cherry-pick será commit B, que es un ancestro común de C y D. (C será LOCAL y D será REMOTO). Sin embargo, si en lugar de hacer "git-cereza recoger < cometer e >, entonces base será cometer D. (C será local y e será REMOTO.)

rebase

Para contexto de fondo, es rebase Aproximadamente iterado cherry-picking.En particular, rebase tema en la parte superior de maestro (es decir, "tema 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 cherry-pick

  • LOCAL: el commit que estés cherry-picking en la parte superior de
    • esta es la cabeza de la nueva rama topic_rebased
    • Por primera cometen solamente, esto va a ser la misma que la cabeza del maestro
  • REMOTO: el compromiso que está haciendo al azar (es decir < cometer C >)
  • BASE: el padre de la que eres cometer cherry picking (C ^, es decir, la matriz de C)

Esto implica algo a tener en cuenta acerca LOCAL vs remoto, si se quiere evitar la confusión:

a pesar de que se encontraba tema rama cuando inició la rebase, local nunca se refiere a un compromiso en la rama temamientras que una rebase está en progreso. En su lugar, LOCAL siempre se refiere a una confirmación en la nueva rama que se está creando (topic_rebased).

(Si uno deja de tener esto en cuenta, a continuación, durante una combinación desagradable uno puede empezar a preguntarse: "Espera, ¿por qué se dice que son locales cambios? Juro que eran los cambios realizados en el maestro, . no en mi rama ")

Para ser más concretos, aquí hay un ejemplo:

Digamos que tenemos cometer gráfico

D <-- foo_feature(*) 
| 
| C <-- master 
B | 
|/ 
| 
A 

y estamos actualmente en el salvado ch foo_feature (indicado por "*"). Si ejecutamos "git rebase master", la rebase procederá en dos pasos:

Primero, los cambios de B se reproducirán en la parte superior de C. Durante esto, C es LOCAL, B es REMOTO y A es BASE. Tenga en cuenta que A es un verdadero ancestro común de B y C. Después de este primer paso, usted tiene un gráfico de aproximadamente así:

B' <-- foo_feature 
D | 
| | 
| C <-- master 
B/
|/ 
| 
A 

(En la vida real, B y D podría ya se han podado del árbol en este punto, pero los dejo aquí, para que sea más fácil detectar posibles ancestros comunes.)

En segundo lugar, los cambios de D se reproducirán en la parte superior de B '. Durante esto, B 'es LOCAL, D es REMOTO, y B es BASE. Tenga en cuenta que B no es un antecesor común relevante de nada. (Por ejemplo, no es un ancestro común de los actuales LOCAL y REMOTO, B 'y D. Y no es un ancestro común de las cabezas de las ramas originales, C y D).Después de este paso, usted tiene una rama de aproximadamente así:

D' <-- foo_feature 
    | 
    B' 
D | 
| | 
| C <-- master 
B/
|/ 
| 
A 

Para completar, nota al final del rebase B y D se retiran de la gráfica, obteniéndose:

D' <-- foo_feature 
| 
B' 
| 
C <-- master 
| 
A 

¿Por qué es BASE definido como es?

Como se mencionó anteriormente, tanto para una selección de cereza como para una rebase, BASE es el padre (C ^) de la C de confirmación. En el caso general C^no es un antepasado común, Entonces, ¿por qué llamarlo BASE? (En una base de fusión usual es un ancestro común. Y parte de los éxitos de git en la fusión se debe a su capacidad para encontrar un buen antepasado común.)

Esencialmente, uno hace esto como una forma de poner en práctica "parche" funcionalidad a través del algoritmo normal three-way merge. En particular, se obtiene estas propiedades "irregulares":

  • Si < cometer C > no modifica una determinada región dada del archivo, entonces prevalecerá la versión de esa región de su rama. (Esto es, las regiones que el "parche" no necesita cambiar no se parchean.)
  • Si < confirma C > modifica una región determinada del archivo y su rama deja esa región sola, entonces la versión de esa región de < commit x > prevalecerá. (Es decir, las regiones que el "parche" requiere cambiar se parchean.)
  • Si < confirma C > modifica una región determinada del archivo pero su rama también ha modificado esa región, y luego obtiene un conflicto de combinación.
+0

Respondiendo a su propia pregunta en un minuto cuando no está completamente seguro de que es correcta es un poco pobre forma. – Cascabel

+0

@Jefromi ¿Sugeriría que incluya respuestas tentativas como parte de la pregunta original? (Pensé que sería útil como una respuesta independiente, porque de esa manera podría ser discutida/subida/bajada/etc. separada de la Q original). Supongo que la alternativa es no incluirlas en absoluto. – Chris

+0

Personalmente he esperado para ver si se publicó una respuesta más definitiva rápidamente. – Cascabel

Cuestiones relacionadas