web-dev-qa-db-fra.com

Existe-t-il une version "la leur" de "git merge -s la nôtre"?

Lors de la fusion de la branche de sujet "B" dans "A" en utilisant git merge, j'obtiens des conflits. Je sais que tous les conflits peuvent être résolus en utilisant la version en "B".

Je suis au courant de git merge -s ours. Mais ce que je veux c'est quelque chose comme git merge -s theirs.

Pourquoi ça n'existe pas? Comment puis-je obtenir le même résultat après la fusion en conflit avec les commandes git existantes? (git checkout tous les fichiers non fusionnés de B)

MISE À JOUR: La "solution" consistant à ne rien supprimer de la branche A (le point de validation de la fusion dans la version B de l'arborescence) n'est pas ce que je recherche.

791
elmarco

Ajoutez l’option -X à theirs. Par exemple:

git checkout branchA
git merge -X theirs branchB

Tout va fusionner de la manière souhaitée.

La seule chose que j'ai vue causer des problèmes est si les fichiers ont été supprimés de branchB. Ils apparaissent comme des conflits si quelque chose d'autre que git a fait le déplacement.

La solution est facile. Il suffit de lancer git rm avec le nom de tous les fichiers supprimés:

git rm {DELETED-FILE-NAME}

Après cela, le -X theirs devrait fonctionner comme prévu.

Bien entendu, la suppression effective avec la commande git rm empêchera le conflit de se produire en premier lieu.


Note: Une option de formulaire plus long existe également. Pour l'utiliser, remplacez:

-X theirs

avec:

--strategy-option=theirs
932
Alan W. Smith

Une solution possible et testée pour fusionner brancheB dans notre branche extraiteA:

# in case branchA is not our current branch
git checkout branchA

# make merge commit but without conflicts!!
# the contents of 'ours' will be discarded later
git merge -s ours branchB    

# make temporary branch to merged commit
git branch branchTEMP         

# get contents of working tree and index to the one of branchB
git reset --hard branchB

# reset to our merged commit but 
# keep contents of working tree and index
git reset --soft branchTEMP

# change the contents of the merged commit
# with the contents of branchB
git commit --amend

# get rid off our temporary branch
git branch -D branchTEMP

# verify that the merge commit contains only contents of branchB
git diff HEAD branchB

Pour l'automatiser, vous pouvez l'envelopper dans un script en utilisant BranchA et BranchB comme arguments.

Cette solution conserve les premier et deuxième parents du commit de fusion, exactement comme vous le souhaiteriez de git merge -s theirs branchB.

200
Paul Pladijs

Les anciennes versions de git vous permettaient d'utiliser la stratégie de fusion "leur":

git pull --strategy=theirs remote_branch

Mais cela a depuis été supprimé, comme expliqué dans ce message par Junio ​​Hamano (le mainteneur de Git). Comme indiqué dans le lien, vous feriez plutôt ceci:

git fetch Origin
git reset --hard Origin

Attention, cependant, cela est différent d'une fusion réelle. Votre solution est probablement l'option que vous recherchez vraiment.

85
Pat Notz

J'ai utilisé la réponse de Paul Pladijs depuis maintenant. J'ai découvert, vous pouvez faire une fusion "normale", des conflits se produisent, alors vous faites

git checkout --theirs <file>

pour résoudre le conflit en utilisant la révision de l’autre branche. Si vous faites cela pour chaque fichier, vous avez le même comportement que vous attendez de

git merge <branch> -s theirs

Quoi qu'il en soit, l'effort est plus que ce ne serait avec la stratégie de fusion! (Ceci a été testé avec la version 1.8.0 de Git)

60
musicmatze

Le résultat souhaité n'est pas tout à fait clair. Il existe donc une certaine confusion quant à la "bonne" façon de le faire dans les réponses et leurs commentaires. J'essaie de donner un aperçu et de voir les trois options suivantes:

Essayez de fusionner et utilisez B pour les conflits

Ceci est pas la "version de leur pour git merge -s ours" mais la "version de leur pour pour git merge -X ours" (qui est l'abréviation de git merge -s recursive -X ours):

git checkout branchA
# also uses -s recursive implicitly
git merge -X theirs branchB

C'est ce que par exemple réponse d'Alan W. Smith le fait.

Utiliser le contenu de B uniquement

Cela crée une validation de fusion pour les deux branches, mais annule toutes les modifications de branchA et ne conserve que le contenu de branchB.

# Get the content you want to keep.
# If you want to keep branchB at the current commit, you can add --detached,
# else it will be advanced to the merge commit in the next step.
git checkout branchB

# Do the merge an keep current (our) content from branchB we just checked out.
git merge -s ours branchA

# Set branchA to current commit and check it out.
git checkout -B branchA

Notez que la fusion commet que le premier parent est maintenant celui de branchB et que le second est de branchA. C'est ce que par exemple réponse de Gandalf458 le fait.

Utiliser le contenu de B uniquement et conserver l'ordre parent correct

C'est la vraie "version pour git merge -s ours". Il a le même contenu que dans l'option précédente (c'est-à-dire seulement celui de branchB) mais l'ordre des parents est correct, c'est-à-dire que le premier parent provient de branchA et le second de branchB.

git checkout branchA

# Do a merge commit. The content of this commit does not matter,
# so use a strategy that never fails.
# Note: This advances branchA.
git merge -s ours branchB

# Change working tree and index to desired content.
# --detach ensures branchB will not move when doing the reset in the next step.
git checkout --detach branchB

# Move HEAD to branchA without changing contents of working tree and index.
git reset --soft branchA

# 'attach' HEAD to branchA.
# This ensures branchA will move when doing 'commit --amend'.
git checkout branchA

# Change content of merge commit to current index (i.e. content of branchB).
git commit --amend -C HEAD

C'est ce que réponse de Paul Pladijs fait (sans nécessiter de branche temporaire).

55
siegi

J'ai résolu mon problème en utilisant

git checkout -m old
git checkout -b new B
git merge -s ours old
20
elmarco

Si vous êtes sur la branche A:

git merge -s recursive -X theirs B

Testé sur la version 1.7.8 de Git

14
rafalmag

Lors de la fusion de la branche de sujet "B" dans "A" à l'aide de la fusion git, j'obtiens des conflits. Je sais que tous les conflits peuvent être résolus en utilisant la version en "B".

Je suis au courant de la fusion de notre société. Mais ce que je veux, c'est quelque chose comme git merge> -s leur.

Je suppose que vous avez créé une branche à partir de master et que vous souhaitez maintenant fusionner en master, en remplaçant les anciens éléments de master. C'est exactement ce que je voulais faire quand je suis tombé sur ce post.

Faites exactement ce que vous voulez faire, sauf fusionner d'abord une branche dans l'autre. Je viens de faire cela et cela a très bien fonctionné.

git checkout Branch
git merge master -s ours

Ensuite, passez à la caisse et fusionnez votre branche (ça se passe bien maintenant):

git checkout master
git merge Branch
8
Gandalf458

Pour faire correctement une fusion qui prend seulement l'entrée de la branche que vous fusionnez, vous pouvez le faire

git merge --strategy=ours ref-to-be-merged

git diff --binary ref-to-be-merged | git apply --reverse --index

git commit --amend

À ma connaissance, il n’y aura pas de conflit, vous n’aurez pas besoin de créer de branches supplémentaires et cela correspond à un commit de fusion normal.

Cela ne joue pas bien avec les sous-modules cependant.

6
thoutbeckers

Voir réponse largement citée de Junio ​​Hamano : si vous voulez supprimer le contenu validé, supprimez simplement les commits ou, en tout cas, gardez-le en dehors de l'historique principal. Pourquoi gêner tout le monde à l'avenir en lisant des messages de commits qui n'ont rien à offrir?

Mais parfois, il existe des exigences administratives, ou peut-être une autre raison. Pour les situations où vous devez vraiment enregistrer des commits qui ne contribuent en rien, vous voulez:

(edit: wow, est-ce que j'ai réussi à me tromper avant? Celui-ci fonctionne.)

git update-ref HEAD $(
        git commit-tree -m 'completely superseding with branchB content' \
                        -p HEAD -p branchB    branchB:
)
git reset --hard
5
jthill

Pourquoi ça n'existe pas?

Bien que je mentionne dans " commande git permettant de créer une branche comme une autre] " comment simuler git merge -s theirs, notez que Git 2.15 (Q4 2017) est désormais plus clair:

La documentation de '-X<option>' pour les fusions a été écrite de manière trompeuse pour suggérer que "-s theirs" existe, ce qui n'est pas le cas.

Voir commit c25d98b (25 sept. 2017) par Junio ​​C Hamano (gitster) .
(Fusionnée par Junio ​​C Hamano - gitster - dans commit 4da3e2 , 28 septembre 2017)

stratégies de fusion: éviter de laisser entendre que "-s theirs" existe

La description de l’option de fusion -Xours a une note entre parenthèses qui indique au lecteur qu’elle est très différente de -s ours, ce qui est correct, mais la description de -Xtheirs qui la suit ne dit que "ceci est le contraire de ours ", donnant une fausse impression que les lecteurs doivent également être avertis qu’il est très différent de -s theirs, qui n’existe même pas en réalité.

-Xtheirs est une option de stratégie appliquée à la stratégie récursive. Cela signifie que la stratégie récursive va toujours fusionner tout ce qu'elle peut et ne retombera que dans la logique "theirs" en cas de conflit.

Ce débat sur la pertinence ou non d'une stratégie de fusion theirs a été récemment rappelé dans le fil de discussion de septembre 2017 .
Il reconnaît anciens fils de discussion (2008)

En résumé, la discussion précédente peut être résumée comme suit: "nous ne voulons pas '-s theirs' car cela encourage le mauvais flux de travail".

Il mentionne l'alias:

mtheirs = !sh -c 'git merge -s ours --no-commit $1 && git read-tree -m -u $1' -

Yaroslav Halchenko tente à nouveau de plaider en faveur de cette stratégie, mais Junio ​​C. Hamano ajoute :

La raison pour laquelle les nôtres et les leurs ne sont pas symétriques, c'est parce que vous êtes vous et pas eux - le contrôle et la propriété de notre histoire et leur histoire ne sont pas symétriques.

Une fois que vous avez décidé que leur historique constituait la ligne principale, vous préféreriez traiter votre ligne de développement comme une branche secondaire et procéder à une fusion dans cette direction. En d'autres termes, le premier parent de la fusion résultante est un engagement de leur histoire et le second. parent est le dernier mauvais de votre histoire. Ainsi, vous utiliseriez "checkout their-history && merge -s ours your-history" pour que la première parenté reste sensible.

Et à ce stade, l'utilisation de "-s ours" n'est plus une solution de contournement faute de "-s theirs".
C'est une partie appropriée de la sémantique désirée, c'est-à-dire que du point de vue de la ligne d'histoire canonique survivante, vous voulez conserver ce qu'elle a fait, en annulant ce que l'autre ligne de l'histoire a fait .

3
VonC

Celui-ci utilise une commande de lecture git plumbing, mais permet un flux de travail global plus court.

git checkout <base-branch>

git merge --no-commit -s ours <their-branch>
git read-tree -u --reset <their-branch>
git commit

# Check your work!
git diff <their-branch>
2
Michael R

Cette réponse a été donnée par Paul Pladijs. Je viens de prendre ses commandes et fait un pseudo git pour plus de commodité.

Editez votre .gitconfig et ajoutez ce qui suit:

[alias]
    mergetheirs = "!git merge -s ours \"$1\" && git branch temp_THEIRS && git reset --hard \"$1\" && git reset --soft temp_THEIRS && git commit --amend && git branch -D temp_THEIRS"

Ensuite, vous pouvez "git merge -s leur s" en lançant:

git checkout B (optional, just making sure we're on branch B)
git mergetheirs A
0
Brain2000

L'équivalent (qui conserve l'ordre parent) à 'git merge -s leurs branchesB'

Avant la fusion: enter image description here

!!! Assurez-vous que vous êtes en état de propreté !!!

Faire la fusion:

git commit-tree -m "take theirs" -p HEAD -p branchB 'branchB^{tree}'
git reset --hard 36daf519952 # is the output of the prev command

Ce que nous avons fait ? Nous avons créé un nouveau commit dont les deux parents sont les nôtres et le leur et le contenu de ce commit est branchB - le leur

Après la fusion: enter image description here

Plus précisément:

git commit-tree -m "take theirs" -p HEAD -p 'SOURCE^{commit}' 'SOURCE^{tree}'
0
Boaz Nahum

Je pense que ce que vous voulez réellement, c'est:

git checkout -B mergeBranch branchB
git merge -s ours branchA
git checkout branchA
git merge mergeBranch
git branch -D mergeBranch

Cela semble maladroit, mais ça devrait marcher. La seule chose qui me déplaise le plus à propos de cette solution, c’est que l’histoire de Git sera confuse ... Mais au moins, l’histoire sera complètement conservée et vous n’aurez pas besoin de faire quelque chose de spécial pour les fichiers supprimés.

0
briemers

Cela va fusionner votre newBranch dans la baseBranch existante

git checkout <baseBranch> // this will checkout baseBranch
git merge -s ours <newBranch> // this will simple merge newBranch in baseBranch
git rm -rf . // this will remove all non references files from baseBranch (deleted in newBranch)
git checkout newBranch -- . //this will replace all conflicted files in baseBranch
0
Pawan Maheshwari