Trouver de l'aide pour résoudre les conflits durant un merge

Tous les changements que git peut fusionner automatiquement sont déjà ajoutés à l'index, donc git diff ne vous montre que les conflits. Il a une syntaxe peu commune:

$ git diff
diff --cc file.txt
index 802992c,2b60207..0000000
--- a/file.txt
+++ b/file.txt
@@@ -1,1 -1,1 +1,5 @@@
++<<<<<<< HEAD:file.txt
 +Hello world
++=======
+ Goodbye
++>>>>>>> 77976da35a11db4580b80ae27e8d65caf5208086:file.txt

Souvenez-vous que le commit qui sera effectué après que nous ayons résolu ce conflit aura 2 parents: l'un sera le sommet de la branche courante (HEAD) et l'autre sera le sommet de la branche qui s'occupe de la fusion, stockée temporairement dans MERGE_HEAD.

Durant le merge, l'index garde 3 versions de chaque fichiers. Une de ces 3 "étape de fichier" représente une version différente du fichier:

$ git show :1:fichier.txt   # Le fichier dans l'ancêtre commun des 2 branches
$ git show :2:fichier.txt   # La version présente dans HEAD.
$ git show :3:fichier.txt   # La version présente dans MERGE_HEAD.

Quand vous demandez à git diff de vous montrer les conflits, il fait une différence en 3 points entre les résultats conflictuels de merge dans le répertoire de travail avec les version 2 et 3 pour montrer seulement les morceaux de code qui ont du contenu de chaque côté, mélangés (en d'autres termes, quand un morceau du résultat de la fusion ne vient que de la version 2, alors ce morceau n'est pas en conflit est n'est pas affiché. Idem pour la version 3).

La différence en début de chapitre vous montre les différences entre la version de travail de fichier.txt et les versions 2 et 3. Donc au lieux de rajouter les préfixes "+" ou "-" devant chaque ligne, on utilise maintenant 2 colonnes pour ces préfixes. La première colonne est utilisée pour les différences entre le premier parent et la copie du répertoire de travail et la deuxième pour les différences entre le second parent et la copie du répertoire de travail. (Voir la section "COMBINED DIFF FORMAT" dans la documentation de git diff-files pour plus de détails sur ce format.)

Après avoir résolu le conflit de manière évidente (mais avant de mettre à jour l'index), le diff ressemblera à:

$ git diff
diff --cc file.txt
index 802992c,2b60207..0000000
--- a/file.txt
+++ b/file.txt
@@@ -1,1 -1,1 +1,1 @@@
- Hello world
-Goodbye
++Goodbye world

Cela montre que notre version résolue a effacé "Hello world" du premier parent, effacé "Goodbye" du second parent, puis ajouté "Goodbye world", qui était avant absent des 2.

Quelques options spéciales de diff permettent de faire la différence entre le répertoire de travail et les différentes étapes:

$ git diff -1 file.txt          # différence avec l'étape 1
$ git diff --base file.txt      # même chose que ci-dessus
$ git diff -2 file.txt          # différence avec l'étape 2
$ git diff --ours file.txt      # même chose que ci-dessus
$ git diff -3 file.txt          # différence avec l'étape 3
$ git diff --theirs file.txt    # même chose que ci-dessus

Les commandes git log and gitk fournissent aussi de l'aide particulière pour les fusions :

$ git log --merge
$ gitk --merge

Cela vous montrera tous les commits qui existent seulement dans HEAD ou dans MERGE_HEAD et qui concernant les fichiers non fusionnés.

Vous pouvez aussi utiliser git mergetool, qui vous permet de fusionner des fichiers non fusionnés en utilisant des outils externes comme emacs ou kdiff3.

Chaque fois que vous résolvez les conflits d'un fichier et que vous mettez à jour l'index :

$ git add fichier.txt

les différentes étapes de ces fichiers "s'effondreront", après quoi git-diff ne montrera plus (par défaut) de différence pour ce fichier.

Merge Multiples

Vous pouvez combiner plusieurs branches en même temps en les listant simplement dans la même commande git merge. Par exemple :

$ git merge scott/master rick/master tom/master

est l'équivalent de :

$ git merge scott/master
$ git merge rick/master
$ git merge tom/master

Subtree

Il y a des moments où vous voulez inclure le contenu d'un projet développé indépendamment dans votre projet. Vous pouvez juste récupérer le code de cet autre projet tant que les chemins ne rentrent pas en conflit.

Les problèmes surviennent quand il y a des fichiers en conflit. Les candidats potentiels sont les Makefiles et les autres noms de fichiers standardisés. Vous pouvez fusionner ces fichiers, mais ce n'est pas forcément ce que vous voulez faire. Une meilleure solution pour ce problème peut être de fusionner le projet dans un sous-répertoire. Mais la stratégie de fusion ne supporte la récursivité, donc la simple récupération des fichiers ne fonctionnera pas.

Vous voudrez alors utiliser la stratégie de fusion subtree, qui vous aidera dans cette situation.

Dans cet exemple, disons que vous avez un dépôt dans /path/to/B (si vous voulez ça peut aussi être une adresse URL). Vous voulez fusionner la branche "master" de ce dépôt dans le sous-répertoire dir-B de la branche actuelle.

Voici la séquence de commande que vous utiliserez :

$ git remote add -f Bproject /path/to/B (1)
$ git merge -s ours --no-commit Bproject/master (2)
$ git read-tree --prefix=dir-B/ -u Bproject/master (3)
$ git commit -m "Merge B project as our subdirectory" (4)
$ git pull -s subtree Bproject master (5)

Utiliser le fusion subtree vous permet d'apporter moins de complications administratives aux utilisateurs de votre dépôt. Elle est aussi compatible avec des version plus anciennes de git (jusqu'à Git v1.5.2) et vous aurez le code juste après le clonage.

Cependant, si vous utilisez des sous-modules, vous pouvez alors choisir de ne pas transférer les objets de ces sous-modules. Cela peut poser un problème lors de l'utilisation des fusions subtree.

Il est aussi plus facile d'effectuer des changements dans votre autre projet si vous utiliser les sous-modules.

(from Using Subtree Merge)