En un conflicto de fusión de Git cherry-pick o rebase, ¿cómo se determinan la BASE (también conocido como "el antepasado"), LOCAL y REMOTO?


En un conflicto normal de fusión de Git, las tres versiones de un archivo en juego para la fusió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 un Git cherry-pick genera un conflicto de fusión, no hay un ancestro común, correctamente hablando, entonces, ¿cómo se determinan estas cosas? Lo mismo se podría preguntar sobre rebase.

Author: Chris, 2012-04-08

1 answers

Cherry-pick

A menos que me haya engañado a mí mismo, entonces si haces " git cherry-pick ", entonces obtienes:

  • LOCAL: el commit sobre el que estás fusionando (es decir, el ENCABEZADO de tu rama)
  • REMOTO: el commit que estás seleccionando (es decir, )
  • BASE: el padre del commit que estás escogiendo (ie C^, ie el padre de C)

Si no está claro inmediatamente por qué BASE debería ser C^, consulte la sección "por qué" debajo.

Mientras tanto, tomemos un ejemplo, y veamos que la BASE puede ser pero a menudo no será un ancestro común durante un cherry-pick. 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 haces " git cherry-pick ", entonces la BASE para esa 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 su lugar haces " git cherry-pick , entonces BASE será commit D. (C será LOCAL y E será REMOTA.)

Rebase

Para el contexto de fondo, rebase es aproximadamente iterado. En particular, el tema de rebase encima del maestro (es decir, "git checkout topic; 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 cherry-pick:

  • LOCAL: el commit que estás escogiendo encima
    • Este es el HEAD of the new topic_rebased branch
    • Para el primer commit solamente, esto será lo mismo que el HEAD of master{[14]]}
  • REMOTO: el commit que estás seleccionando (es decir, )
  • BASE: el padre del commit que estás escogiendo (C^, es decir, el padre de C)

Esto implica algo a tener en cuenta sobre LOCAL vs REMOTO, si desea evitar confusiones:

A pesar de que estaba en el tema de rama cuando inició el rebase, LOCAL nunca se refiere a un commit en la rama topic mientras que una rebase está en curso. En su lugar, LOCAL siempre se refiere a una confirmación en la nueva rama que se está creando (basada en topic_rebased).

(Si uno falla en mantener esto en mente, entonces durante una fusión desagradable uno puede comenzar a preguntarse, "Espera, ¿por qué está diciendo que estos son cambios locales? Juro que fueron cambios hechos en el maestro, no en mi rama.")

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

Digamos que tenemos gráfico de confirmación

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

Y actualmente estamos en branch foo_feature (indicado por"*"). Si ejecutamos "git rebase master", la rebase se realizará 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 común real 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, B y D podrían tener ya han sido podados del árbol en este punto, pero los estoy dejando aquí, para que sea más fácil detectar cualquier ancestro común potencial.)

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 ancestro común relevante de nada. (Por ejemplo, no es un ancestro común de los actuales LOCALES y REMOTOS, B' y D. Y no es un ancestro común de los jefes de rama originales, C y D). Después de este paso, usted tener 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 del gráfico, produciendo:

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

¿Por qué se define BASE como es?

Como se ha señalado anteriormente, tanto para un cherry-pick como para un rebase, BASE es el padre (C^) del commit C que se extrae. En el caso general C^ no es un ancestro común, así que ¿por qué llamarlo BASE? (En una BASE de fusión normal es un ancestro común. Y parte de los éxitos de git en la fusión se debe a su capacidad de encontrar un buen ancestro común.)

Esencialmente, uno hace esto como una forma de implementar la funcionalidad "patch" a través del algoritmo normal three-way merge . En particular, obtienes estas propiedades "irregulares":

  • Si no modifica una 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 llama para cambiar no se parchean.)
  • If modifica una región dada del archivo y tu rama deja esa región sola, entonces la versión de esa región de prevalecerá. (Es decir, las regiones que el" parche " pide cambiar se parchean.)
  • Si modifica una región dada del archivo pero su rama también ha modificado esa región, entonces obtiene un conflicto de fusión.
 31
Author: Chris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-21 23:34:10