J'ai une branche appelée demo
que je dois fusionner avec la 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
Ma seule préoccupation est que s'il y a des problèmes de fusion , je veux dire git
d'écraser les modifications dans la master
branche sans me donner d'invite de fusion. Donc, fondamentalement, les changements de demo
branche devraient automatiquement écraser les changements de master
branche.
J'ai regardé autour de moi, il y a plusieurs options, mais je ne veux pas prendre de risques avec la fusion.
git push -f origin master
-f
option avec lamerge
commande et non avec lapush
commandeRéponses:
Pas vraiment lié à cette réponse, mais je laisserais tomber
git pull
, qui ne fait quegit fetch
suivregit 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: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 larecursive
stratégie par défaut et laresolve
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
à lacolour
ligne 17 et elles passentfred
à labarney
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 fusionnezdemo
(le leur) dansmaster
(le nôtre) et que vous voulez les changementsdemo
, 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: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
à lagit 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 localdemo
(vos utilisationsgit pull
qui, si votre Git est très ancien, échoueront à se mettre à jourorigin/demo
mais produiront le même résultat final). Le second est de faireorigin/master
entrermaster
.Ce n'est pas clair pour moi qui met à jour
demo
et / oumaster
. Si vous écrivez votre propre code sur votre propredemo
branche et que d' autres écrivent du code et le poussent vers lademo
brancheorigin
, 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 à lagit rebase
place. D'un autre côté, si vous ne faites jamais aucun de vos propres commitsdemo
, vous n'avez même pas besoin d' unedemo
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 rapidementdemo
pour correspondre à la mise à jourorigin/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 surmaster
, vous avez certainement besoin d' unmaster
. 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'êtregit merge --ff-only origin/master
.Disons que vous ne faites jamais vos propres engagements
demo
. Dans ce cas, nous pouvonsdemo
complètement abandonner le nom :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).la source
J'ai eu un problème similaire, où je devais remplacer efficacement tout fichier qui avait des changements / conflits avec une branche différente.
La solution que j'ai trouvée était d'utiliser
git merge -s ours branch
.Notez que l'option est
-s
et non-X
.-s
indique l'utilisation deours
comme stratégie de fusion de niveau supérieur,-X
appliquerait l'ours
option à larecursive
stratégie de fusion, ce qui n'est pas ce que je (ou nous) voulons dans ce cas.Steps, où se
oldbranch
trouve la branche avec laquelle vous souhaitez écrasernewbranch
.git checkout newbranch
vérifie la succursale 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 souhaitez écraserget merge newbranch
fusionne dans la nouvelle branche, écrasant l'ancienne branchela source
Cette approche de fusion ajoutera un commit sur
master
lequel se colle dans tout ce qui se trouvefeature
, sans se plaindre de conflits ou d'autres conneries.Avant de toucher quoi que ce soit
Maintenant, prépare le maître
Obtenez
feature
tout habilléAllez pour le tuer
la source
Changes from the other tree that do not conflict with our side are reflected in the merge result
. Cela n'a pas fonctionné pour moi, car j'avais des commits fusionnés proprement dans ma branche qui était en cours d'écrasement. Est-ce qu'il y a un autre moyen?Vous pouvez essayer l'option "notre" dans git merge,
la source
demo
version soit préférée même s'il fusionne avecmaster
. Il y-X theirs
en a aussi, mais il n'est pas clair que ce soit ce que le PO veut vraiment.ours
fait lors de l'utilisation sur le backend avec l'-s
option. Lors de l'utilisationours
avec-X
: Il supprime tout ce que l'autre arbre a fait, déclarant que notre historique contient tout ce qui s'est passé. sourceQuand j'ai essayé d'utiliser
-X theirs
et d'autres commutateurs de commande connexes, j'ai continué à obtenir un commit de fusion. Je ne l'ai probablement pas bien compris. Une alternative facile à comprendre est simplement de supprimer la branche puis de la suivre à nouveau.Ce n'est pas exactement une "fusion", mais c'est ce que je cherchais quand je suis tombé sur cette question. Dans mon cas, je voulais extraire des modifications d'une branche distante qui ont été forcées.
la source