Résoudre un conflit Git avec des fichiers binaires

464

J'utilise Git sur Windows (msysgit) pour suivre les modifications de certains travaux de conception que j'ai effectués.

Aujourd'hui, je travaille sur un autre PC (avec repo à distance brian) et j'essaie maintenant de fusionner les modifications effectuées aujourd'hui dans ma version locale habituelle sur mon ordinateur portable.

Sur mon ordinateur portable, j'ai l'habitude git pull brian masterde tirer les modifications dans ma version locale. Tout allait bien, sauf le document InDesign principal - cela se présente comme un conflit.

La version sur PC ( brian) est la dernière que je souhaite conserver mais je ne sais pas quelles commandes indiquent au référentiel d'utiliser celle-ci.

J'ai essayé de copier directement le fichier sur mon ordinateur portable, mais cela semble interrompre tout le processus de fusion.

Est-ce que quelqu'un peut-il me montrer la bonne direction?

Kevin Wilson
la source

Réponses:

854

git checkoutaccepte une option --oursou --theirspour des cas comme celui-ci. Donc, si vous avez un conflit de fusion et que vous savez que vous voulez juste le fichier de la branche dans laquelle vous fusionnez, vous pouvez faire:

$ git checkout --theirs -- path/to/conflicted-file.txt

pour utiliser cette version du fichier. De même, si vous savez que vous voulez votre version (pas celle qui est fusionnée), vous pouvez utiliser

$ git checkout --ours -- path/to/conflicted-file.txt
mipadi
la source
47
J'ai dû exécuter 'git reset HEAD path / to / conflicted-file.txt' sur le fichier avant d'utiliser --ours, sinon cela ne semblait pas avoir d'effet.
Zitrax
6
@Zitrax Avez-vous différencié le fichier après l'exécution git checkout --ours? La page de manuel suggère (à mon humble avis) que le paiement --nos / - le leur supprimera la modification de la liste "les deux modifiés, ont besoin de fusion" et l'ajoutera à l'index, et je pense que ce n'est pas correct. Je pense que vous devrez exécuter git addaprès le paiement.
Tim Keating
15
Remarque: vous voulez toujours faire "git add conflicted-file.txt " et "git commit". Handily, quand je l'ai essayé, le message de validation a été pré-rempli avec une note sur le conflit.
Edward Falk du
2
la formulation de "la branche dans laquelle vous fusionnez" est dangereusement proche de "la branche dans laquelle vous fusionnez", je pense que simplement supprimer la préposition serait mieux: "la branche dans laquelle vous fusionnez", qui refléterait également la commande git (c. git merge branch_name-à-d.).
andrybak
13
Quelques points importants qui manquent toujours dans les explications de ce sujet. Lorsque vous effectuez un rebase au lieu de fusionner, la signification de --theiret --oursest permutée, c'est-à-dire - leur == branche actuellement extraite et --ours est la branche, généralement une branche distante, ou la spécification de chemin que vous essayez de fusionner dans le courant branche. L' [space]--[space]option élimine toute ambiguïté en spécification de chemin entre le nom de la branche et la spécification de chemin qui existent tous les deux avec le même nom (par exemple, un nom de branche existant est "abc" et un répertoire existe appelé "abc").
BoiseBaked
147

Vous devez résoudre le conflit manuellement (copier le fichier), puis valider le fichier (peu importe si vous l'avez copié ou utilisé la version locale) comme ceci

git commit -a -m "Fix merge conflict in test.foo"

Git effectue automatiquement des validations automatiques après la fusion, mais lorsqu'il détecte des conflits qu'il ne peut pas résoudre par lui-même, il applique tous les correctifs qu'il a déterminés et vous laisse le reste à résoudre et à valider manuellement. La page de manuel Git Merge , le cours accéléré Git-SVN ou cette entrée de blog peuvent éclairer la façon dont cela est censé fonctionner.

Modifier: voir l'article ci-dessous, vous n'avez pas réellement à copier les fichiers vous-même, mais vous pouvez utiliser

git checkout --ours -- path/to/file.txt
git checkout --theirs -- path/to/file.txt

pour sélectionner la version du fichier que vous souhaitez. La copie / l'édition du fichier ne sera nécessaire que si vous souhaitez un mélange des deux versions.

Veuillez marquer la réponse de mipadis comme étant la bonne.

VolkA
la source
1
Merci pour ça. Je ne savais pas s'il y avait une sorte de méthode intégrée pour marquer un fichier comme étant le «correct». Explique pourquoi je n'ai pas pu trouver la commande inexistante!
Kevin Wilson
Oui, c'est un peu peu intuitif - quelque chose comme git resolution serait bien, mais ce serait aussi une étape supplémentaire ...
VolkA
120

Vous pouvez également surmonter ce problème avec

git mergetool

ce qui provoque la gitcréation de copies locales du binaire en conflit et la génération de votre éditeur par défaut sur eux:

  • {conflicted}.HEAD
  • {conflicted}
  • {conflicted}.REMOTE

De toute évidence, vous ne pouvez pas modifier utilement les fichiers binaires dans un éditeur de texte. Au lieu de cela, vous copiez le nouveau {conflicted}.REMOTEfichier {conflicted}sans fermer l'éditeur. Ensuite, lorsque vous fermez, l'éditeur gitvoit que la copie de travail non décorée a été modifiée et votre conflit de fusion est résolu de la manière habituelle.

RobM
la source
8
Si les fichiers sont volumineux ou si vous ne voulez pas risquer d'ouvrir le binaire dans un éditeur de texte, vous pouvez appuyer sur ctrl + c à l'invite mergetool (" Hit return to start merge resolution tool") et git laissera les fichiers supplémentaires en place. Vous pouvez ensuite les modifier ou les fusionner dans un outil externe (utile pour les formats de documents binaires comme LibreOffice / OpenOffice / MSWord) et enregistrer le résultat dans le nom de fichier d'origine. Pour informer git que le conflit est résolu, git addle nom de fichier d'origine et vous pouvez ensuite terminer la validation de la fusion.
Felix
18

Pour résoudre le problème en conservant la version dans votre branche actuelle (ignorez la version de la branche dans laquelle vous fusionnez), il suffit d'ajouter et de valider le fichier:

git commit -a

Pour résoudre le problème en remplaçant la version de votre branche actuelle par la version de la branche dans laquelle vous fusionnez, vous devez d'abord récupérer cette version dans votre répertoire de travail, puis l'ajouter / valider:

git checkout otherbranch theconflictedfile
git commit -a

Expliqué plus en détail

Joshua Flanagan
la source
1
Je préfère cette variante à la réponse acceptée, car elle est plus intuitive, d'autant plus que le sens de ces "- nos" et "- leurs" est inversé en cas de rebasage.
Antony Hatchkins
11

La réponse de mipadi n'a pas vraiment fonctionné pour moi, je devais faire ceci:

git checkout - notre chemin / vers / fichier.bin

ou, pour conserver la version fusionnée dans:

git checkout - leur chemin / vers / fichier.bin

puis

git add path / to / file.bin

Et puis j'ai pu refaire "git mergetool" et continuer sur le prochain conflit.

kris
la source
6

À partir des git checkoutdocuments

git checkout [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...

--ours
--theirs
Lors de la vérification des chemins à partir de l'index, consultez l'étape # 2 ( ours) ou # 3 ( theirs) pour les chemins non fusionnés.

L'index peut contenir des entrées non fusionnées en raison d'une précédente fusion ayant échoué. Par défaut, si vous essayez d'extraire une telle entrée de l'index, l'opération d'extraction échouera et rien ne sera extrait. L'utilisation -fignorera ces entrées non fusionnées. Le contenu d'un côté spécifique de la fusion peut être extrait de l'index à l'aide de --oursou --theirs. Avec -m, les modifications apportées au fichier d'arborescence de travail peuvent être ignorées pour recréer le résultat de la fusion conflictuelle d'origine.

user456814
la source
4

Je suis tombé sur un problème similaire (vouloir retirer un commit qui incluait des fichiers binaires qui provoquaient des conflits lors de la fusion), mais je suis tombé sur une solution différente qui peut être entièrement réalisée à l'aide de git (c'est-à-dire ne pas avoir à copier manuellement les fichiers). J'ai pensé que je l'inclurais ici, donc au moins je m'en souviendrai la prochaine fois que j'en aurai besoin. :) Les étapes ressemblent à ceci:

% git fetch

Cela récupère les dernières validations du référentiel distant (vous devrez peut-être spécifier un nom de branche distante, selon votre configuration), mais n'essaie pas de les fusionner. Il enregistre la validation dans FETCH_HEAD

% git checkout FETCH_HEAD stuff/to/update

Cela prend la copie des fichiers binaires que je veux et écrase ce qui est dans l'arborescence de travail avec la version extraite de la branche distante. git n'essaie pas de fusionner, vous vous retrouvez donc avec une copie exacte du fichier binaire de la branche distante. Une fois cela fait, vous pouvez ajouter / valider la nouvelle copie comme d'habitude.

Brian Webster
la source
4

Cette procédure consiste à résoudre les conflits de fichiers binaires après avoir soumis une demande d'extraction à Github:

  1. Donc, sur Github, vous avez trouvé que votre demande d'extraction a un conflit sur un fichier binaire.
  2. Revenez maintenant à la même branche git sur votre ordinateur local.
  3. Vous (a) recréez / recréez à nouveau ce fichier binaire, et (b) validez le fichier binaire résultant dans cette même branche git.
  4. Ensuite, vous poussez à nouveau cette même branche git vers Github.

Sur Github, sur votre pull request, le conflit devrait disparaître.

david m lee
la source
C'est exactement la procédure dont j'ai besoin
Huifang Feng
2

Si le binaire est quelque chose de plus qu'une DLL ou quelque chose qui peut être édité directement comme une image, ou un fichier de mélange (et vous n'avez pas besoin de jeter / sélectionner un fichier ou l'autre), une vraie fusion ressemblerait à ceci:

Je suggère de rechercher un outil diff orienté vers ce que vous êtes un fichier binaire, par exemple il y en a des gratuits pour les fichiers image par exemple

et les comparer.

S'il n'y a pas d'outil de comparaison pour comparer vos fichiers, alors si vous avez le générateur d'origine du fichier bin (c'est-à-dire qu'il existe un éditeur pour cela ... comme blender 3d, vous pouvez ensuite inspecter manuellement ces fichiers, également consultez les journaux et demandez à l'autre personne ce que vous devez inclure) et effectuez une sortie des fichiers avec https://git-scm.com/book/es/v2/Git-Tools-Advanced-Merging#_manual_remerge

$ git show :1:hello.blend > hello.common.blend $ git show :2:hello.blend > hello.ours.blend $ git show :3:hello.blend > hello.theirs.blend

tyoc213
la source
1

Je suis tombé sur deux stratégies pour gérer la diff / fusion de fichiers binaires avec Git sur Windows.

  1. Tortoise git vous permet de configurer des outils de diff / fusion pour différents types de fichiers en fonction de leurs extensions de fichier. Voir 2.35.4.3. Paramètres avancés de diff / fusion http://tortoisegit.org/docs/tortoisegit/tgit-dug-settings.html . Cette stratégie repose bien sûr sur la disponibilité d'outils de diff / fusion appropriés.

  2. En utilisant les attributs git, vous pouvez spécifier un outil / commande pour convertir votre fichier binaire en texte, puis laisser votre outil de diff / fusion par défaut faire la chose. Voir http://git-scm.com/book/it/v2/Customizing-Git-Git-Attributes . L'article donne même un exemple d'utilisation de métadonnées pour diff images.

J'ai eu les deux stratégies pour travailler avec des fichiers binaires de modèles logiciels, mais nous avons opté pour tortoise git car la configuration était facile.

BoJohDoh
la source
0

J'utilise Git Workflow pour Excel - https://www.xltrail.com/blog/git-workflow-for-excel pour résoudre la plupart de mes problèmes de fusion liés aux fichiers binaires. Cette application open source m'aide à résoudre les problèmes de manière productive sans perdre trop de temps et me permet de choisir la bonne version du fichier sans aucune confusion.

Siddhartha Thota
la source
0

mon cas ressemble à un bug .... en utilisant git 2.21.0

J'ai fait un pull ... il se plaignait des fichiers binaires:

warning: Cannot merge binary files: <path>
Auto-merging <path>
CONFLICT (content): Merge conflict in <path>
Automatic merge failed; fix conflicts and then commit the result.

Et puis rien dans aucune des réponses ici n'a abouti à une sortie qui avait un sens.

Si je regarde quel fichier j'ai maintenant ... c'est celui que j'ai édité. Si je fais soit:

git checkout --theirs -- <path>
git checkout --ours -- <path>

J'obtiens une sortie:

Updated 0 paths from the index

et j'ai toujours ma version du fichier. Si je rm et que je passe à la caisse, ça dira 1 à la place, mais cela me donne toujours ma version du fichier.

git mergetool dit

No files need merging

et le statut git dit

    All conflicts fixed but you are still merging.
    (use "git commit" to conclude merge)

Une option est d' annuler le commit ... mais je n'ai pas eu de chance et j'ai eu de nombreux commit , et ce mauvais était le premier. Je ne veux pas perdre de temps à répéter cela.

donc pour résoudre cette folie:

Je viens de courir

git commit

qui perd la version distante, et gaspille probablement un peu d'espace pour stocker un fichier binaire supplémentaire ... puis

git checkout <commit where the remote version exists> <path>

ce qui me rend la version à distance

puis édité à nouveau le fichier ... et ensuite valider et pousser, ce qui signifie encore probablement perdre de l'espace avec une autre copie du fichier binaire.

Peter
la source
Dans mon cas, après avoir essayé, git checkout --ours <path>j'ai reçu Updated 0 paths from the index . J'ai corrigé cela avec la git add <path>commande, qui fait la même chose.
Andriy