40 votes

Ordre de fusion de branches multiples dans Git octopus

Il m'est arrivé quelque chose d'intéressant en utilisant git, je me demandais si quelqu'un pouvait m'expliquer pour que je puisse mieux comprendre.

Lorsqu'on fait une fusion de plusieurs branches (A,B),

git merge A B

échoue en tant que non-transfert rapide, tandis que

git merge B A

a bien fonctionné. Pourquoi ça ?

49voto

huitseeker Points 6049

Supposons que A soit un strict, enfant direct de la branche en cours. Supposons alors que B est un enfant strict et direct de A .

La fusion des pieuvres, qui traite les têtes données comme arguments de gauche à droite , de manière incrémentielle par rapport à l'arbre mais indépendamment par rapport à l'indice réussit sans conflit s'il essaie d'appliquer B et ensuite A, mais rencontre un conflit s'il fait la conversion.

Conformément à la git-merge manuel, section STRATÉGIES DE FUSION :

octopus
   This resolves cases with more than two heads, but refuses to do a
   complex merge that needs manual resolution.

Par exemple :

 ~                 $ git init testdir && cd testdir && echo "This is C" > myfile
 Initialized empty Git repository in /home/huitseeker/testdir/.git/

 ~/testdir         $ git add myfile && git commit -m "C" 
 [master (root-commit) f0c8c82] C
  1 files changed, 1 insertions(+), 0 deletions(-)
  create mode 100644 myfile

 ~/testdir(master) $ git checkout -b "A" && echo "This is A1" > myfile
 Switched to a new branch 'A'
 ~/testdir(A)      $ git commit -m "A1" myfile
 [A ac5b51c] A1
  1 files changed, 1 insertions(+), 1 deletions(-)

 ~/testdir(A)      $ git checkout -b "B" && echo "This is B1" >> myfile
 Switched to a new branch 'B'
 ~/testdir(B)      $ git commit -m "B1" myfile
 [B 5bc838c] B1
  1 files changed, 1 insertions(+), 0 deletions(-)

 ~/testdir(B)      $ git checkout master
 Switched to branch 'master'
 ~/testdir(master) $ git merge B A
 Fast-forwarding to: B
 Already up-to-date with A
 Merge made by octopus.
  myfile |    3 ++-
  1 files changed, 2 insertions(+), 1 deletions(-)

 ~/testdir(master) $ git reset --hard HEAD^^^
 HEAD is now at f0c8c82 C
 ~/testdir(master) $ git merge A B
 Fast-forwarding to: A
 Fast-forwarding to: B
 error: Entry 'myfile' would be overwritten by merge. Cannot merge.
 Merge with strategy octopus failed.

 ~/testdir(master) $ cat myfile
 This is A1

En effet, lors de l'avance rapide vers A, l'étiquette du maître n'a pas été avancée, alors que l'arbre l'a été.

 ~/testdir(master) $ git status
 # On branch master
 # Changes to be committed:
 #   (use "git reset HEAD <file>..." to unstage)
 #
 #  modified:   myfile
 #

Si, en regardant le code de ce que fait la fusion octopus, je l'effectue manuellement (regardez ci-dessus pour les hachages) :

 ~/testdir(master) $ git reset --hard f0c8c82
 HEAD is now at f0c8c82 C     
 ~/testdir(master) $ git read-tree -u -m f0c8c82 ac5b51c
 ~/testdir(master) $ git read-tree -u -m f0c8c82 5bc838c
 error: Entry 'myfile' would be overwritten by merge. Cannot merge.

Dans l'autre sens ( merge B A ), maintenant, si vous regardez à nouveau le code de merge-octopus, il essaie de détecter la branche que nous essayons d'ajouter est déjà dans l'arbre (deuxième case de la for boucle). En effet, lors de la fusion de A, il voit que ac5b51c (alias la tête de A) est l'ancêtre commun de A et B, et abandonne sans effectuer la deuxième opération read-tree .

Ce comportement est cohérent avec la nouvelle version de git : bien que j'aie pointé vers la v.1.3.1, cela se produit toujours avec ma version.

 ~/testdir(master) $ git --version
 git version 1.7.5.4

En résumé : vous voulez que vos branches de fusion octopus touchent des fichiers distincts

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X