Quelle est la signification précise de «nôtre» et «leur» en git?

323

Cela peut sembler trop basique d'une question, mais j'ai cherché des réponses et je suis plus confus maintenant qu'avant.

Que signifie «nôtre» et «leur» dans git lors de la fusion de ma branche dans mon autre branche? Les deux branches sont "les nôtres".

Dans un conflit de fusion, "la nôtre" est-elle toujours la partie supérieure des deux versions affichées?

Est-ce que «la nôtre» fait toujours référence à la branche vers laquelle HEAD pointait lorsque la fusion a commencé? Si oui, alors pourquoi ne pas utiliser une référence possessive claire comme "branche actuelle" au lieu d'utiliser un pronom possessif comme "nôtre" qui est référentiellement ambigu (puisque les deux branches sont techniquement les nôtres)?

Ou utilisez simplement le nom de la branche (au lieu de dire «le nôtre», dites simplement «maître local» ou autre)?

La partie la plus déroutante pour moi est que je spécifie dans le fichier .gitattributes d'une branche spécifique. Disons que dans la branche de test, j'ai le fichier .gitattributes suivant:

config.xml merge=ours

Maintenant, je vérifie et pointe HEAD vers master, puis je fusionne dans le test . Puisque le maître est à nous, et que les attributs .gitattributs du test ne sont pas extraits, cela aura-t-il même un effet? Si cela a un effet, puisque le maître est maintenant "le nôtre", que se passera-t-il?

CommaToast
la source

Réponses:

375

Je suppose que vous êtes confus ici parce que c'est fondamentalement déroutant. Pour aggraver les choses, tout le nôtre / le leur change de rôle (devient à l'envers) lorsque vous effectuez un rebase.

En fin de compte, au cours d' une git merge, la branche se réfère à la branche « la nôtre » vous fusionnez dans :

git checkout merge-into-ours

et la branche "leur" fait référence à la branche (unique) que vous fusionnez:

git merge from-theirs

et ici "les nôtres" et "les leurs" ont un certain sens, car même si "les leurs" sont probablement les vôtres de toute façon, "les leurs" n'est pas celui sur lequel vous étiez lorsque vous avez couru git merge.

Bien que l'utilisation du nom de la branche réelle puisse être plutôt cool, elle se désagrège dans des cas plus complexes. Par exemple, au lieu de ce qui précède, vous pouvez faire:

git checkout ours
git merge 1234567

où vous fusionnez par raw commit-ID. Pire, vous pouvez même faire ceci:

git checkout 7777777    # detach HEAD
git merge 1234567       # do a test merge

dans ce cas, aucun nom de branche n'est impliqué!

Je pense que c'est peu utile ici, mais en fait, dans la gitrevisionssyntaxe , vous pouvez faire référence à un chemin individuel dans l'index par numéro, lors d'une fusion en conflit

git show :1:README
git show :2:README
git show :3:README

L'étape # 1 est l'ancêtre commun des fichiers, l'étape # 2 est la version de la branche cible et l'étape # 3 est la version à partir de laquelle vous fusionnez.


La raison pour laquelle les notions "les nôtres" et "les leurs" sont échangées pendant rebaseque le rebase fonctionne en faisant une série de choix de cerises, dans une branche anonyme (mode HEAD détaché). La branche cible est la branche anonyme, et la branche issue de la fusion est votre branche d'origine (pré-rebase): donc "--ours" signifie que le rebase anonyme est en train de se construire tandis que "--theirs" signifie "notre branche est rebasée" .


Quant à l'entrée gitattributes: elle pourrait avoir un effet: «la nôtre» signifie vraiment «utiliser l'étape 2» en interne. Mais comme vous le constatez, il n'est pas réellement en place à ce moment-là, donc cela ne devrait pas avoir d'effet ici ... enfin, sauf si vous le copiez dans l'arbre de travail avant de commencer.

Soit dit en passant, cela s'applique à toutes les utilisations de la nôtre et de la leur, mais certaines sont au niveau d'un fichier entier ( -s ourspour une stratégie de fusion; git checkout --ourspendant un conflit de fusion) et certaines sont au coup par coup ( -X oursou -X theirspendant un -s recursivefusionner). Ce qui n'aide probablement pas avec la confusion.

Je n'ai jamais trouvé de meilleur nom pour ces derniers, cependant. Et: voir la réponse de VonC à une autre question, où git mergetoolintroduit encore plus de noms pour ceux-ci, les appelant "locaux" et "distants"!

torek
la source
28
+1. À propos des nôtres et des leurs inversés lors du rebase, voir aussi: stackoverflow.com/a/2960751/6309 et stackoverflow.com/a/3052118/6309
VonC
1
Deux choses «fusionnent» l'une avec l'autre. Lorsqu'une fusion se produit, les deux parties fusionnent «l'une dans l'autre». Je pense qu'il serait incorrect de dire que l'un des deux côtés "ne fusionne en rien". S'il n'y a pas de noms de branche impliqués (comme vous le faites remarquer), alors il y a des noms de commit impliqués (vous pouvez dire "7777777" et "1234567" au lieu de "nôtre" et "le leur"). Je comprends ce qui se passe lors d'un rebase et je ne trouve pas cela déroutant du tout. Je pense que "HEAD" et "entrant" fonctionneraient mieux que "le nôtre" et "le leur" car il y a toujours un "HEAD" (qu'il soit détaché ou non).
CommaToast
15
Je suppose que puisque la tête est le siège de l'esprit, qui est la source de l'identité, qui est la source de soi, il est un peu plus logique de penser à tout ce que HEAD désigne comme étant "le mien" ("le nôtre", puisque Je suppose que moi et la tête fait deux). Si rien de plus, ce sera juste un bon appareil mnémotechnique.
CommaToast
1
Cela étant dit, j'aime toujours faire une copie physique de la totalité du repo avant de faire quoi que ce soit comme le rebasage ...: D
CommaToast
3
"auquel cas aucun nom de branche n'est impliqué!" ... Il devrait donc utiliser à la place le commentaire / hachage de validation. Tout ce qu'il peut mettre la main sur. Pratiquement tout serait mieux que "le nôtre" et "le leur". Je me demande combien de milliers d'heures de développement cette confusion s'est évaporée. git's answer to C ++'s "most vexing parse";)
Jarrod Smith
49

Le ' nôtre ' dans Git fait référence à la branche de travail d'origine qui a une partie autoritaire / canonique de l'histoire de Git.

Le « leur » fait référence à la version qui contient le travail afin d'être rebasé (modifications à rejouer sur la branche actuelle).

Cela peut sembler être échangé à des personnes qui ne savent pas que le rebasage (par exemple git rebase) prend en fait votre travail en attente (qui est le leur ) afin de rejouer sur l'histoire canonique / principale qui est la nôtre , parce que nous rebasons notre modifications en tant que travail tiers.

La documentation de a git-checkoutété clarifiée dans Git> = 2.5.1 selon la f303016validation :

--ours --theirs

Lors de la vérification des chemins de l'index, consultez l'étape # 2 («la nôtre») ou # 3 («la leur») pour les chemins non fusionnés.

Notez que pendant git rebaseet git pull --rebase, «les nôtres» et «les leurs» peuvent apparaître échangés; --oursdonne la version de la branche sur laquelle les modifications sont rebasées, tandis que --theirsdonne la version de la branche qui contient votre travail qui est rebasé.

En effet, rebaseest utilisé dans un flux de travail qui traite l'historique sur la télécommande comme un canonique partagé et traite le travail effectué sur la branche que vous rebasiez comme le travail tiers à intégrer, et vous assumez temporairement le rôle de le gardien de l'histoire canonique pendant le rebase. En tant que gardien de l'histoire canonique, vous devez afficher l'historique depuis la télécommande en tant que ours(c'est-à-dire "notre histoire canonique partagée"), tandis que ce que vous avez fait sur votre branche latérale en tant que theirs(c'est-à-dire "le travail d'un contributeur en plus").

Car git-mergec'est expliqué de la manière suivante:

les notres

Cette option oblige les mecs en conflit à être résolus automatiquement et proprement en favorisant notre version. Les changements de l'autre arborescence qui n'entrent pas en conflit avec notre côté sont reflétés dans le résultat de la fusion. Pour un fichier binaire, tout le contenu est pris de notre côté.

Cela ne doit pas être confondu avec la nôtre stratégie de fusion, qui ne regarde même pas du tout ce que l'autre arbre contient. Il rejette tout ce que l'autre arbre a fait, déclarant que notre histoire contient tout ce qui s'y est passé.

les leurs

C'est l'opposé du nôtre.

De plus, voici comment les utiliser:

Le mécanisme de fusion ( git mergeet les git pullcommandes) permet de choisir les stratégies de fusion du backend avec -soption. Certaines stratégies peuvent également prendre leurs propres options, qui peuvent être adoptées en donnant des -X<option>arguments à git mergeet / ou git pull.


Parfois, cela peut être déroutant, par exemple:

  • git pull origin master-Xoursest notre section locale, -Xtheirsleur succursale (distante)
  • git pull origin master -r-Xoursest la leur (à distance), la -Xtheirsnôtre

Donc le 2ème exemple est opposé au 1er, parce que nous rebasons notre branche au-dessus de la distante, donc notre point de départ est distant, et nos changements sont traités comme externes.

Similaire pour les git mergestratégies ( -X ourset -X theirs).

Kenorb
la source
2
cette réponse semble obsolète => "git merge --ours" n'est pas une option valide
Alexander Mills
@AlexanderMills La réponse n'a pas parlé git merge, mais git pullet à git checkouttitre d'exemple. Si vous souhaitez utiliser ce paramètre avec git merge, vous devez utiliser -X ours. Vous pouvez toujours utiliser la --ourssyntaxe pour git checkout. J'ai clarifié davantage la réponse.
kenorb
46

Je sais que cela a été répondu, mais ce problème m'a confus tant de fois que j'ai mis en place un petit site Web de référence pour m'aider à me souvenir: https://nitaym.github.io/ourstheirs/

Voici les bases:

Fusionne:

$ git checkout master 
$ git merge feature

Si vous souhaitez sélectionner la version dans master:

$ git checkout --ours codefile.js

Si vous souhaitez sélectionner la version dans feature:

$ git checkout --theirs codefile.js

Rebases:

$ git checkout feature 
$ git rebase master 

Si vous souhaitez sélectionner la version dans master:

$ git checkout --ours codefile.js

Si vous souhaitez sélectionner la version dans feature:

$ git checkout --theirs codefile.js

(C'est pour les fichiers complets, bien sûr)

Nitay
la source
1
Ce site Web est super utile. Le style de l'organigramme et les mots codés par couleur rendent le site Web beaucoup plus facile à comprendre que les réponses SO. Je vous remercie.
Ron
10
  • La nôtre : c'est la branche sur laquelle vous vous trouvez actuellement.
  • Leur : c'est l'autre branche qui est utilisée dans votre action.

Donc, si vous êtes sur la version de branche / 2.5 et que vous y fusionnez la fonction de branche / nouveaux-boutons , le contenu tel que trouvé dans la version / 2.5 est ce à quoi le nôtre fait référence et le contenu que l'on trouve sur la fonction / nouveaux-boutons est ce à quoi leur fait référence à. Pendant une action de fusion, c'est assez simple.

Le seul problème pour lequel la plupart des gens tombent est le cas de rebase . Si vous effectuez une nouvelle base au lieu d'une fusion normale, les rôles sont échangés. Comment ça? Eh bien, cela est uniquement dû à la façon dont le rebasage fonctionne. Pensez à rebaser pour travailler comme ça:

  1. Tous les commits que vous avez effectués depuis votre dernier pull sont déplacés vers une branche qui leur est propre, appelons-la BranchX .
  2. Vous extrayez le chef de votre branche actuelle, rejetant toutes les modifications locales que vous avez eues, mais récupérant ainsi toutes les modifications que d'autres ont poussées pour cette branche.
  3. Désormais, chaque validation sur BranchX est triée sur le volet dans l'ordre de l'ancien au nouveau dans votre branche actuelle.
  4. BranchX est à nouveau supprimé et n'apparaîtra donc jamais dans aucun historique.

Bien sûr, ce n'est pas vraiment ce qui se passe, mais c'est un bon modèle mental pour moi. Et si vous regardez 2 et 3, vous comprendrez pourquoi les rôles sont échangés maintenant. Depuis le 2, votre branche actuelle est maintenant la branche du serveur sans aucune de vos modifications, donc c'est la nôtre (la branche sur laquelle vous êtes). Les modifications que vous avez apportées sont désormais sur une branche différente qui n'est pas la vôtre ( BranchX ) et donc ces modifications (bien qu'elles soient les modifications que vous avez apportées) sont les leurs (l'autre branche utilisée dans votre action).

Cela signifie que si vous fusionnez et que vous voulez que vos modifications gagnent toujours, vous diriez à git de toujours choisir "les nôtres" mais si vous rebase et que vous voulez que toutes vos modifications gagnent toujours, vous dites à git de toujours choisir "les leurs".

Mecki
la source
3

Je sais que cela n'explique pas le sens mais je me suis fait une petite image, comme référence pour rappeler laquelle utiliser:

entrez la description de l'image ici

J'espère que ça aide!

PS - Vérifiez également le lien dans la réponse de Nitay 🙂

Kamafeather
la source
3

Je posterai ma note ici, car je dois revenir ici encore et encore.

SCÉNARIO 1. Développeur normal: vous êtes un développeur qui ne peut pas fusionner masteret ne doit jouer qu'avec des featurebranches.

Cas 1: le maître est un roi. Vous souhaitez actualiser votre featurebranche (= rebase to master), car mastercontient de nouvelles mises à jour des dépendances et vous souhaitez écraser vos modestes modifications.

git checkout master
git pull

git checkout feature
git rebase -X ours master

Cas 2: vous êtes roi. Vous souhaitez rebaser votre featurebranche aux mastermodifications. Mais vous avez fait plus que vos collègues et vous souhaitez utiliser vos propres changements en priorité.

git checkout master
git pull

git checkout feature
git rebase -X theirs master

IMPORTANT: Comme vous pouvez le voir, les développeurs normaux devraient préférer rebaseet répéter chaque matin comme des exercices / du café.

SCÉNARIO 2. Fusion-sensei: Vous êtes un chef d'équipe et vous souhaitez fusionner d'autres branches et envoyer un résultat fusionné directement à un maître. masterest une branche que vous allez changer.

Cas 1: le maître est un roi Vous voulez fusionner une branche tierce, mais masterc'est une priorité. featureest une branche que votre senior a fait.

git checkout feature
git pull

git checkout master
git merge -X ours master

Cas 2: les nouveaux changements sont un roi Lorsque votre développeur senior a publié un cool featureet que vous souhaitez remplacer l'ancien s ** t dans la masterbranche.

git checkout feature
git pull

git checkout master
git merge -X theirs master

RAPPELEZ-VOUS: Se rappeler à minuit lequel choisir: masterc'est oursTOUJOURS. Et theirsc'est ce featureque les leurs ont fait.

DenisKolodin
la source
2

De git checkoutl'utilisation de:

-2, --ours            checkout our version for unmerged files
-3, --theirs          checkout their version for unmerged files
-m, --merge           perform a 3-way merge with the new branch

Lors de la résolution des conflits de fusion, vous pouvez le faire git checkout --theirs some_fileet git checkout --ours some_fileréinitialiser le fichier à la version actuelle et aux versions entrantes respectivement.

Si vous avez effectué git checkout --ours some_fileou git checkout --theirs some_filesouhaitez réinitialiser le fichier dans la version de fusion à 3 voies du fichier, vous pouvez le faire git checkout --merge some_file.

Joshua Ryan
la source