Pourquoi git fast-forward fusionne-t-il par défaut?

venant de mercurial, j'utilise des branches pour organiser les traits. Naturellement, je veux voir ce flux de travail dans mon histoire.

j'ai commencé mon nouveau projet en utilisant git et j'ai terminé ma première fonctionnalité. En fusionnant la fonctionnalité, j'ai réalisé que git utilise fast-forward, c'est-à-dire qu'il applique mes modifications directement à la branche principale si possible et oublie ma branche.

Donc, penser à l'avenir: je suis le seul à travailler sur ce projet. Si j'utilise l'approche par défaut de git (fast-forward merging), mon histoire aboutirait à une branche principale géante. Personne ne sait que j'ai utilisé une branche séparée pour chaque fonctionnalité, parce qu'à la fin j'aurai seulement cette branche principale géante. Ne pas que l'air manque de professionnalisme?

par ce raisonnement, Je ne veux pas de fusion accélérée et je ne vois pas pourquoi c'est la valeur par défaut. Ce qui est bon à ce sujet?

612
demandé sur Nick Volynkin 2010-05-17 19:26:16

2 réponses

d'avance Rapide, de la fusion de sens que de courte durée branches, mais dans un plus complexe de l'histoire , non d'avance rapide, de la fusion peut rendre l'histoire plus facile à comprendre, et de le rendre plus facile pour rétablir un groupe de commits.

Avertissement : Non, l'avance rapide a des effets secondaires potentiels ainsi. S'il vous plaît revoir https://sandofsky.com/blog/git-workflow.html , éviter le "non-ff" avec son "point de contrôle s'engage" qui cassent traversent, ou de blâme, et examiner soigneusement la question de savoir s'il devrait être par défaut de votre approche de master .

alt text

(de nvie.com , Vincent Driessen , post un modèle de branchement réussi ")

incorporant un élément fini sur le développement

les fonctionnalités terminées peuvent être fusionnées dans la branche de développement pour les ajouter à la prochaine version:

$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff myfeature
Updating ea1b82a..05e9557
(Summary of changes)
$ git branch -d myfeature
Deleted branch myfeature (was 05e9557).
$ git push origin develop

le drapeau --no-ff fait que la fusion crée toujours un nouvel objet commit, même si la fusion peut être effectuée avec un fast-forward. Cela évite de perdre des informations sur l'existence historique d'une branche de fonctionnalité et regroupe tous les commits qui, ensemble, ajout de la fonctionnalité.

Jakub Narębski aussi mentions the config merge.ff :

par défaut, Git ne crée pas de commit de fusion supplémentaire lors de la fusion d'une commit qui est un descendant de la commit actuelle. Au lieu de cela, la pointe de la branche courante est expédiée rapidement.

Lorsqu'elle est définie à false , cette variable indique à Git de créer un commit de fusion supplémentaire dans un tel cas (équivalent à donner l'option --no-ff de la ligne de commande).

Lorsqu'elle est définie à ' only ', seules de telles fusions rapides sont autorisées (ce qui équivaut à donner l'option --ff-only de la ligne de commande).


Le fast-forward est la valeur par défaut parce que:

  • les branches éphémères sont très faciles à créer et à utiliser en Git
  • les branches éphémères isolent souvent plusieurs commit qui peuvent être réorganisées librement au sein de cette branche
  • ces commits font en fait partie de la branche principale: une fois réorganisée, la branche principale est expédiée rapidement pour les inclure.

mais si vous prévoyez un workflow itératif sur un sujet / branche de fonctionnalité (i.e., je fusionne, alors je de retour à cette branche, et ajouter plus valide), puis il est utile d'inclure uniquement l'opération de fusion dans la branche principale, plutôt que tous les intermédiaires commits de la branche.

dans ce cas, vous pouvez configurer ce type de fichier de configuration :

[branch "master"]
# This is the list of cmdline options that should be added to git-merge 
# when I merge commits into the master branch.

# The option --no-commit instructs git not to commit the merge
# by default. This allows me to do some final adjustment to the commit log
# message before it gets commited. I often use this to add extra info to
# the merge message or rewrite my local branch names in the commit message
# to branch names that are more understandable to the casual reader of the git log.

# Option --no-ff instructs git to always record a merge commit, even if
# the branch being merged into can be fast-forwarded. This is often the
# case when you create a short-lived topic branch which tracks master, do
# some changes on the topic branch and then merge the changes into the
# master which remained unchanged while you were doing your work on the
# topic branch. In this case the master branch can be fast-forwarded (that
# is the tip of the master branch can be updated to point to the tip of
# the topic branch) and this is what git does by default. With --no-ff
# option set, git creates a real merge commit which records the fact that
# another branch was merged. I find this easier to understand and read in
# the log.

mergeoptions = --no-commit --no-ff

L'OP ajoute dans les commentaires:

je vois un certain sens, en avance rapide pour [de courte durée] branches, mais en faire l'action par défaut signifie que git vous suppose... ils ont souvent des branches [éphémères]. Est-elle raisonnable?

Jefromi answers:

je pense que la durée de vie des branches varie grandement d'un utilisateur à l'autre. Chez les utilisateurs expérimentés, cependant, il y a probablement une tendance à avoir des branches beaucoup plus éphémères.

pour moi, une branche éphémère est une branche que je créer afin de rendre une certaine opération plus facile (rebasement, probable, ou correction rapide et test), puis supprimer immédiatement une fois que j'ai terminé.

Cela signifie qu'il est probable devrait être absorbé dans la branche du sujet qu'il a bifurqué de , et la branche du sujet sera fusionnée en une seule branche. Personne n'a besoin de savoir ce que j'ai fait en interne pour créer la série de commits implémentant cette fonctionnalité.

plus généralement, j'ajoute:

cela dépend vraiment de votre flux de développement :

  • si elle est linéaire, une branche a du sens.
  • si vous avez besoin d'isoler des caractéristiques et de travailler dessus pendant une longue période de temps et les fusionner à plusieurs reprises, plusieurs branches font du sens.

Voir " Quand devrais - vous branche? "

one branch per repository (même si vous pouvez créer anonymous heads, bookmarks and even named branches )

Voir "Git et Mercurial - Comparer et de Contraste" .

Mercurial, par défaut, utilise anonyme léger codelines, qui, dans sa terminologie sont appelés "têtes".

Git utilise des branches nommées légères, avec des mappages injectifs pour mapper les noms des branches dans le dépôt distant vers les noms des branches de suivi à distance.

Git "force" vous pour nommer les branches( bien, à l'exception d'une seule branche sans nom, qui est une situation appelée " tête détachée "), mais je pense cela fonctionne mieux avec les flux de travail lourds par branche tels que le flux de travail par branche thématique, c'est-à-dire plusieurs branches dans un même paradigme de dépôt.

688
répondu VonC 2017-05-23 12:10:34

Permettez-moi de développer un peu sur un VonC 's réponse très complète :


tout D'abord, si je m'en souviens bien, le fait que Git par défaut ne crée pas merge commits dans le cas fast-forward vient de considérer une seule branche" dépôts égaux", où traction mutuelle est utilisé pour synchroniser ces deux dépôts (un flux de travail que vous pouvez trouver comme premier exemple dans la plupart de la documentation de l'utilisateur, y compris "le manuel de L'utilisateur de Git" et "le contrôle de Version par exemple"). Dans ce cas, vous n'utilisez pas pull pour fusionner branche entièrement réalisée, vous l'utilisez pour suivre avec d'autres travaux. Vous ne voulez pas avoir un fait éphémère et sans importance quand vous faites une synchronisation sauvegardée et stockée dans un dépôt, sauvegardée pour le futur.

noter que l'utilité des branches caractéristiques et d'avoir plusieurs branches dans un seul le dépôt est venu seulement plus tard, avec une utilisation plus répandue de VCS avec une bonne prise en charge de la fusion, et avec l'essai de divers flux de travail basés sur la fusion. C'est la raison pour laquelle, par exemple, Mercurial ne supportait à l'origine qu'une seule branche par dépôt (plus des astuces anonymes pour le suivi des branches distantes), comme le montrent les anciennes révisions de "Mercurial: The Definitive Guide".


Second, lorsque l'on suit meilleures pratiques de l'utilisation branches caractéristiques , c'est-à-dire que les branches de fonctionnalité doivent toutes commencer à partir de la version stable (généralement à partir de la dernière version), pour être en mesure de choisir et de sélectionner les fonctionnalités à inclure en sélectionnant les branches de fonctionnalité à fusionner, vous n'êtes généralement pas dans la situation fast-forward ... ce qui rend cette question discutable. Vous devez vous soucier de créer une vraie Fusion et non pas une fusion rapide lors de la fusion d'une toute première branche (en supposant que vous ne mettez pas les changements de single-commit directement sur "master"); toutes les autres fusions ultérieures se trouvent bien entendu dans une situation non accélérée.

HTH

40
répondu Jakub Narębski 2017-08-25 16:19:00