Choisissez la stratégie de fusion Git pour des fichiers spécifiques («les nôtres», «les miens», «les leurs»)

207

Je suis en train de rebaser après a git pull --rebase. J'ai quelques fichiers qui ont des conflits de fusion. Comment puis-je accepter «leurs» modifications ou «mes» modifications pour des fichiers spécifiques?

$ git status
# Not currently on any branch.
# You are currently rebasing.
#   (fix conflicts and then run "git rebase --continue")
#   (use "git rebase --skip" to skip this patch)
#   (use "git rebase --abort" to check out the original branch)
#
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:  CorrectlyMergedFile
#
# Unmerged paths:
#   (use "git reset HEAD <file>..." to unstage)
#   (use "git add <file>..." to mark resolution)
#
#       both modified: FileWhereIWantToAcceptTheirChanges
#       both modified: FileWhereIWantToAcceptMyChanges

Normalement, j'ouvre simplement le fichier ou un outil de fusion et accepte manuellement toutes "leurs" ou "mes" modifications. Cependant, je soupçonne que je manque une commande git pratique.

Notez également que je ne pourrai choisir une stratégie de fusion pour chaque fichier que lorsque je verrai quels fichiers sont en conflit et éventuellement quels sont les conflits.

Steven Wexler
la source
@AbeVoelker Je ne pense pas que cela résout mon problème. Je souhaite sélectionner une stratégie de fusion pour des fichiers spécifiques. Notez également que je ne saurai quelle stratégie de fusion utiliser lorsque je serai dans mon rebase et je verrai quels fichiers ont rencontré des conflits et quels sont les conflits.
Steven Wexler
J'ai modifié cette question pour être plus générique: stackoverflow.com/questions/278081/… . Peut-être pouvons-nous fermer cette question en double? Est-ce approprié?
@TheShadow Cela me semble raisonnable.
Steven Wexler
Je ne savais pas s'il était approprié de changer le titre de l'autre question en ce que j'ai fait, car j'ai retiré la partie sur la résolution des fichiers binaires. J'ai rétabli l'autre question à ce qu'elle était auparavant, donc cette question actuelle ajoute encore de la valeur.

Réponses:

251

Pour chaque fichier en conflit que vous obtenez, vous pouvez spécifier

git checkout --ours -- <paths>
# or
git checkout --theirs -- <paths>

À partir des git checkoutdocuments

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

--ours
--theirs
Lors de l'extraction de 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.


la source
9
Est-il possible d'accepter les leurs pour tous les fichiers laissés en mémoire?
aslakjo
42
@aslakjo git rebase -s recursive -X <ours/theirs>ou git merge -s recursive -X <ours/theirs>. Gardez à l'esprit que pour un rebase, «le nôtre» et «le leur» sont inversés par rapport à ce qu'ils sont lors d'une fusion. Vous pourriez probablement aussi utiliser un glob de fichier / shell, comme git checkout --theirs -- *.txt.
2
Merci beaucoup, @Cupcake, le renversement inattendu de ours/theirsrebase me rendait fou !! (Il est logique maintenant que je pense à la façon dont un rebase fonctionne réellement, mais pas du tout intuitif.)
Dan Lenski
2
@DanLenski rebase en général n'est qu'un outil vraiment difficile à comprendre au début, mais une fois que vous comprenez comment cela fonctionne, vous pouvez faire toutes sortes de choses vraiment puissantes avec.
1
@VincentSels en fait, vous devez masquer le caractère *, sinon, le shell essaiera de le développer. dans votre cas, vous git checkout --outs -- "**/*.csproj"ferez ce que vous voulez dire. La même chose est vraie, par exemple pour git lfs track "*.jpg". Si vous avez des fichiers jpg dans votre CWD, sans les guillemets, seuls ceux-ci seront suivis.
eFloh
117

Même si cette question reçoit une réponse, elle fournit un exemple de ce que «leur» et «le nôtre» signifient dans le cas de git rebase vs merge. Voir ce lien

Git Rebase
theirs est en fait la branche actuelle dans le cas de rebase . Ainsi, l'ensemble de commandes ci-dessous accepte réellement vos modifications de branche actuelles sur la branche distante.

# see current branch
$ git branch
... 
* branch-a
# rebase preferring current branch changes during conflicts
$ git rebase -X theirs branch-b

Git Merge
Pour fusion , le sens de theirset oursest inversé. Donc, pour obtenir le même effet lors d'une fusion , c'est-à-dire, conservez vos modifications de branche actuelles ( ours) sur la branche distante fusionnée ( theirs).

# assuming branch-a is our current version
$ git merge -X ours branch-b  # <- ours: branch-a, theirs: branch-b
Abe
la source
2
eh bien, c'est une distinction assez importante! Merci de clarifier.
verboze
26

Notez que git checkout --ours|--theirsva écraser les fichiers entièrement , en choisissant soit theirsou la oursversion, ce qui pourrait être ou ne pas être ce que vous voulez faire (si vous avez des modifications non conflictuelles provenant de l'autre côté, ils seront perdus).

Si, à la place, vous souhaitez effectuer une fusion à trois sur le fichier et résoudre uniquement les mecs en conflit à l' aide --ours|--theirs, tout en conservant les mecs non en conflit des deux côtés en place, vous souhaiterez peut-être recourir à git merge-file; voir les détails dans cette réponse .

jakub.g
la source
1
En ce qui concerne les "modifications non conflictuelles" qui seront perdues - cela se réfère uniquement aux fichiers où il y a des modifications non conflictuelles dans des lignes spécifiques ailleurs dans le même fichier, ou toutes les modifications de tous les fichiers dans des historiques alignés?
ktamlyn
2
@ktamlyn par "changements non conflictuels", je voulais dire des changements dans le même fichier. Par exemple, il y a deux Hunks modifiées (parties) dans example.txtdans la oursversion, on est en conflit (également changé dans la theirsrévision), autre est non conflictuel. Si vous le faites git checkout --theirs example.txt, il lira à l'aveuglette tout le fichier lors de la theirsrévision, et la partie non conflictuelle du diff sera perdue.
jakub.g
1
Merci! C'était une clarification nécessaire pour moi, même si les «changements dans le même fichier» sont les plus sensés dans ce contexte.
ktamlyn
Cela devrait être la réponse acceptée, bien que cela ne donne pas vraiment de réponse, mais souligne un problème important dans l'autre solution proposée.
tomasyany
1
Si vous souhaitez revenir au fichier en conflit d'origine, vous pouvez l'exécuter git checkout --merge <path>.
Andrew Keeton