Pourquoi les validations git ne contiennent-elles pas le nom de la branche sur laquelle elles ont été créées?


20

Lorsque je travaille avec git dans une équipe utilisant des branches de fonctionnalités, j'ai souvent du mal à comprendre la structure des branches dans l'histoire.

Exemple:

Supposons qu'il y ait une fonctionnalité / préparation de branche de fonctionnalité , et la correction de bogues se poursuit sur le maître en parallèle à la branche de fonctionnalité.

L'histoire pourrait ressembler à ceci:

*     merge feature/make-coffee
|\
| *   small bugfix
| |
* |    fix bug #1234
| |
| *    add milk and sugar
| |
* |    improve comments
| |
* |    fix bug #9434
| |
| *    make coffe (without milk or sugar)
| |
* |    improve comments
|/
*

Problème

À première vue, je trouve difficile de dire de quel côté se trouve la branche de fonctionnalité. J'ai généralement besoin de parcourir plusieurs commentaires des deux côtés pour avoir une idée de qui est lequel. Cela devient plus compliqué s'il y a plusieurs branches d'entités en parallèle (en particulier si elles concernent des entités étroitement liées), ou s'il y a fusion dans les deux sens entre la branche d'entités et le maître.

En revanche, dans Subversion, c'est beaucoup plus facile car le nom de la branche fait partie de l'historique - je peux donc dire tout de suite qu'un commit a été initialement fait sur "feature / make-coffee".

Git pourrait faciliter cela en incluant le nom de la branche actuelle dans les métadonnées de validation lors de la création d'une validation (avec l'auteur, la date, etc.). Cependant, git ne fait pas cela.

Y a-t-il une raison fondamentale pour laquelle cela n'est pas fait? Ou est-ce juste que personne ne voulait la fonctionnalité? Si c'est le dernier, existe-t-il d'autres façons de comprendre le but des branches historiques sans voir le nom?


1
Question connexe: recherche de la branche d'où provient un commit . Il s'agit de savoir comment trouver ces informations malgré le fait que git ne les enregistre pas explicitement.
sleske

1
Note à moi: Il est intéressant, dans Mercurial la commettras ne contient le nom de la branche. Il semble donc que les développeurs Mercurial aient pris une décision de conception différente de celle des développeurs Git. Voir par exemple felipec.wordpress.com/2012/05/26/… pour plus de détails.
sleske

Réponses:


14

Probablement parce que les noms de branche n'ont de sens que dans un seul référentiel. Si je fais partie de l' make-coffeeéquipe et que je soumets toutes mes modifications via un portier, ma masterbranche peut être attirée sur la make-coffee-guibranche du portier , qu'il fusionnera avec sa make-coffee-backendbranche, avant de rebaser sur une make-coffeebranche qui sera fusionnée dans la masterbranche centrale .

Même au sein d'un même référentiel, les noms de branche peuvent changer et changent à mesure que votre flux de travail évolue. masterpourrait changer plus tard pour être appelé development, par exemple.

Comme CodeGnome l'a fait allusion, git a une philosophie de conception forte de ne pas incorporer quelque chose dans les données s'il n'est pas nécessaire. Les utilisateurs sont censés utiliser les options git loget git diffproduire les données à leur convenance après coup. Je recommande d'en essayer jusqu'à ce que vous trouviez un format qui vous convient mieux. git log --first-parent, par exemple, n'affichera pas les validations d'une branche en cours de fusion.


2
Il convient de noter cependant que le premier parent est généralement le mauvais. Parce qu'habituellement, on tire simplement le maître dans tout ce sur quoi il travaille et le pousse à faire de son travail le premier parent et le deuxième maître.
Jan Hudec

1
@JanHudec: En fait, cela dépend :-). Si la personne qui fait le travail le fusionne, alors oui. Si la fusion se produit plus tard, peut-être après une révision, il est plus probable que le réviseur ait extrait le fichier maître et fusionne la branche de fonctionnalité dans le fichier maître, la teste et envoie.
sleske

5

Suivez l'historique des succursales avec --no-ff

Dans Git, un commit a des ancêtres, mais une "branche" n'est vraiment que la tête actuelle d'une ligne de développement. En d'autres termes, une validation est un instantané de l'arborescence de travail à un moment donné et peut appartenir à n'importe quel nombre de branches à la fois. Cela fait partie de ce qui rend la branche Git si légère par rapport aux autres DVCS.

Les validations Git ne contiennent pas les informations de branche car elles ne sont pas nécessaires pour l'historique Git. Cependant, les fusions qui ne sont pas rapides peuvent certainement contenir des informations supplémentaires sur la branche qui a été fusionnée. Vous pouvez vous assurer que votre historique contient ces informations en passant toujours le --no-ffdrapeau à vos fusions. git-merge (1) dit:

   --no-ff
       Create a merge commit even when the merge resolves as a
       fast-forward. This is the default behaviour when merging an
       annotated (and possibly signed) tag.

Cela créera généralement un message de fusion similaire à Merge branch 'foo', donc vous pouvez généralement trouver des informations sur les "branches ancêtres" avec une ligne similaire à la suivante:

$ git log --regexp-ignore-case --grep 'merge branch'

Merci, mais cela (surtout) ne répond pas à ma question. Je ne demande pas quelles sont les autres façons de trouver la branche d'origine, mais pourquoi les informations ne sont pas incluses en tant que métadonnées régulières - c'est plus une question de conception.
sleske

1
@sleske Je pense que ma réponse était sensible: Git ne le suit pas parce que l'historique de Git n'en a pas besoin; Je ne pense pas que cela devienne plus fondamental que cela. Il faudrait regarder la source pour plus de détails, mais l'historique est effectivement calculé à l'envers à partir de la pointe de la branche actuelle. Vous pouvez toujours comparer cela avec d'autres DVCS qui traitent les branches comme des objets de première classe et voyez si vous aimez mieux cette philosophie de conception. YMMV.
CodeGnome

1
Ce dernier devrait être git log --merges.
Dan

3

La réponse la plus simple est que les noms des branches sont éphémères. Et si vous deviez, par exemple, renommer une branche ( git branch -m <oldname> <newname>)? Qu'arriverait-il à tous les commits contre cette branche? Ou que se passe-t-il si deux personnes ont des succursales portant le même nom sur différents référentiels locaux?

La seule chose qui a un sens dans git est la somme de contrôle du commit lui-même. Il s'agit de l'unité de base du suivi.

L'information est là, vous ne la demandez tout simplement pas, et ce n'est pas exactement là.

Git stocke la somme de contrôle du chef de chaque branche dans .git/refs/heads . Par exemple:

... /. git / refs / heads $ ls test 
-rw-rw-r-- 1 michealt michealt 41 sept 30 30 11:50 test
... /. git / refs / heads $ cat test 
87111111111111111111111111111111111111d4

(oui, je fais trembler mes sommes de contrôle git, ce n'est pas spécial, mais ce sont des référentiels privés que je regarde au moment où il n'y a pas besoin de fuite accidentelle).

En regardant cela et en retraçant chaque commit qui a ceci comme parent, ou le parent des parents ou le parent des parents ... vous pouvez découvrir dans quelles branches se trouve un commit donné. C'est juste un gros graphique à rendre.

Stocker où spécifiquement le nom d'une branche (qui peut changer comme mentionné ci-dessus) un commit est dans le commit lui-même est une surcharge supplémentaire sur le commit qui ne l'aide pas. Stockez le (s) parent (s) du commit et son bien.

Vous pouvez voir les branches en exécutant la commande git log avec l'indicateur approprié.

git log --branches --source --pretty = oneline --graph
git log --all --source --pretty = oneline --graph

Il existe de nombreuses façons de choisir ce que vous voulez pour cela - consultez la documentation du journal git - le-all section et les quelques options qui suivent.

* 8711111111111111111111111111111111111111d4 test Fusionner la branche 'test1' dans test
| \  
| * 42111111111111111111111111111111111111e8 mise à jour test1: ajouter des éléments
* | dd1111111111111111111111111111111111111159 test Fusionner la branche 'test3' dans test
| \ \  

Ce «test», «test1» et «test2» sont les branches sur lesquelles ils se sont engagés.

Notez que la documentation du journal git est énorme et qu'il est tout à fait possible d'en tirer presque tout ce que vous voulez.


3

Pourquoi les validations git ne contiennent pas le nom de la branche sur laquelle elles ont été créées?

Juste une décision de conception. Si vous avez besoin de ces informations, vous pouvez ajouter un hook prepare-commit-msg ou commit-msg pour l'imposer sur un seul référentiel.

Après la catastrophe de BitKeeper, Linus Torvalds a développé git pour correspondre au processus de développement du noyau Linux. Là, jusqu'à ce qu'un patch soit accepté, il est révisé, édité, poli plusieurs fois (tout au long de Mail), signé (= éditer un commit), choisi par les cerises, errant vers les branches du lieutenant peut-être souvent rebasé, plus de modifications, cerise -picks et ainsi de suite jusqu'à ce qu'ils soient finalement fusionnés en amont par Linus.

Dans un tel flux de travail, il peut n'y avoir aucune origine spécifique d'une validation, et souvent une validation est juste créée dans une branche de débogage temporaire dans un référentiel aléatoire privé sans importance avec des noms de branche drôles, car git est distribué.

Peut-être que cette décision de conception est arrivée par hasard, mais elle correspond exactement au processus de développement du noyau Linux.


2

Parce que dans Git, les commits comme "faire du café" sont considérés comme faisant partie des deux branches lorsque la branche de fonction est fusionnée. Il y a même une commande pour vérifier que:

% git branch --contains @
  feature/make-coffee
  master

De plus, les branches sont bon marché, locales et éthérées; ils peuvent être facilement ajoutés, supprimés, renommés, poussés et supprimés du serveur.

Git suit le principe que tout peut être fait, c'est pourquoi vous pouvez facilement supprimer une branche d'un serveur distant, et vous pouvez facilement réécrire l'historique.

Disons que j'étais dans la branche «master», et j'ai fait deux commits: «faire du café» et «ajouter du lait et du sucre», puis je décide d'utiliser une nouvelle branche pour cela, donc je remets «master» à «origine» /Maître'. Ce n'est pas un problème, toute l'histoire est toujours propre: «faire du café» et «ajouter du lait et du sucre» ne font pas partie du maître, seulement une fonction / faire du café.

Mercurial est le contraire; il ne veut pas changer les choses. Les branches sont permanentes, l'historique de réécriture est mal vu, vous ne pouvez pas simplement supprimer une branche du serveur.

En bref: Git vous permet de tout faire, Mercurial veut rendre les choses faciles (et rend vraiment difficile de vous laisser faire ce que vous voulez).

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.