Quelle est la différence entre "git merge" et " git merge --no-ff`?

en utilisant gitk log , Je n'ai pas pu distinguer une différence entre les deux. Comment puis-je observer la différence (avec une commande git ou un autre outil)?

658
demandé sur abc 2012-01-30 22:45:41

5 réponses

le drapeau --no-ff empêche git merge d'exécuter un "fast-forward" s'il détecte que votre courant HEAD est un ancêtre de la propagation que vous essayez de fusionner. Un fast-forward est quand, au lieu de construire une commit de fusion, git déplace juste votre pointeur de branche pour pointer vers la commit entrante. Cela se produit souvent quand on fait un git pull sans aucun changement local.

cependant, de temps en temps vous voulez empêcher ce comportement de se produire, généralement parce que vous voulez maintenir une topologie de branche spécifique (par exemple, vous fusionnez dans une branche de sujet et vous voulez vous assurer qu'il ressemble de cette façon lors de la lecture de l'histoire). Pour ce faire, vous pouvez passer le drapeau --no-ff et git merge will toujours construire une fusion au lieu de fast-forwarding.

de Même, si vous voulez exécuter un git pull ou utiliser git merge afin explicitement avance rapide, et vous voulez caution si elle ne peut pas accélérer, alors vous pouvez utiliser le drapeau --ff-only . De cette façon, vous pouvez régulièrement faire quelque chose comme git pull --ff-only sans penser, et puis si elle se trompe, vous pouvez revenir en arrière et décider si vous voulez fusionner ou rebase.

760
répondu Kevin Ballard 2012-01-30 18:51:29

réponse graphique à cette question

Ici est un site avec une explication claire et l'illustration graphique de l'utilisation de git merge --no-ff :

difference between git merge --no-ff and git merge

Jusqu'à ce que je vois ça, j'étais complètement perdu avec git. L'utilisation de -- Non-ff permet à quelqu'un qui passe en revue l'histoire de voir la branche que vous avez cochée à travailler. (ce lien pointe vers l'outil de visualisation "réseau" de github) et voici une autre grande référence avec des illustrations. Cette référence complète bien la première en mettant davantage l'accent sur les personnes moins familiarisées avec le git.


infos de Base pour les newbs comme moi

si vous êtes comme moi, et non pas un gourou, ma réponse ici décrit la manipulation de la suppression de fichiers du tracking de git sans les supprimer du système de fichiers local, ce qui semble mal documenté mais se produit souvent. Une autre situation newb est obtenir le code actuel , qui parvient toujours à m'échapper.


Exemple De Flux De Travail

j'ai mis à jour un paquet sur mon site et a dû revenir à mes notes pour voir mon travail; j'ai pensé utile d'ajouter un exemple de cette réponse.

mon workflow de commandes git:

git checkout -b contact-form
(do your work on "contact-form")
git status
git commit -am  "updated form in contact module"
git checkout master
git merge --no-ff contact-form
git branch -d contact-form
git push origin master

ci-dessous: usage actuel, y compris les explications.

Note: la sortie ci-dessous est ébréchée; git est assez verbeux.

$ git status
# On branch master
# Changed but not updated:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   ecc/Desktop.php
#       modified:   ecc/Mobile.php
#       deleted:    ecc/ecc-config.php
#       modified:   ecc/readme.txt
#       modified:   ecc/test.php
#       deleted:    passthru-adapter.igs
#       deleted:    shop/mickey/index.php
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       ecc/upgrade.php
#       ecc/webgility-config.php
#       ecc/webgility-config.php.bak
#       ecc/webgility-magento.php

noter 3 choses d'en haut:

1) dans la sortie, vous pouvez voir les changements de la mise à niveau du paquet ECC, y compris l'ajout de nouveaux fichiers.

2) notez aussi qu'il y a deux fichiers (pas dans le dossier /ecc ) que j'ai supprimés indépendamment de ce changement. Au lieu de confondre ces suppressions de fichiers avec ecc , je ferai une branche différente cleanup plus tard pour refléter la suppression de ces fichiers.

3) je n'ai pas suivi mon travail! J'ai oublié git pendant que j'essayais de faire fonctionner l'ecc.

ci-dessous: plutôt que de faire le tout compris git commit -am "updated ecc package" Je normalement je voulais juste ajouter les fichiers dans le dossier /ecc . Ces fichiers supprimés ne faisaient pas spécifiquement partie de mon git add , mais parce qu'ils étaient déjà traqués dans git, je dois les supprimer de la propagation de cette branche:

$ git checkout -b ecc
$ git add ecc/*
$ git reset HEAD passthru-adapter.igs
$ git reset HEAD shop/mickey/index.php
Unstaged changes after reset:
M       passthru-adapter.igs
M       shop/mickey/index.php

$ git commit -m "Webgility ecc desktop connector files; integrates with Quickbooks"

$ git checkout master
D       passthru-adapter.igs
D       shop/mickey/index.php
Switched to branch 'master'
$ git merge --no-ff ecc
$ git branch -d ecc
Deleted branch ecc (was 98269a2).
$ git push origin master
Counting objects: 22, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (14/14), done.
Writing objects: 100% (14/14), 59.00 KiB, done.
Total 14 (delta 10), reused 0 (delta 0)
To git@github.com:me/mywebsite.git
   8a0d9ec..333eff5  master -> master




Script pour l'automatisation de ce qui précède

ayant utilisé ce processus plus de 10 fois dans la journée, j'ai pris à l'écriture de lot scripts pour exécuter les commandes, donc j'ai fait un script presque approprié git_update.sh <branch> <"commit message"> pour faire les étapes ci-dessus. Voici la source Gist pour ce script.

au lieu de git commit -am je sélectionne des fichiers de la liste" modifiée "produite par git status et puis je les colle dans ce script. Cela s'est produit parce que j'ai fait des douzaines de modifications, mais je voulais des noms de branches variés pour aider à grouper les changements.

751
répondu Chris K 2017-05-23 12:26:34

l'option --no-ff garantit qu'une fusion rapide ne se produira pas, et que un nouvel objet commit sera toujours créé . Cela peut être souhaitable si vous voulez git pour conserver un historique de branches.              git merge --no-ff vs git merge Dans l'image ci-dessus, le côté gauche est un exemple de l'histoire de git après avoir utilisé git merge --no-ff et le côté droit est un exemple d'utilisation de git merge où une fusion ff était possible.

EDIT : une version précédente de cette image indiquait seulement un parent unique pour la propagation de la fusion. Fusion s'engage plusieurs parent s'engage à qui git utilise pour conserver un historique de la "branche" et de l'origine de la branche. Les liens parents multiples sont surlignés en vert.

155
répondu Daniel Smith 2014-06-30 00:41:32

C'est une vieille question, et cela est quelque peu subtilement mentionné dans les autres Billets, mais l'explication qui a fait ce clic pour moi est que Non fast forward merges nécessitera une propagation séparée .

33
répondu Parris Varney 2014-04-02 19:56:06

"Stratégies De Fusion

  • Explicite, non d'avance rapide, de fusion
  • Implicite via rebase ou avancer rapidement dans la fusion
  • Squash sur la fusion

enter image description here

enter image description here

enter image description here

enter image description here

9
répondu Premraj 2018-09-04 02:21:15