Pas vraiment lié à cette réponse, mais je laisserais tomber git pull
, qui ne fait que git fetch
suivre git merge
. Vous effectuez trois fusions, ce qui va obliger votre Git à exécuter trois opérations d'extraction, lorsqu'une extraction est tout ce dont vous aurez besoin. Par conséquent:
git fetch origin # update all our origin/* remote-tracking branches
git checkout demo # if needed -- your example assumes you're on it
git merge origin/demo # if needed -- see below
git checkout master
git merge origin/master
git merge -X theirs demo # but see below
git push origin master # again, see below
Contrôle de la fusion la plus délicate
La partie la plus intéressante ici est git merge -X theirs
. Comme root545 l'a noté , les -X
options sont transmises à la stratégie de fusion, et la recursive
stratégie par défaut et la resolve
stratégie alternative prennent -X ours
ou -X theirs
(l'une ou l'autre, mais pas les deux). Pour comprendre ce qu'ils font, cependant, vous devez savoir comment Git trouve et traite les conflits de fusion .
Un conflit de fusion peut se produire dans un fichier 1 lorsque la version de base diffère à la fois de la version actuelle (également appelée locale, HEAD ou --ours
) et de l'autre version (également appelée distante ou --theirs
) de ce même fichier. Autrement dit, la fusion a identifié trois révisions (trois commits): la base, la nôtre et la leur. La version "de base" provient de la base de fusion entre notre commit et leur commit, comme on le trouve dans le graphe de commit (pour beaucoup plus à ce sujet, voir d'autres publications de StackOverflow). Git a alors trouvé deux ensembles de changements: "ce que nous avons fait" et "ce qu'ils ont fait". Ces changements sont (en général) trouvés sur une ligne par ligne, purement textuellebase. Git n'a aucune compréhension réelle du contenu des fichiers; il s'agit simplement de comparer chaque ligne de texte.
Ces changements sont ce que vous voyez dans la git diff
sortie et, comme toujours, ils ont également un contexte . Il est possible que les choses que nous avons modifiées soient sur des lignes différentes de celles qu'elles ont modifiées, de sorte que les changements semblent ne pas entrer en collision, mais le contexte a également changé (par exemple, en raison de notre changement proche du haut ou du bas du fichier, pour que le fichier s'épuise dans notre version, mais dans la leur, ils ont également ajouté plus de texte en haut ou en bas).
Si les modifications se produisent sur des lignes différentes - par exemple, nous passons color
à la colour
ligne 17 et elles passent fred
à la barney
ligne 71 - alors il n'y a pas de conflit: Git prend simplement les deux modifications. Si les modifications se produisent sur les mêmes lignes, mais sont des modifications identiques , Git prend une copie de la modification. Seulement si les changements sont sur les mêmes lignes, mais sont des changements différents, ou ce cas particulier de contexte interférant, vous obtenez un conflit de modification / modification.
Les options -X ours
et -X theirs
indiquent à Git comment résoudre ce conflit, en ne sélectionnant qu'un seul des deux changements: le nôtre ou le leur. Puisque vous avez dit que vous fusionnez demo
(le leur) dans master
(le nôtre) et que vous voulez les changements demo
, vous voudriez -X theirs
.
L'application aveugle -X
, cependant, est dangereuse. Ce n'est pas parce que nos modifications ne sont pas en conflit ligne par ligne que nos modifications ne sont pas réellement en conflit! Un exemple classique se produit dans les langages avec des déclarations de variables. La version de base peut déclarer une variable inutilisée:
int i;
Dans notre version, nous supprimons la variable inutilisée pour faire disparaître un avertissement du compilateur - et dans leur version, ils ajoutent une boucle quelques lignes plus tard, en utilisant i
comme compteur de boucle. Si nous combinons les deux changements, le code résultant ne se compile plus. L' -X
option n'est d'aucune aide ici puisque les changements sont sur des lignes différentes .
Si vous disposez d'une suite de tests automatisés, la chose la plus importante à faire est d'exécuter les tests après la fusion. Vous pouvez le faire après la validation et réparer les choses plus tard si nécessaire; ou vous pouvez le faire avant de valider, en ajoutant --no-commit
à la git merge
commande. Nous laisserons les détails pour tout cela à d'autres publications.
1 Vous pouvez également obtenir des conflits en ce qui concerne les opérations "à l'échelle du fichier", par exemple, peut-être que nous corrigeons l'orthographe d'un mot dans un fichier (afin que nous ayons un changement), et qu'ils suppriment le fichier entier (afin qu'ils aient un supprimer). Git ne résoudra pas ces conflits tout seul, quels que soient les -X
arguments.
Faire moins de fusions et / ou des fusions plus intelligentes et / ou utiliser le rebase
Il y a trois fusions dans nos deux séquences de commandes. La première consiste à introduire origin/demo
dans le local demo
(vos utilisations git pull
qui, si votre Git est très ancien, échoueront à se mettre à jour origin/demo
mais produiront le même résultat final). Le second est de faire origin/master
entrer master
.
Ce n'est pas clair pour moi qui met à jour demo
et / ou master
. Si vous écrivez votre propre code sur votre propre demo
branche et que d' autres écrivent du code et le poussent vers la demo
branche origin
, alors cette première fusion peut avoir des conflits ou produire une véritable fusion. Le plus souvent, il est préférable d'utiliser le rebase, plutôt que de fusionner, pour combiner le travail (certes, c'est une question de goût et d'opinion). Si tel est le cas, vous voudrez peut-être utiliser à la git rebase
place. D'un autre côté, si vous ne faites jamais aucun de vos propres commits demo
, vous n'avez même pas besoin d' une demo
branche. Sinon, si vous souhaitez automatiser une grande partie de cela, mais être en mesure de vérifier soigneusement quand il y a des commits que vous et d'autres avez faits, vous voudrez peut-être utilisergit merge --ff-only origin/demo
: cela vous fera avancer rapidement demo
pour correspondre à la mise à jour origin/demo
si possible, et échouera simplement si ce n'est pas le cas (à quel point vous pouvez inspecter les deux ensembles de modifications et choisir une véritable fusion ou un rebase selon le cas).
Cette même logique s'applique master
, bien que vous faites la fusion sur master
, vous avez certainement besoin d' un master
. Cependant, il est encore plus probable que vous souhaitiez que la fusion échoue si elle ne peut pas être effectuée en tant que non-fusion à avance rapide, donc cela devrait probablement également l'être git merge --ff-only origin/master
.
Disons que vous ne faites jamais vos propres engagements demo
. Dans ce cas, nous pouvons demo
complètement abandonner le nom :
git fetch origin # update origin/*
git checkout master
git merge --ff-only origin/master || die "cannot fast-forward our master"
git merge -X theirs origin/demo || die "complex merge conflict"
git push origin master
Si vous êtes en train de faire vos propres demo
commits de branche, ce n'est pas utile; vous pouvez aussi bien conserver la fusion existante (mais peut-être l'ajouter en --ff-only
fonction du comportement souhaité), ou la changer pour effectuer un rebase. Notez que les trois méthodes peuvent échouer: la fusion peut échouer avec un conflit, la fusion avec --ff-only
peut ne pas être en mesure d'avancer rapidement, et le rebase peut échouer avec un conflit (le rebase fonctionne, essentiellement, en sélectionnant les commits, qui utilise la fusion machines et peut donc provoquer un conflit de fusion).
git push -f origin master