¿Git Revert también usa la combinación de 3 vías?

Cuando ejecuto git revert , puede suceder que se produzca un conflicto. ¿Git confía en la combinación de 3 vías, como se representa en la pregunta fusión interna (consulte la tabla a continuación) también para revert ?

enter image description here

¿Cuál es la base de fusión para una reversión? En ¿Cuáles son los tres files en una combinación de 3 vías para el rebasamiento interactivo usando git y meld? está bastante claro, pero es difícil imaginar esto para revertir.

 A - B - C - D - C^-1 

(Si quiero revertir C al final)

Sí, hay una base. (Nota al pie: este código ha cambiado mucho desde que lo observé hace años. Recogí algo de esto para mi respuesta reciente, que has vinculado aquí).

Tanto git cherry-pick como git revert están implementados por los mismos files fuente ( builtin/revert.c y sequencer.c ).

Como dices, la parte difícil es decidir qué devise para la base de combinación. En su ejemplo, estamos deshaciendo los B to- C diffs. Aquí está el código fuente real (en sequencer.c ), algo desglosado:

 if (opts->action == REPLAY_REVERT) { base = commit; base_label = msg.label; next = parent; next_label = msg.parent_label; strbuf_addstr(&msgbuf, "Revert \""); strbuf_addstr(&msgbuf, msg.subject); strbuf_addstr(&msgbuf, "\"\n\nThis reverts commit "); strbuf_addstr(&msgbuf, oid_to_hex(&commit->object.oid)); if (commit->parents && commit->parents->next) { strbuf_addstr(&msgbuf, ", reversing\nchanges made to "); strbuf_addstr(&msgbuf, oid_to_hex(&parent->object.oid)); } strbuf_addstr(&msgbuf, ".\n"); } else { 

[este es el caso de selección de cerezas, incluido solo para completar]

  const char *p; base = parent; base_label = msg.parent_label; next = commit; next_label = msg.label; 

Cuando ingresemos aquí, ingrese los puntos a los datos de C y parent puntos parent a los datos de B La asignación a base variable es lo que establece la base de fusión, y la next -vs- base es lo que debe traer. Para cherry-pick, el padre del compromiso (posiblemente elegido a través de -m ) es la base de fusión. Para revertir, el commit en sí mismo es la base de combinación y el padre (otra vez posiblemente de -m ) es what-to-bring-in.

La otra forma de get el mismo efecto (que es cómo se hizo esto hace muchos años, y hasta hace poco, pensé que esto todavía se estaba usando) es aplicar de forma inversa una confirmación como la producida por el git format-patch . En este caso, la versión base construida es el segundo hash (la parte B de la parte A..B de una diferencia textual):

 /* * This represents a "patch" to a file, both metainfo changes * such as creation/deletion, filemode and content changes represented * as a series of fragments. */ struct patch { [snip] char old_sha1_prefix[41]; char new_sha1_prefix[41]; static void reverse_patches(struct patch *p) { [snip] swap(p->old_sha1_prefix, p->new_sha1_prefix); 

La function reverse_patches se reverse_patches después de extraer el text en una serie de parches, es decir, después del código que extrae los hash de las líneas de index , colocando las partes A y B en los campos de prefijo antiguo y nuevo. Luego (después de reverse_patches ), cuando se aplica realmente cada parche, git usa los valores guardados sha1 antiguo y nuevo para falsificar una combinación de 3 vías (si git am se da --3way ). Entonces al aplicar un parche de text de forma inversa, obtendríamos el nuevo file como la base y el original como el objective, al igual que con el código del sequencer.c .