J'ai une branche appelée demo
que je dois fusionner avec master
branche. Je peux obtenir le résultat souhaité avec les commandes suivantes:
git pull Origin demo
git checkout master
git pull Origin master
git merge demo
git Push Origin master
Mon seul souci est, s'il y a des problèmes de fusion, je veux dire à git
d'écraser les modifications dans la branche master
sans me donner l'invite de fusion. Donc, fondamentalement, les changements dans la branche demo
devraient écraser automatiquement ceux de la branche master
.
J'ai regardé autour de moi, il y a plusieurs options mais je ne veux pas prendre de risques avec la fusion.
Pas vraiment lié à cette réponse, mais j'aurais abandonné git pull
, qui ne fait que lancer git fetch
suivi de git merge
. Vous faites trois fusions, ce qui obligera 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
La partie la plus intéressante ici est git merge -X theirs
. Comme noté root545 , les options -X
sont transférées à la stratégie de fusion, et la stratégie par défaut recursive
et la stratégie alternative resolve
prennent -X ours
ou -X theirs
(l'une ou l'autre). , mais pas les deux). Pour comprendre ce qu’ils font, vous devez savoir comment Git trouve et traite les conflits de fusion .
Un conflit de fusion peut survenir dans certains fichiers.1 lorsque la version de base diffère de la version actuelle (également appelée locale, HEAD ou --ours
) version et l'autre version (également appelée distante ou --theirs
) de ce même fichier. C'est-à-dire que la fusion a identifié trois révisions (trois commits): base, la nôtre et la leur. La version "base" provient de la base de fusion entre notre commit et leur commit, comme indiqué dans le graphe de commit (pour plus d'informations à ce sujet, voir autre Messages StackOverflow). Git a ensuite trouvé deux ensembles de modifications: "ce que nous avons fait" et "ce qu'ils ont fait". Ces modifications se trouvent (en général) ligne par ligne, purement textuelles . Git ne comprend pas vraiment le contenu du fichier. c'est simplement comparer chaque ligne de texte.
Ces modifications correspondent à ce que vous voyez dans la sortie de git diff
et, comme toujours, elles ont également un contexte . Il est possible que les choses que nous avons changées soient sur des lignes différentes de celles qu'ils ont changées, de sorte que les modifications ne semblent pas entrer en collision, mais le contexte a également changé (par exemple, notre modification étant proche du haut ou du bas du fichier, de sorte 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 différentes lignes , par exemple, nous changeons color
en colour
à la ligne 17 et elles changent fred
à barney
à la ligne 71 - il n'y a alors aucun conflit: Git prend simplement les deux modifications . Si les changements se produisent sur les mêmes lignes, mais sont identiques , Git prend une copie du changement. Vous obtenez un conflit de modification/modification uniquement si les modifications sont sur les mêmes lignes, mais qu'il s'agisse de modifications différentes ou de ce cas particulier de contexte interférant.
Les options -X ours
et -X theirs
indiquent à Git comment résoudre ce conflit en sélectionnant l'un des deux changements: le nôtre ou le leur. Puisque vous avez dit que vous fusionniez demo
(le leur) en master
(le nôtre) et que vous souhaitiez les modifications apportées à demo
, vous souhaiteriez le -X theirs
.
L'application aveugle de -X
est cependant dangereuse. Le simple fait que nos modifications n'entrent pas en conflit ligne par ligne ne signifie pas que nos modifications ne sont pas en conflit! Un exemple classique se produit dans les langues 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 modifications, le code résultant ne sera plus compilé. L'option -X
n'est d'aucune aide ici car les modifications sont sur des lignes différentes .
Si vous avez une suite de tests automatisée, le plus important est d'exécuter les tests après la fusion. Vous pouvez le faire après vous être engagé et régler le problème plus tard si nécessaire. ou vous pouvez le faire avant de commettre, en ajoutant --no-commit
à la commande git merge
. Nous laisserons les détails de tout cela à d'autres publications.
1Vous pouvez également avoir des conflits en ce qui concerne les opérations "au niveau du fichier", par exemple, nous corrigeons peut-être l'orthographe d'un mot dans un fichier (afin que nous ayons une modification), et ils delete l'intégralité du fichier (afin qu'ils aient une suppression). Git ne résoudra pas seul ces conflits, quels que soient les arguments -X
.
Il y a trois fusions dans nos deux séquences de commandes. La première consiste à introduire Origin/demo
dans le local demo
(le vôtre utilise git pull
qui, si votre Git est très ancien, ne pourra pas mettre à jour Origin/demo
mais produira le même résultat final). La seconde consiste à introduire Origin/master
dans master
.
Il m'est difficile de savoir qui met à jour demo
et/ou master
. Si vous écrivez votre propre code sur votre propre branche demo
, et écrivez du code et le transmettez à la branche demo
sur Origin
, alors cette fusion de première étape peut avoir des conflits ou produire une fusion réelle. Plus souvent qu'autrement, il est préférable d'utiliser rebase plutôt que de fusionner pour combiner travail (certes, c'est une question de goût et d'opinion). Si tel est le cas, vous pouvez utiliser plutôt git rebase
. Par contre, si vous ne faites jamais vos propres commits sur demo
, vous n'avez même pas besoin de a demo
branche. Alternativement, si vous voulez automatiser beaucoup de choses, mais que vous pouvez vérifier soigneusement quand il y a des commits que vous et d'autres faites, vous voudrez peut-être utiliser git merge --ff-only Origin/demo
: ceci fera avancer rapidement votre demo
pour correspondre le Origin/demo
mis à jour, si possible, et échouez carrément si ce n'est pas le cas (vous pouvez alors inspecter les deux ensembles de modifications et choisir une fusion ou une base réelle, selon le cas).
Cette même logique s'applique à master
, bien que vous fassiez la fusion sur master
, vous avez donc absolument besoin d'un master
. Cependant, il est même plus probable que vous souhaitiez que la fusion échoue si elle ne peut pas être effectuée en tant que non-fusion rapide, ce qui devrait donc également être git merge --ff-only Origin/master
.
Disons que vous ne faites jamais vos propres commits sur demo
. Dans ce cas, nous pouvons supprimer le nom demo
:
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 effectuez votre propre commise de branche demo
, ceci n'est pas utile; vous pouvez aussi bien conserver la fusion existante (mais peut-être ajouter --ff-only
en fonction du comportement souhaité) ou la changer pour une refonte. 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 la rebase peut échouer avec un conflit (la refonte fonctionne essentiellement, la sélection des commandes est validée, elle utilise le mécanisme de fusion et peut donc donner lieu à un conflit de fusion).
Vous pouvez essayer "la nôtre" dans la fusion de git,
branche de fusion git -X notre
Cette option oblige les mecs en conflit à se résoudre eux-mêmes automatiquement en privilégiant notre version. Les modifications de l’autre arbre qui ne sont pas en conflit avec notre côté se reflètent dans le résultat de la fusion. Pour un fichier binaire, tout le contenu est pris de notre côté.
J'avais un problème similaire, je devais remplacer efficacement tout fichier comportant des modifications/des conflits avec une branche différente.
La solution que j'ai trouvée consistait à utiliser git merge -s ours branch
.
Notez que l'option est -s
et non pas -X
. -s
indique l'utilisation de ours
comme stratégie de fusion de niveau supérieur, -X
appliquerait l'option ours
à la stratégie de fusion recursive
, ce qui n'est pas ce que Je (ou nous) voulons dans ce cas.
Étapes, où oldbranch
est la branche que vous souhaitez écraser avec newbranch
.
git checkout newbranch
vérifie la branche que vous souhaitez conservergit merge -s ours oldbranch
fusionne dans l'ancienne branche, mais conserve tous nos fichiers.git checkout oldbranch
vérifie la branche que vous voulez écraserget merge newbranch
fusionne dans la nouvelle branche et remplace l'ancienne.