1226 votes

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

Utilisation de gitk log Je n'ai pas pu faire la différence entre les deux. Comment puis-je observer la différence (avec une commande git ou un outil quelconque) ?

4 votes

1 votes

2 votes

1331voto

Kevin Ballard Points 88866

Le site --no-ff le drapeau empêche git merge d'exécuter un "fast-forward" s'il détecte que votre actuel HEAD est un ancêtre du commit que vous essayez de fusionner. Un fast-forward est le cas où, au lieu de construire un commit de fusion, git déplace simplement votre pointeur de branche pour pointer sur le commit entrant. Cela se produit généralement lors de l'exécution d'un git pull sans aucune modification locale.

Cependant, il arrive que vous vouliez empêcher ce comportement de se produire, typiquement 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 en soit ainsi lors de la lecture de l'historique). Pour ce faire, vous pouvez passer l'option --no-ff et git merge sera toujours construire une fusion au lieu de faire une avance rapide.

De même, si vous voulez exécuter un git pull ou utiliser git merge afin d'effectuer une avance rapide explicite, et que vous souhaitez vous désister si l'avance rapide ne peut pas être effectuée, vous pouvez alors utiliser la fonction --ff-only drapeau. De cette façon, vous pouvez régulièrement faire quelque chose comme git pull --ff-only sans réfléchir, et ensuite, s'il y a des erreurs, vous pouvez revenir en arrière et décider si vous voulez fusionner ou rebaser.

106 votes

Pour répondre plus directement à la question de l'OP : ils ne sont pas toujours différents, mais s'ils le sont, c'est clair d'après les données de l'OP. gitk ou git log --graph que la fusion rapide n'a pas créé de commit de fusion, alors que la fusion non-rapide l'a fait.

18 votes

Il serait bien de développer la raison d'éviter ff : l'auteur a mentionné "la topologie spécifique des branches", ce qui signifie que dans le cas --no-ff un commit de fusion supplémentaire sert de marqueur de la fusion. Le pour est un marqueur de fusion explicite avec les noms de l'auteur et de la fusion. Le contre est une histoire non linéaire qui ressemble à un ensemble de voies ferrées convergentes. Une possibilité psychologique L'effet secondaire de la fusion est la perte d'intérêt des contributeurs en raison d'un processus d'examen plus long : blog.spreedly.com/2014/06/24/

8 votes

Serait-il juste de dire que --no-ff d'une fonctionnalité à développer ou de développer à maîtriser est similaire à la fusion d'une demande de retrait ?

1251voto

Chris K Points 3940

Réponse graphique à cette question

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

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

Jusqu'à ce que je voie ça, j'étais complètement perdu avec git. Utilisation de --no-ff permet à quelqu'un qui revoit l'histoire de clairement voir la branche que vous avez vérifiée pour 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 agréablement la première en se concentrant davantage sur les personnes moins familiarisées avec git.


Informations de base pour les novices comme moi

Si vous êtes comme moi, et pas un gourou de Git, ma réponse ici décrit la gestion de la suppression des fichiers du suivi de git sans les supprimer du système de fichiers local, ce qui semble peu documenté mais se produit souvent. Une autre situation pour les débutants est obtention du code actuel qui m'échappe encore.


Exemple de flux de travail

J'ai mis à jour un paquet sur mon site Web et j'ai dû retourner à mes notes pour voir mon flux de travail ; j'ai pensé qu'il était utile d'ajouter un exemple à cette réponse.

Mon flux de travail des 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

En dessous : l'usage réel, y compris les explications.
Note : la sortie ci-dessous est un extrait ; 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

Notez 3 choses d'en haut :
1) Dans la sortie, vous pouvez voir les modifications apportées par la mise à niveau du paquet ECC, y compris l'ajout de nouveaux fichiers.
2) Remarquez également qu'il y a deux fichiers (pas dans le fichier /ecc dossier) que j'ai supprimé indépendamment de ce changement. Au lieu de confondre ces suppressions de fichiers avec ecc je vais faire une autre cleanup plus tard pour refléter la suppression de ces fichiers.
3) Je n'ai pas suivi mon flux de travail ! J'ai oublié git pendant que j'essayais de faire fonctionner ecc à nouveau.

En dessous : plutôt que de faire le tout-inclus git commit -am "updated ecc package" Je le ferais normalement, je voulais seulement ajouter les fichiers dans le /ecc dossier. Ces fichiers supprimés ne faisaient pas spécifiquement partie de mon git add mais comme ils étaient déjà suivis dans git, je dois les supprimer du commit 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 automatiser ce qui précède.

Après avoir utilisé ce processus plus de 10 fois par jour, j'ai pris l'habitude d'écrire des scripts de traitement par lots pour exécuter les commandes, et j'ai donc créé un script presque parfait. git_update.sh <branch> <"commit message"> script pour effectuer les étapes ci-dessus. Voici la source du Gist pour ce script.

Au lieu de git commit -am Je sélectionne les fichiers à partir de la liste "modifiée" produite via git status puis les coller dans ce script. Cela s'est produit parce que j'ai fait des dizaines d'éditions mais je voulais des noms de branches variés pour aider à regrouper les changements.

14 votes

Pouvez-vous toujours supprimer une branche en toute sécurité après avoir effectué une fusion avec le fichier --no-ff option ?

22 votes

@DesignerGuy oui, vous pouvez supprimer l'ancienne branche en toute sécurité. Pensez aux branches comme des pointeurs vers un commit spécifique.

3 votes

J'ai trouvé ce texte de la page liée utile : sans --no-ff "il est impossible de voir à partir de l'historique de Git lesquels des objets commit ensemble ont implémenté une fonctionnalité - vous devriez lire manuellement tous les messages de log".

499voto

premraj Points 120

Fusionner les stratégies

Fusion explicite (c'est-à-dire sans avance rapide) : Crée un nouveau commit de fusion. (C'est ce que vous obtiendrez si vous utilisez --no-ff .)

enter image description here

Fusion en avance rapide : Avancer rapidement, sans créer un nouveau commit :

enter image description here

Rebasement : Établir un nouveau niveau de base :

enter image description here

Courge : Écraser ou presser (quelque chose) avec force pour qu'il devienne plat :

enter image description here

249voto

Daniel Smith Points 2746

Le site --no-ff L'option garantit qu'une fusion en avance rapide ne se produira pas, et que un nouvel objet commit sera toujours créé . Cela peut être souhaitable si vous voulez que git maintienne un historique des branches de fonctionnalités.              git merge --no-ff vs git merge Dans l'image ci-dessus, le côté gauche est un exemple de l'historique 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 n'indiquait qu'un seul parent pour le commit de fusion. Les commits de fusion ont plusieurs commits parents que git utilise pour maintenir un historique de la "feature branch" et de la branche d'origine. Les liens parentaux multiples sont surlignés en vert.

3 votes

Qu'indique la flèche verte par rapport à la flèche noire ?

12 votes

La flèche verte indique un lien entre un commit et un parent lorsque le commit a plus d'un parent. Les commits normaux (en noir) n'ont qu'un seul parent.

10 votes

@DanielSmith Comment dessinez-vous ce graphique élégant ?

42voto

Parris Varney Points 4249

Il s'agit d'une vieille question, qui est mentionnée de manière quelque peu subtile dans les autres messages, mais l'explication qui m'a fait cliquer est que les fusions non rapides nécessiteront une validation séparée. .

0 votes

Pourriez-vous revoir le flux de travail dans ma réponse ci-dessus : cela signifie-t-il que j'ai besoin de commits supplémentaires en plus de ce que j'ai maintenant ? Merci.

3 votes

@ChrisK git merge --no-ff ecc vous aurez simplement un commit de fusion supplémentaire dans le fichier git log pour la branche master. Cela n'est techniquement pas nécessaire dans le cas où master pointe vers un ancêtre direct du commit sur lequel ecc se trouve mais en spécifiant l'option --no-ff vous forcez la création de ce commit de fusion. Il aura le titre : Merge branch 'ecc'

0 votes

Excellent résumé ! :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X