web-dev-qa-db-fra.com

Ordre de fusion Git Octopus de plusieurs branches

J'ai eu une chose intéressante en utilisant git, me demandant si quelqu'un pouvait me l'expliquer afin que je puisse mieux comprendre.

Lors d'une fusion de plusieurs branches (A, B),

git merge A B

échoue en tant qu'avance non rapide, tandis que

git merge B A

a bien fonctionné. Pourquoi serait-ce?

38
James Maroney

Supposons que A est un strict, enfant direct de la branche courante. Supposons ensuite que B est un enfant strict et direct de A .

La fusion de poulpe, qui traite les têtes données comme arguments de gauche à droite , incrémentalement par rapport à l'arbre, mais indépendamment par rapport à l'index réussit sans conflit s'il essaie d'appliquer B puis A, mais rencontre un conflit s'il effectue la conversion.

Selon le git-merge manuel, section MERGE STRATEGIES:

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 d'une avance rapide vers A, l'étiquette de maître n'a pas été poussée en avant, contrairement à l'arborescence.

 ~/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 de poulpe, j'exécute ceci 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 fusion-octopus, il essaie de détecter que la branche que nous essayons d'ajouter est déjà dans l'arborescence (deuxième case du for boucle). En effet, à 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 faire le second read-tree.

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

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

tl; dr: vous voulez que vos branches de fusion de poulpe touchent des fichiers distincts

48
Francois G