2016-05-10 6 views
1

Lorsque je cours git revert, il peut arriver qu'un conflit se produise. Git compte-t-il sur la fusion à 3 voies, comme cela est décrit dans la question merge internals (voir le tableau ci-dessous) également pour revert?Git Revert utilise-t-il également la fusion 3-way?

enter image description here

Quelle est la base de fusion pour un revert? En What are the three files in a 3-way merge for interactive rebasing using git and meld? il est tout à fait clair, mais il est difficile d'imaginer cela pour un retour.

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

(Si je veux revenir C à la fin.)

Répondre

3

Oui, il y a une base. (Note Side:.. Ce code a beaucoup changé depuis que je l'ai regardé il y a quelques années, je pris un peu de cela pour ma récente réponse cerise de choix, que vous avez lié ici)

Les deux git cherry-pick et git revert sont mis en œuvre par les mêmes fichiers sources (builtin/revert.c et sequencer.c). Comme vous le dites, la partie la plus difficile est de décider quoi faire pour la base de fusion. Dans votre exemple, nous annulons les diffs B -to- C. Voici le code source (en sequencer.c), dépouillé quelque peu:

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 { 

[c'est le cas écrémer, inclus juste pour être complet]

 const char *p; 

     base = parent; 
     base_label = msg.parent_label; 
     next = commit; 
     next_label = msg.label; 

Quand nous entrons ici, commit points Les données pour C et parent pointent vers les données pour B. L'affectation à la variable base est ce qui définit la base de fusion, et next -vs- base est ce qu'il faut apporter. Pour Cherry-Pick, le parent de la validation (éventuellement choisi via -m) est la base de fusion. Pour revenir, le commit lui-même est la base de fusion et le parent (encore possiblement de -m) est quoi-à-bring-in.

L'autre façon d'obtenir le même effet (comme cela a été fait il y a de nombreuses années, et jusqu'à récemment, je pensais que cela était encore utilisé) est d'appliquer une validation inversée comme produite par git format-patch. Dans ce cas, la version de base construit est le second hachage (la B partie de la A..B partie d'un diff textuel):

/* 
* 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 fonction reverse_patches est appelé après l'extraction du texte en une série de plaques, à savoir, après le code qui extrait les hachages des lignes index, en insérant les parties A et B dans les anciens et nouveaux champs de préfixe. Ensuite (après reverse_patches), lorsque vous appliquez réellement chaque patch, git utilise les anciennes et les nouvelles valeurs sha1 enregistrées pour simuler une fusion à 3 voies (si git am est donné --3way). Ainsi, en appliquant un patch de texte à l'envers, nous obtiendrions le nouveau fichier en tant que base et l'original en tant que cible, tout comme avec le code sequencer.c.