Résoudre les conflits de fusion Git en faveur de leurs modifications lors d'un pull

1227

Comment résoudre un conflit de fusion git en faveur de modifications retirées?

Fondamentalement, je dois supprimer toutes les modifications conflictuelles d'une arborescence de travail sans avoir à passer par tous les conflits git mergetoolpendant un certain temps en conservant toutes les modifications sans conflit. Faites-le de préférence en tirant, pas après.

sanmai
la source
2
Duplicata de git pull from remote .. puis-je le forcer à écraser plutôt qu'à signaler des conflits? Vous pouvez y voir la même solution.
Dan Dascalescu
3
@DanDascalescu La réponse acceptée ne répond pas à ces questions, donc ce n'est clairement pas un doublon. De plus, cette autre question est assez ambiguë: il est très difficile de dire ce qui est demandé. Dans l'ensemble, je ne suis pas d'accord avec vous. Que voulez-vous dire là-dedans?
sanmai
2
@sanmai Vous avez deux réponses - et vous en avez accepté une. Pouvez-vous mieux expliquer ce que vous attendez d'une réponse et combien de détails souhaitez-vous ici?
Edward Thomson
2
@EdwardThomson bien, en fait, je pensais donner cette réputation pour la première réponse, mais si vous demandez, je pourrais attendre et voir si une meilleure réponse se présente
sanmai

Réponses:

1220
git pull -s recursive -X theirs <remoterepo or other repo>

Ou, tout simplement, pour le référentiel par défaut:

git pull -X theirs

Si vous êtes déjà en conflit ...

git checkout --theirs path/to/file
Pascal Fares
la source
40
Notez -s recursivequ'ici est redondant, car c'est la stratégie de fusion par défaut. Vous pouvez donc le simplifier git pull -X theirs, ce qui est fondamentalement équivalent à git pull --strategy-option theirs.
5
Si je fais cela, je me retrouve dans l' MERGINGétat. Je peux alors git merge --abortet réessayer, mais à chaque fois je me retrouve avec une fusion. … Je sais cependant qu'un rebase a été poussé vers mon amont, alors c'est peut-être la cause de cela?
Benjohn
22
Soyez prudent avec git checkout --theirs path/to/file. Utilisé lors du rebase et obtenu des résultats inattendus. Explication trouvée dans le doc: Notez que pendant git rebase et git pull --rebase, les nôtres et les leurs peuvent apparaître échangés; --ours donne la version de la branche sur laquelle les modifications sont rebasées, tandis que - theirs donne la version de la branche qui contient votre travail qui est rebasé.
Vuk Djapic
10
Notez que la git checkout --theirs/--ours pathpage de manuel indique qu'elle fonctionne pour les chemins non fusionnés . Donc s'il n'y avait pas de conflit dans le chemin, il est déjà fusionné cette commande ne fera rien. Cela peut entraîner des problèmes lorsque vous souhaitez par exemple la version «leur» d'un sous-dossier entier. Donc, dans ce cas, il serait plus sûr de faire git checkout MERGE_HEAD pathou d'utiliser le hachage de validation.
fsw
4
git pull -X theirscrée un commit de fusion s'il y a des conflits (par exemple si un autre committer a couru git push -fvers la télécommande). Si vous ne voulez pas de validations de fusion, exécutez plutôt git fetch && git reset --hard origin/master.
Dan Dascalescu
985

Vous pouvez utiliser l' option de stratégie récursive "la leur" :

git merge --strategy-option theirs

De l' homme :

ours
    This option forces conflicting hunks to be auto-resolved cleanly by 
    favoring our version. Changes from the other tree that do not 
    conflict with our side are reflected to the merge result.

    This should not be confused with the ours merge strategy, which does 
    not even look at what the other tree contains at all. It discards 
    everything the other tree did, declaring our history contains all that
    happened in it.

theirs
    This is opposite of ours.

Remarque: comme l'indique la page de manuel, l' option de stratégie de fusion "nôtre" est très différente de la stratégie de fusion "nôtre" .

Ikke
la source
Voici une explication plus détaillée: lostechies.com/joshuaflanagan/2010/01/29/…
mPrinC
227
Aussi git checkout --theirspour opérer sur un seul fichier conflictuel
dvd
48
Cela ne fonctionne pas si vous êtes déjà en état de résolution de conflit. Dans ce cas, je crois que la meilleure façon de résoudre est de git checkout <ref to theirs> -- the/conflicted.file; puis git addleurs changements.
ThorSummoner
54
@ThorSummoner Dans ce cas, il y a git checkout --leur chemin / de / fichier. De cette façon, vous n'avez pas à rechercher manuellement le hachage correct.
Ikke
8
@Ikke Cela devrait être fondamentalement sa propre réponse (et la réponse acceptée à cela) si vous me le demandez.
ThorSummoner
474

Si vous êtes déjà en état de conflit et que vous souhaitez simplement accepter tous les leurs:

git checkout --theirs .
git add .

Si vous voulez faire le contraire:

git checkout --ours .
git add .

C'est assez drastique, alors assurez-vous vraiment de tout effacer comme ça avant de le faire.

beaucoup à apprendre
la source
47
ou, n'utilisez pas le .et spécifiez le (s) fichier (s) à la place du point que vous souhaitez extraire. probablement moins "drastique" et exactement ce que vous voulez faire.
manroe
10
cela ne fonctionne pas si le fichier a été supprimé de l'autre branche: '<fichier>' n'a pas de version
Japster24
3
Je voterais plus si je le pouvais, revenez de temps en temps à cette réponse.
tarikki
6
Utilisez-le à la git add -uplace pour ignorer les fichiers qui ne sont pas sous contrôle de version.
Sudipta Basak
3
Cas hypothétique, trois modifications dans un fichier, une conflictuelle, deux sans conflit, cette solution appliquerait-elle des modifications non conflictuelles et résoudrait-elle la nôtre? Ou faudrait-il seulement notre version ignorant les changements non conflictuels de la leur?
pedromarce
222

OK, imaginez le scénario dans lequel je venais de:

Vous tentez un merge, ou peut-être un cherry-pick, et vous êtes arrêté avec

$ git cherry-pick 1023e24
error: could not apply 1023e24... [Commit Message]
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'

Maintenant, vous affichez le fichier en conflit et vous ne voulez vraiment pas conserver vos modifications. Dans mon cas ci-dessus, le fichier était en conflit sur une nouvelle ligne que mon IDE avait ajoutée automatiquement. Pour annuler vos modifications et accepter les leurs, la manière la plus simple est:

git checkout --theirs path/to/the/conflicted_file.php
git add path/to/the/conflicted_file.php

L'inverse de ceci (pour écraser la version entrante avec votre version) est

git checkout --ours path/to/the/conflicted_file.php
git add path/to/the/conflicted_file.php

Étonnamment, je n'ai pas pu trouver cette réponse très facilement sur le Net.

Theodore R. Smith
la source
15
Notez que, si l'on effectue un git statusentre checkoutet add, le fichier apparaît toujours comme "les deux modifiés".
évêque
Savez-vous s'il existe un moyen de le faire pour tous les fichiers en conflit? Si c'est le cas, ce serait une belle extension de votre réponse.
Drew Noakes
2
Je fais cela: git reset --hard et puis git pull [remote server name] [branch name] -Xtheirs(annule la fusion puis tire les nouveaux trucs par-dessus mes trucs) - je ne sais pas si c'est ce que vous voulez.
ssaltman
38

Les git pull -X theirsréponses peuvent créer un vilain commit de fusion ou émettre un

erreur: vos modifications locales dans les fichiers suivants seraient écrasées par la fusion:

Si vous souhaitez simplement ignorer toute modification locale des fichiers du référentiel, par exemple sur un client qui doit toujours être le miroir d'une origine, exécutez ceci (replace master par la branche souhaitée):

git fetch && git reset --hard origin/master

Comment ça marche? git fetchfait git pullmais sans fusion . Fait ensuite correspondre git reset --hardvotre arbre de travail au dernier commit. Toutes vos modifications locales apportées aux fichiers du référentiel seront ignorées , mais les nouveaux fichiers locaux seront laissés seuls.

Dan Dascalescu
la source
1
+1 - git fetch && git reset --hard {remote}/{branch}c'est ce qui a résolu mon problème. J'avais besoin d'abandonner complètement mes propres changements en faveur de l'état "leur" d'une branche, mais il s'est git pull -X theirsétouffé avec certains fichiers déplacés / renommés. Merci!
Ivaylo Slavov
23

Après la fusion de git, si vous rencontrez des conflits et que vous souhaitez que votre ou leur

git checkout --theirs .
git checkout --ours .
Mohit Kanojia
la source
Comment pourrais-je faire cela sur une base par morceau en conflit? Ce qui précède fonctionne au niveau d'un fichier, jetant tous les morceaux non conflictuels qu'un fichier en conflit pourrait avoir.
Jani
21

Pour résoudre tous les conflits avec la version dans une branche particulière:

git diff --name-only --diff-filter=U | xargs git checkout ${branchName}

Donc, si vous êtes déjà dans l'état de fusion et que vous souhaitez conserver la version principale des fichiers en conflit:

git diff --name-only --diff-filter=U | xargs git checkout master
Ariel Alvarez
la source
Et pour les personnes sur les fenêtres sans accès aux xargs de tuyau, comment cela se traduit-il?
tsemer
Cela n'ignorerait-il pas complètement vos modifications? Même ceux qui ne sont pas en état de conflit?
Valentin Heinitz
C'est ce que j'ai fini par faire. Malheureusement, il nécessite par la suite une git cherry-pick --continue ou une git commit --allow-emptycommande pour valider ces modifications, et il ne semble pas y avoir de système derrière lequel la commande est requise, ce qui rend l'automatisation difficile. Je suis en train de résoudre ce problème en testant l'existence d'un .git/COMMIT_EDITMSGfichier, mais cela semble hacky et fragile, et je ne suis pas encore convaincu que cela fonctionne toujours.
Konrad Rudolph
C'est bien, cela signifie que si vous résolvez manuellement certains (et le faites git add), vous pouvez résoudre le reste en bloc via cela. git checkout --ours/ git checkout --theirsest également utile.
rcoup
18

Veuillez noter que parfois cela ne fonctionnera pas :

git checkout - notre chemin / vers / fichier

ou

git checkout - leur chemin / vers / fichier

Je l'ai fait à la place, en supposant que HEAD est à nous et MERGE_HEAD est à eux

git checkout HEAD -- path/to/file

ou:

git checkout MERGE_HEAD -- path/to/file

Après cela, nous sommes bons:

git add .

Si vous voulez en savoir plus, consultez le merveilleux article de torek ici: git checkout --ours ne supprime pas les fichiers de la liste des fichiers non fusionnés

Nicolas D
la source
12

Utilisateurs IDE VS Code (Git intégré):

Si vous souhaitez accepter toutes les modifications entrantes dans le fichier de conflit, procédez comme suit.

1. Go to command palette - Ctrl + Shift + P
2. Select the option - Merge Conflict: Accept All Incoming

De même, vous pouvez faire pour d'autres options comme Accepter tous les deux, Accepter tout le courant, etc.,

SridharKritha
la source
2
Cela semble ne fonctionner que pour un seul fichier, mais pas tous les fichiers avec des conflits.
Yoryo
1

J'avais une next-versionbranche de longue date avec des tonnes de suppressions de fichiers qui avaient changé develop, des fichiers qui avaient été ajoutés à différents endroits sur les deux branches, etc.

Je voulais prendre tout le contenu de la next-versionbranche dans develop, tout en un gros commit de fusion.

La combinaison des commandes ci-dessus qui a fonctionné pour moi était:

git merge -X theirs next-version
# lots of files left that were modified on develop but deleted on next-version
git checkout next-version .
# files removed, now add the deletions to the commit
git add .
# still have files that were added on develop; in my case they are all in web/
git rm -r web

Pas une nouvelle réponse, juste en combinant des extraits de nombreuses réponses, en partie pour rassurer que vous pourriez avoir besoin de toutes ces réponses.

Gordon
la source
1

Si vous êtes déjà en état de conflit et que vous ne souhaitez pas extraire le chemin un par un. Vous pouvez essayer

git merge --abort
git pull -X theirs
Lee Chee Kiam
la source
-1

depuis https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging

Cela fera essentiellement une fausse fusion. Il enregistrera un nouveau commit de fusion avec les deux branches en tant que parents, mais il ne regardera même pas la branche dans laquelle vous fusionnez. Il enregistrera simplement comme résultat de la fusion le code exact dans votre branche actuelle.

$ git merge -s ours mundo

Fusion faite par la stratégie «nôtre».

$ git diff HEAD HEAD~

Vous pouvez voir qu'il n'y a aucune différence entre la branche sur laquelle nous étions et le résultat de la fusion.

Cela peut souvent être utile pour inciter Git à penser qu'une branche est déjà fusionnée lors d'une fusion ultérieure. Par exemple, supposons que vous ayez créé une branche de version et que vous ayez effectué un travail sur celle-ci que vous souhaiterez fusionner à nouveau dans votre branche principale à un moment donné. En attendant, certains correctifs de bogues sur master doivent être rétroportés dans votre branche de publication. Vous pouvez fusionner la branche bugfix dans la branche release et également fusionner la nôtre - la même branche dans votre branche master (même si le correctif est déjà là) donc quand vous fusionnerez plus tard la branche release, il n'y aura aucun conflit depuis le bugfix.

Une situation que j'ai trouvée utile si je veux que master reflète les changements d'une nouvelle branche de sujet. J'ai remarqué que -Xtheirs ne fusionne pas sans conflits dans certaines circonstances ... par exemple

$ git merge -Xtheirs topicFoo 

CONFLICT (modify/delete): js/search.js deleted in HEAD and modified in topicFoo. Version topicFoo of js/search.js left in tree.

Dans ce cas, la solution que j'ai trouvée était

$ git checkout topicFoo

à partir de topicFoo, fusionnez d'abord dans master en utilisant la stratégie -s our, cela créera le faux commit qui n'est que l'état de topicFoo. $ git merge -s our master

vérifier le commit de fusion créé

$ git log

passez à la caisse principale

$ git checkout master

fusionnez la branche de sujet en arrière, mais cette fois utilisez la stratégie récursive -Xtheirs, cela vous présentera maintenant une branche principale avec l'état de topicFoo.

$ git merge -X theirs topicFoo
Amos Folarin
la source