Existe-t-il une option git-merge --dry-run?

725

Je fusionne dans une branche distante qui peut avoir beaucoup de conflits. Comment puis-je savoir s'il y aura des conflits ou non?

Je ne vois rien comme un --dry-runsur git-merge.

Otto
la source
5
Étant donné que le branchement est bon marché avec Git, pourquoi ne pas extraire une copie et vous n'avez donc pas besoin de faire un essai à sec? Vous pouvez simplement jeter la copie par la suite.
Alexander Mills

Réponses:

812

Comme indiqué précédemment, passez le --no-commitdrapeau, mais pour éviter une validation rapide, passez également --no-ff, comme ceci:

$ git merge --no-commit --no-ff $BRANCH

Pour examiner les modifications par étapes:

$ git diff --cached

Et vous pouvez annuler la fusion, même s'il s'agit d'une fusion à avance rapide:

$ git merge --abort
mipadi
la source
51
C'est très bien, mais cela modifiera toujours votre copie de travail. Si votre dépôt est un serveur Web en direct, vous pouvez alors servir des fichiers avec des conflits.
dave1010
21
Vous ne pouvez pas vraiment faire une fusion sans affecter la copie de travail.
mipadi
55
C'est vrai, mais quelque chose comme git merge --only-if-there-wont-be-any-conflictsou git diff --show-conflicts <commit>serait vraiment pratique. Dommage que ce ne soit pas encore possible, ou manque-t-il quelque chose?
dave1010
344
@ dave1010 Vous ne devriez jamais gérer les fusions sur un serveur Web en direct !!! C'est à ça que sert votre box de développement! Corrigez la branche "prod", puis poussez-la vers le vrai serveur Web.
jpswain
52
Si vous travaillez sur un serveur live / production, vous ne voulez jamais rien faire d'autre git pull --ff-only!
ThiefMaster
237

Je viens de mettre en œuvre une méthode qui détecte automatiquement les conflits entre un référentiel et sa télécommande. Cette solution effectue la fusion en mémoire afin qu'elle ne touche pas l'index, ni l'arborescence de travail. Je pense que c'est la façon la plus sûre possible de résoudre ce problème. Voici comment ça fonctionne:

  1. Récupérez la télécommande dans votre référentiel. Par exemple: git fetch origin master
  2. Exécutez git merge-base: git merge-base FETCH_HEAD master
  3. Exécutez git merge-tree: git merge-tree mergebase master FETCH_HEAD( mergebase est l'identifiant hexadécimal imprimé par la base de fusion à l'étape précédente)

Supposons maintenant que vous souhaitiez fusionner le maître distant avec votre maître local, mais vous pouvez utiliser n'importe quelle branche. git merge-treeexécutera la fusion en mémoire et imprimera le résultat sur la sortie standard. Grep pour le motif <<ou >>. Ou vous pouvez imprimer la sortie dans un fichier et vérifier cela. Si vous trouvez une ligne commençant par «changé dans les deux», il y aura très probablement un conflit.

akostajti
la source
41
Cette réponse est bien sous-estimée, à mon humble avis, car c'est une solution propre sans toucher à la copie de travail ou à l'index.
sschuberth
23
BTW, les étapes 2 et 3 peuvent être fusionnées en une seule étape, en utilisant l'opérateur backtick de la console Linux, qui évalue sur place son contenu:git merge-tree `git merge-base FETCH_HEAD master` FETCH_HEAD master
jakub.g
15
Ajoutez à [alias] dans .gitconfig: dry = "! F () {git merge-tree` git merge-base $ 2 $ 1` $ 2 $ 1;}; f "#vérifiez comment se fera la fusion de dev dans master: git dry dev master
Noel
8
Ma nouvelle ligne GIT fav: tout git merge-tree `git merge-base clieop master` clieop master | grep -A3 "changed in both"simplement génial! +100
Rudie
4
En testant cela, j'ai trouvé que la fusion des drapeaux «changé dans les deux» fusionne lorsque les deux branches modifient le même fichier, même si elles n'entraînent pas de conflit de fusion. Pour identifier uniquement les conflits réels, j'ai trouvé nécessaire de grep pour le balisage de conflit qui commence comme ceci +<<<<<<< .ourgrep -q '^+<* \.our$'
Guy
55

Ma solution brute-force simple à ceci est:

  1. Créer une branche "pré-master" (à partir du master bien sûr)

  2. Fusionnez tout ce que vous voulez dans ce pré-master.
    Ensuite, vous pouvez voir comment la fusion s'est produite sans toucher au maître.

    • Fusionner le pré-master en master OR
    • Fusionner toutes les branches libérées par wannabe en master

Quoi qu'il en soit, je suivrais les conseils de @ orange80.

Enfers
la source
5
J'aime la solution @akostajti, mais c'est encore une autre option sous-estimée. En fait, je préfère être défensif et créer une nouvelle branche temporaire (bien sûr uniquement lorsque j'attends des conflits, sinon ce sera une surpuissance), et si quelque chose ne va pas, supprimez-le simplement.
jakub.g
1
ne sais pas si c'est une solution "sale" ou pas, mais ça fait vraiment l'affaire. Je l'aime! (Y)
sara
3
Cela devrait être la solution acceptée, imo. C'est rapide, facile, sûr, réversible, intuitif et tant qu'il n'y aura pas de changements non validés avant de commencer, cela n'aura aucun effet secondaire.
Bob Ray
3
Cette solution vous indique que vous ne comprenez pas comment fonctionne git. Les branches ne sont que des pointeurs et vous créez uniquement un pointeur redondant. Vous avez un mauvais pressentiment que vous pouvez en quelque sorte blesser la fusion de votre succursale, mais vous ne pouvez pas. Vous pouvez toujours le faire en git merge --abortcas de conflit, en git reset --hard HEAD~1cas de fusion ou git reset --hard origin/master. Créer une autre branche vous donne un sentiment de sécurité mais si vous apprenez comment fonctionne git, vous comprendrez que c'est une peur mal placée. Lorsque le souci est de ne pas modifier la copie de travail, cela n'offre aucune solution.
Thibault D.
@ thibault-d Réfléchissez à la complexité de la solution lorsque vous ne commencez pas avec une branche propre. git merge --no-commitn'interrompra pas une fusion si elle peut être transmise rapidement. git merge --abortne fonctionne pas s'il a été fusionné. Si vous voulez écrire cela sous forme de script, c'est gênant, car git mergeil ne répond pas avec des codes d'erreur suffisamment bons pour expliquer les différents types de conflits. Travailler avec une nouvelle branche empêche un script cassé de laisser votre dépôt dans un état qui nécessite une intervention manuelle. Bien sûr, vous ne pouvez rien perdre. Mais il est plus facile de construire autrement.
Erik Aronesty
47

Annuler une fusion avec git est si facile que vous ne devriez même pas vous soucier du run à sec:

$ git pull $REMOTE $BRANCH
# uh oh, that wasn't right
$ git reset --hard ORIG_HEAD
# all is right with the world

EDIT: Comme indiqué dans les commentaires ci-dessous, si vous avez des changements dans votre répertoire de travail ou votre zone de transit, vous voudrez probablement les ranger avant de faire ce qui précède (sinon ils disparaîtront après ce qui git resetprécède)

Brian Phillips
la source
7
Vérifier simplement si une fusion sera rapide (FF) est une question de vérifier la liste git branch --contains HEADou même plus directement, utilisez simplementgit merge --ff-only
Brian Phillips
7
git reset --hard est l'une des rares commandes de suppression d'informations sans suppression de git, elle doit donc être utilisée avec une extrême prudence. En tant que tel, -1
Kzqai
8
@Tchalvak il y a toujours reflog.
Kissaki
3
--dry-runne "vérifierait pas simplement si une fusion sera rapide". Cela retournerait la sortie exacte d'une fusion: fichiers, conflits, etc. Si will ff n'est pas vraiment intéressant, n'est-ce pas?
Rudie
3
que diriez-vous git stash; git reset --hard? @BrianPhillips
Code Whisperer
41

J'ai fait un alias pour faire ça et ça marche comme un charme, je fais ça:

 git config --global alias.mergetest '!f(){ git merge --no-commit --no-ff "$1"; git merge --abort; echo "Merge aborted"; };f '

Maintenant j'appelle

git mergetest <branchname>

Pour savoir s'il y a des conflits.

Okonomiyaki3000
la source
Brillant! Je garde ça.
qbert65536
28

Il suffit de comparer votre branche actuelle à la branche distante, cela vous dira ce qui va changer lorsque vous effectuez un pull / merge.

#see diff between current master and remote branch
git diff master origin/master
timh
la source
1
Idée intéressante. Comment pourrais-je regarder cette sortie et déterminer si la fusion va fonctionner ou non?
MatrixFrog
6
Cela ne vous dira pas si des conflits se produiront ... mais cela vous donnera une idée générale de ce qui se passera si vous faites un pull / merge.
timh
10
Cela ne vous indiquera que la différence entre les deux branches, il ne vous dira pas quel sera le résultat de la fusion. Il s'agit d'une distinction importante car la fusion entraînera dans certains cas automatiquement des modifications de différentes branches selon le moment où elles ont été validées. Donc, en substance, faire un diff peut vous faire penser que certaines de vos modifications seront annulées alors qu'en réalité, le processus de fusion prendra automatiquement les modifications les plus récentes par rapport aux anciennes. J'espère que cela a du sens.
Markquezada
3
Pour s'appuyer sur le commentaire de @ mirthlab, il y aura une différence significative entre diff et la fusion si quelqu'un a précédemment effectué une fusion avec la stratégie de fusion «la nôtre» (ou d'autres corrections de fusion manuelles); le diff vous montrera également les différences qui sont déjà comptées comme "fusionnées".
Tao
21

J'utilise la commande request-pull git pour ce faire. Il vous permet de voir tous les changements qui se produiraient lors de la fusion, mais sans rien faire sur vos référentiels locaux ou distants .

Par exemple, imaginez que vous souhaitez fusionner une branche nommée "feature-x" dans votre branche principale

git request-pull master origin feature-x

vous montrera un résumé de ce qui se passerait (sans rien faire):

The following changes since commit fc01dde318:
    Layout updates (2015-06-25 11:00:47 +0200)
are available in the git repository at:
    http://fakeurl.com/myrepo.git/ feature-x
for you to fetch changes up to 841d3b41ad:
----------------------------------------------------------------
john (2):
    Adding some layout
    Refactoring
ioserver.js            |   8 +++---
package.json           |   7 +++++-
server.js              |   4 +--
layout/ldkdsd.js       | 277 +++++++++++++++++++++++++++++++++++++
4 files changed, 289 insertions(+), 7 deletions(-)
create mode 100644 layout/ldkdsd.js

Si vous ajoutez le -pparamètre, vous obtiendrez également le texte complet du patch, exactement comme si vous faisiez un diff git sur chaque fichier modifié.

ArnaudR
la source
3
Vous pourriez rendre cela un peu plus clair en ajoutant quoi masteret originfaire dans les options de ligne de commande, et qu'en est-il si je suis par exemple sur un local branch1et que je veux faire request-pullsur une branche de fonctionnalité locale branch2? Ai-je encore besoin origin? Bien sûr, on peut toujours lire la documentation.
Ela782
Malheureusement, cette commande ne fonctionne que si Rev # 2 est un nom de branche, elle ne fonctionne pas pour les hachages: /
Jared Grubb
20

Je suis surpris que personne n'ait encore suggéré d'utiliser des correctifs.

Imaginons que vous souhaitiez tester une fusion depuis your_branchdans master(je suppose que vous avez mastervérifié):

$ git diff master your_branch > your_branch.patch
$ git apply --check your_branch.patch
$ rm your_branch.patch

Cela devrait faire l'affaire.

Si vous obtenez des erreurs comme

error: patch failed: test.txt:1
error: test.txt: patch does not apply

cela signifie que le patch n'a pas réussi et qu'une fusion entraînerait des conflits. Aucune sortie signifie que le patch est propre et vous pourrez facilement fusionner la branche


Notez que cela ne changera pas réellement votre arbre de travail (à part la création du fichier de patch bien sûr, mais vous pouvez le supprimer en toute sécurité par la suite). De la documentation git-apply:

--check
    Instead of applying the patch, see if the patch is applicable to the
    current working tree and/or the index file and detects errors. Turns
    off "apply".

Remarque à tous ceux qui sont plus intelligents / plus expérimentés avec git que moi: faites-le moi savoir si je me trompe ici et cette méthode montre un comportement différent d'une fusion régulière. Il semble étrange qu'au cours des 8 ans et plus que cette question ait existé, personne ne suggérerait cette solution apparemment évidente.

Christoph Böhmwalder
la source
Cette méthode est la réponse acceptée à cette question et il y a quelques mises en garde dans les commentaires tels que "git n'a pas pu utiliser la stratégie de fusion" récursive "" et "le fichier patch donne une erreur pour les nouveaux fichiers". Sinon, ça semble super.
neno
1
Une façon plus courte sans créer un fichier correctif temporaire: git diff master your_branch | git apply --check.
ks1322
9

Cela pourrait être intéressant: De la documentation:

Si vous avez essayé une fusion qui a entraîné des conflits complexes et que vous souhaitez recommencer, vous pouvez récupérer avec git merge --abort .

Mais vous pouvez aussi le faire de manière naïve (mais lente):

rm -Rf /tmp/repository
cp -r repository /tmp/
cd /tmp/repository
git merge ...
...if successful, do the real merge. :)

(Remarque: cela ne fonctionnera pas simplement en clonant vers / tmp, vous auriez besoin d'une copie, afin d'être sûr que les modifications non validées n'entreront pas en conflit).


la source
2
Si vous n'avez besoin que d'un marteau ... :) +1
kaiser
Nettoyer copie peut être obtenue avec cp -r repository/.git /tmp/repository/.git, cd /tmp/repository, git reset --hard, git add --all, git reset --hard(pour faire bonne mesure), git status(pour vérifier qu'il est propre).
2017 ADTC
8

Je sais que c'est une vieille question, mais c'est la première à apparaître sur une recherche Google.

Git a introduit une option --ff-only lors de la fusion.

De: http://git-scm.com/docs/git-merge


--ff-only

Refusez de fusionner et de quitter avec un état différent de zéro à moins que le HEAD actuel ne soit déjà à jour ou que la fusion puisse être résolue comme une avance rapide.

Cette opération tentera de fusionner et d'avancer rapidement, et si elle ne le peut pas, elle abandonne et vous indique que l'avance rapide n'a pas pu être effectuée, mais laisse votre branche de travail intacte. S'il peut avancer rapidement, il effectuera la fusion sur votre branche de travail. Cette option est également disponible sur git pull. Ainsi, vous pouvez effectuer les opérations suivantes:

git pull --ff-only origin branchA #See if you can pull down and merge branchA

git merge --ff-only branchA branchB #See if you can merge branchA into branchB
Jason McKindly
la source
1
Cela fera la fusion si cela peut être fait avec une avance rapide qui n'est pas ce que je voulais dans la question d'origine. Je pense que la réponse acceptée a l'autre moitié qui le corrige.
Otto
Vraiment cependant, les invites de fantaisie git évitent le besoin que j'ai pour ce genre de chose.
Otto
2
Ce n'est pas vraiment pareil. Quitter avec un état différent de zéro car la fusion ne peut pas être résolue car l'avance rapide ne signifie pas qu'il y a des conflits . Cela signifie simplement que l'histoire a divergé et qu'un commit de fusion est nécessaire.
2017 ADTC
7

J'utilise git log pour voir ce qui a changé sur une branche de fonctionnalité de la branche principale

git log does_this_branch..contain_this_branch_changes

par exemple - pour voir les validations dans une branche de fonctionnalité qui a / n'a pas été fusionnée avec master:

git log master..feature_branch
nelsonenzo
la source
3

Si vous voulez avancer rapidement de B vers A, alors vous devez vous assurer que le journal de git B..A ne vous montre rien, c'est-à-dire que A n'a rien que B n'a pas. Mais même si B..A a quelque chose, vous pourrez peut-être fusionner sans conflits, donc ce qui précède montre deux choses: qu'il y aura une avance rapide, et donc vous n'obtiendrez pas de conflit.

Erik Kaplun
la source
2

Ma solution est de fusionner en arrière.

Au lieu de fusionner votre branche dans la branche "cible" distante, fusionnez cette branche dans la vôtre.

git checkout my-branch
git merge origin/target-branch

Vous verrez s'il y a des conflits et pouvez planifier comment les résoudre.

Après cela, vous pouvez soit abandonner la fusion via git merge --abort, ou (s'il n'y a pas eu de conflits et de fusion) revenir à la validation précédente viagit reset --hard HEAD~1

Ubeogesh
la source
-2

Faites une copie temporaire de votre copie de travail, puis fusionnez-la et différez les deux.

vanboom
la source