Pourquoi squit git s'engage pour les demandes de tirage?

200

Pourquoi chaque dépôt Github sérieux que je fais génère-t-il des demandes de désincarcération en un seul commit?

Je pensais que le journal git était là pour que vous puissiez examiner tout votre historique et voir exactement quels changements se sont produits où, mais le supprimer le retire de l’historique et le regroupe en un seul commit. Dans quel but?

Cela semble également aller à l’encontre du mantra "commettez tôt et commettez souvent".

hamstar
la source
1
Pour un gros repo, cela économise beaucoup de temps et d’espace lorsque les gens veulent faire quelque chose avec le repo.
raptortech97
8
" Cela semble également aller à l'encontre du" commettre tôt et commettez souvent "mantra. " - Non, vous commettez tôt / souvent, mais vous ne voulez pas forcément faire une PR à chaque petit changement. Et le critique ne veut pas les examiner, c'est sûr.
JensG
7
Il n'est pas nécessaire de modifier la question pour résumer la réponse perçue. C’est la place des réponses acceptées et des votes positifs. Les gens peuvent tirer leurs propres conclusions en lisant les réponses.
5
Je ne comprends toujours pas pourquoi il y a un désir d'écraser les commits. Je pense qu'il y a beaucoup trop d'inconvénients à écraser avec presque aucun avantage. C’est un problème de présentation qui se fait passer pour un problème de données.
mkobit
3
Toutes les analyses utiles dans le journal sont perdues avec des squash. Il semble donc qu'un développeur ait créé une fonctionnalité avec un seul commit. Il est également difficile de comprendre pourquoi un code étrange existe. L'historique d'une fonctionnalité peut être important et peut aider à expliquer pourquoi le code est ce qu'il est. La vue concise du journal est utile, mais ne peut-on pas l'obtenir autrement?
Tjaart le

Réponses:

158

Pour que vous ayez un historique git clair et concis qui documente clairement et facilement les modifications apportées et les raisons.

Par exemple, un journal git typique «non épilé» pourrait ressembler à ceci:

7hgf8978g9... Added new slideshow feature, JIRA # 848394839
85493g2458... Fixed slideshow display issue in ie
gh354354gh... wip, done for the week
789fdfffdf... minor alignment issue
787g8fgf78... hotfix for #5849564648
9080gf6567... implemented feature # 65896859
gh34839843... minor fix (typo) for 3rd test

Quel bordel!

Considérant qu'un journal git mieux géré et fusionné avec un peu plus d’attention sur les messages pourrait ressembler à ceci:

7hgf8978g9... 8483948393 Added new slideshow feature
787g8fgf78... 5849564648 Hotfix for android display issue
9080gf6567... 6589685988 Implemented pop-up to select language

Je pense que vous pouvez voir l’intérêt d’écraser les commits et le même principe s’applique aux demandes d’extraction: lisibilité de l’historique. Vous pouvez également ajouter des informations à un journal de validation qui contient déjà des centaines, voire des milliers, de modifications, ce qui contribuera à la brièveté de l’historique croissant.

Vous voulez vous engager tôt et souvent. C'est une bonne pratique pour plusieurs raisons. Je trouve que cela m'amène à avoir fréquemment des commits "wip" (travaux en cours), "partie A terminée" ou "faute de frappe, correction mineure", où j'utilise git pour m'aider à travailler et me donner des points de travail qui Je peux revenir à si le code suivant ne fonctionne pas alors que je progresse pour que les choses fonctionnent. Cependant, je n'ai pas besoin ou ne souhaite pas que cette histoire fasse partie de la version finale de l'histoire de git afin d'écraser mes commits - mais reportez-vous aux notes ci-dessous pour en savoir ce que cela signifie sur une branche de développement par rapport à maître.

S'il existe des jalons importants représentant des étapes de travail distinctes, il est toujours possible d'avoir plus d'un commit par fonctionnalité / tâche / bogue. Cependant, cela peut souvent mettre en évidence le fait que le ticket en cours de développement est "trop ​​gros" et doit être décomposé en éléments plus petits pouvant être autonomes, par exemple:

8754390gf87... Implement feature switches

semble être "1 morceau de travail". Ou ils existent ou ils n'existent pas! Ne semble pas avoir de sens pour le sortir. Cependant, l'expérience m'a montré que (selon la taille et la complexité de l'organisation), un chemin plus granulaire pourrait être:

fgfd7897899... Add field to database, add indexes and a trigger for the dw group
9458947548g... Add 'backend' code in controller for when id is passed in url.
6256ac24426... Add 'backend' code to make field available for views.
402c476edf6... Add feature to UI

Les petites pièces signifient des révisions de code plus faciles, des tests unitaires plus faciles, une meilleure opportunité de qa, un meilleur alignement sur le principe de responsabilité unique, etc.

Pour des raisons pratiques de savoir quand faire de telles courges, il existe essentiellement deux étapes distinctes qui ont leur propre flux de travail

  • votre développement, par exemple les demandes d'extraction
  • votre travail ajouté à la branche principale, par exemple maître

Au cours de votre développement, vous vous engagez «tôt et souvent» et avec des messages rapides «jetables». Vous voudrez peut-être écraser ici parfois, par exemple écraser dans les messages wip et todo. Il est normal, au sein de la branche, de conserver plusieurs commits qui représentent des étapes distinctes du développement. La plupart des courges que vous choisissez de faire doivent se trouver dans ces branches, pendant leur développement et avant leur fusion.
Lors de l'ajout à la branche principale, vous voulez que les commits soient concis et correctement formatés en fonction de l'historique existant de la ligne principale. Cela peut inclure l'ID du système Ticket Tracker, par exemple JIRA, comme indiqué dans les exemples. La compression ne s'applique pas vraiment ici à moins que vous ne souhaitiez «cumuler» plusieurs commits distincts sur le maître. Normalement vous ne le faites pas.

Utiliser --no-fflors de la fusion avec master utilisera un commit pour la fusion et préservera également l'historique (dans la branche). Certaines organisations considèrent qu'il s'agit d'une pratique exemplaire. Voir plus à https://stackoverflow.com/q/9069061/631619 Vous verrez également l'effet pratique git log--no-ffcommettras sera la dernière commettras, au sommet de la tête (quand tout fait), alors que sans --no-ffqu'il soit plus loin dans l’histoire, en fonction des dates et des autres commits.

Michael Durrant
la source
30
Je suis complètement en désaccord avec cette philosophie. Les petits commits réguliers divisent une tâche en tâches plus petites et donnent souvent des informations utiles sur ce qui était en train d'être travaillé lors du changement de ligne. Si vous avez de petites commissions "WIP", vous devriez utiliser une base interactive pour les nettoyer avant de les pousser. Réduire les relations publiques semble complètement vaincre le point des IMHO à petit commet habituel. C'est presque irrespectueux pour l'auteur qui a fait l'effort de donner des messages de log avec des informations de commit spécifiques et vous ne faites que tout gâcher.
Jez
6
Intéressant. À la fin de la journée, je fonde ma «philosophie» sur ce que j'ai vu fonctionner. Pour être clair - diviser le travail en petites parties et s’engager chacune est une excellente chose tout en travaillant sur le changement. Mon expérience a été que , une fois ce travail est fusionné à maîtriser, la principale chose qui a tendance à faire examiner est « ce qui, dans son tout ce qui est cette fusion commit qui a causé (généralement) les questions x ...
Michael Durrant
6
Je suis aussi anti-squash. Vous ne devriez pas écrire des messages de commit stupides en premier lieu. Et dans l'exemple (85493g2458 ... Correction d'un problème d'affichage de diaporama dans ie) Cela serait beaucoup plus utile si je devais déboguer le code qui lui était associé.
Thomas Davis
5
Il est regrettable qu'un tel dogme négligent et mal placé ait émergé dans la pratique de la gestion de la chaîne d'approvisionnement. Les outils de filtrage doivent être utilisés pour gérer la lisibilité de l'historique et non le comportement des commits.
ctpenrose
4
tendances inquiétantes et dogme. yow. Je préférerais un argument plus factuel présenté d'une manière plus agréable. Vous êtes invités à poster / voter un avis différent. C'est le but du vote communautaire
Michael Durrant
26

Parce que, souvent, la personne qui rédige un PR se soucie de l'effet net des validations "fonctionnalité ajoutée X", et non des "modèles de base, fonction de correction X, fonction d'ajout de correction Y, correction des fautes de frappe dans les commentaires, paramètres de mise à l'échelle des données ajustés, hashmap fonctionne mieux que list "... niveau de détail

Si vous pensez que vos 16 commits sont mieux représentés par 2 commits que par 1 "Ajout de la fonctionnalité X, ré-factorisé Z pour utiliser X", alors c'est probablement bien de proposer un pr avec 2 commits, mais alors il serait peut-être préférable de proposer 2 prs séparés dans ce cas (si le repo insiste toujours sur des prs à engagement unique)

Cela ne va pas à l’encontre du mantra "engagez-vous tôt et engagez-vous souvent", comme dans votre référant, tandis que vous développez, vous avez toujours les détails granulaires, de sorte que vous avez une chance minime de perdre du travail, et que d’autres personnes puissent examiner / tirer / proposer prs contre ton travail pendant que le nouveau pr est en cours de développement.

Andrew Hill
la source
4
Mais lorsque vous écrasez, vous perdez également cette histoire dans votre fourche, n'est-ce pas? Pourquoi voudriez-vous jeter cette histoire?
Hamstar
4
a) si vous voulez conserver l’historique de votre branche, il est assez facile d’avoir une branche "pour la fusion" et une branche "dev" (ce qui pourrait bien être ce dont vous avez besoin de toute façon, car vous pourriez ajouter de nouvelles commits à votre dev principal. branche après avoir proposé le PR) b) vous conservez toujours l’effet net de ces commits, c’est uniquement dans les cas où vous souhaitez annuler, ou sélectionner un sous-composant du pr que le commet individuel est nécessaire . Dans ce cas, vous faites probablement plusieurs choses (par exemple: correction de bug X, ajout de la fonctionnalité Y) dans un seul PR et plusieurs PR peuvent à nouveau être nécessaires.
Andrew Hill
@ AndrewHill quel concept génial! Je souhaite présenter ce flux de travail à mon équipe. Comment cela a-t-il fonctionné pour vous? J'ai écrit un billet de blog à ce sujet et je suis tombé sur ce commentaire en faisant des recherches.
Droogans
19

La principale raison de ce que je peux voir est la suivante:

  • L’interface utilisateur GitHub pour la fusion des demandes d'extraction actuellement (octobre 2015) ne vous permet pas de modifier la première ligne du message de validation, ce qui vous oblige à le modifier. Merge pull request #123 from joebloggs/fix-snafoo
  • L’interface utilisateur GitHub permettant de parcourir l’historique des validations ne vous permet pas de visualiser l’historique de la branche du --first-parentpoint de vue.
  • L’interface utilisateur de GitHub qui examine le blâme d’un fichier ne vous permet pas de visualiser le blâme du fichier avec le --first-parentpoint de vue (notez que cela n’a été corrigé que dans Git 2.6.2, nous pourrions donc pardonner à GitHub de ne pas avoir ce message. disponible)

Ainsi, lorsque vous combinez les trois situations ci-dessus, vous obtenez une situation dans laquelle les modifications inconditionnelles en cours de fusion sont laides à partir de l'interface utilisateur de GitHub.

Votre histoire avec les commits écrasés ressemblera à quelque chose comme

1256556316... Merge pull request #423 from jrandom/add-slideshows
7hgf8978g9... Added new slideshow feature
56556316ad... Merge pull request #324 from ahacker/fix-android-display
787g8fgf78... Hotfix for android display issue
f56556316e... Merge pull request #28 from somwhere/select-lang-popup
9080gf6567... Implemented pop-up to select language

Considérant que sans commets écrasés l'histoire ressemblera à quelque chose comme

1256556316... Merge pull request #423 from jrandom/add-slideshows
7hgf8978g9... Added new slideshow feature, JIRA # 848394839
85493g2458... Fixed slideshow display issue in ie
gh354354gh... wip, done for the week
789fdfffdf... minor alignment issue
56556316ad... Merge pull request #324 from ahacker/fix-android-display
787g8fgf78... hotfix for #5849564648
f56556316e... Merge pull request #28 from somwhere/select-lang-popup
9080gf6567... implemented feature # 65896859
gh34839843... minor fix (typo) for 3rd test

Lorsque vous avez beaucoup de commits dans un suivi de relations publiques où un changement est intervenu, cela peut devenir un peu un cauchemar si vous vous limitez à utiliser l'interface utilisateur de GitHub .

Par exemple, vous trouvez qu'un pointeur null est dé-référencé quelque part dans un fichier ... vous dites donc "qui a fait cela, et quand? Quelles versions de version sont affectées?". Ensuite, vous vous dirigez vers la vue des responsables dans l'interface utilisateur de GitHub et vous constatez que la ligne a été modifiée dans789fdfffdf... "oh, mais attendez une seconde, l'indentation de cette ligne venait juste d'être modifiée pour s'inscrire dans le reste du code"; la page de blâme ... finalement vous trouvez le commit ... c'est un commit d'il y a 6 mois ... "oh **** cela pourrait affecter les utilisateurs depuis 6 mois" dites-vous ... ah mais attendez, ce commit était en fait dans une requête Pull et n’a été fusionné qu’hier et personne n’a encore publié de communiqué à ce sujet ... "Bon sang pour avoir fusionné des commits sans avoir écrasé l’histoire" UI GitHub

Voyons maintenant comment cela fonctionne si vous utilisez la ligne de commande Git (et le super-génial 2.6.2 qui a le correctif pour git blame --first-parent)

  • Si vous utilisiez la ligne de commande Git, vous seriez en mesure de contrôler complètement le message de validation de la fusion. Ainsi, la validation de la fusion pourrait avoir une belle ligne de résumé.

Donc, notre histoire de commit ressemblerait à

$ git log
1256556316... #423 Added new slideshow feature
7hgf8978g9... Added new slideshow feature, JIRA # 848394839
85493g2458... Fixed slideshow display issue in ie
gh354354gh... wip, done for the week
789fdfffdf... minor alignment issue
56556316ad... #324 Hotfix for android display issue
787g8fgf78... hotfix for #5849564648
f56556316e... #28 Implemented pop-up to select language
9080gf6567... implemented feature # 65896859
gh34839843... minor fix (typo) for 3rd test

Mais on peut aussi faire

$ git log --first-parent
1256556316... #423 Added new slideshow feature
56556316ad... #324 Hotfix for android display issue
f56556316e... #28 Implemented pop-up to select language

(En d'autres termes: la CLI Git vous permet de prendre votre gâteau et de le manger aussi)

Maintenant, lorsque nous abordons le problème du pointeur null ... eh bien, nous utilisons simplement git blame --first-parent -w dodgy-file.cet nous recevons immédiatement le commit exact où la dé-référence du pointeur null a été introduite dans la branche principale en ignorant les simples changements d'espaces.

Bien sûr, si vous effectuez des fusions à l'aide de l'interface utilisateur de GitHub, alors git log --first-parentc'est vraiment merdique, car GitHub a forcé la première ligne du message de validation de fusion:

1256556316... Merge pull request #423 from jrandom/add-slideshows
56556316ad... Merge pull request #324 from ahacker/fix-android-display
f56556316e... Merge pull request #28 from somwhere/select-lang-popup

Donc, pour résumer une longue histoire:

L'interface utilisateur de GitHub (octobre 2015) présente un certain nombre d'inconvénients en ce qui concerne la fusion des demandes d'extraction, la présentation de l'historique des validations et l'attribution des informations de responsabilité. Le meilleur moyen actuel de corriger ces défauts dans l'interface utilisateur de GitHub est de demander aux personnes d'écraser leurs commits avant de procéder à la fusion.

La CLI Git ne présente pas ces problèmes et vous pouvez facilement choisir la vue à afficher afin de découvrir à la fois la raison pour laquelle une modification particulière a été apportée de cette façon (en consultant l'historique des commits non annulés), ainsi que voir les commits effectivement écrasés.

Post script

La dernière raison souvent invoquée pour écraser les commits est de faciliter le portage en arrière… Si vous n'avez qu'un seul commit à sauvegarder (c.-à-d. Le commit écrasé), il est facile de choisir les cerises…

Eh bien, si vous regardez l’histoire de git avec, git log --first-parentvous pouvez simplement choisir les modifications de fusion. La plupart des gens sont confus, car ils doivent spécifier l’ -m Noption mais si vous recevez le commit, git log --first-parentvous savez que c’est le premier parent que vous souhaitez suivre, ce sera donc le cas.git cherry-pick -m 1 ...

Stephen Connolly
la source
1
Bonne réponse! Mais choisir une gamme est assez facile, je ne suis pas sûr de l'acheter comme raison.
Stiggler
1
@ Stiggler Je ne l'achète pas personnellement comme raison, mais je l'ai vu citée par d'autres comme raison. IMHO l'outillage de git est ce que vous voulez et écraser commet est mal ... mais je dirais que cela m'a conduit à --first-parentme réparer afin de gagner un argument contre les écrasements ;-)
Stephen Connolly
1
Cela devrait être la réponse acceptée. Beaucoup moins de dogmes et cela montre que le filtrage historique peut être utilisé pour "avoir votre gâteau et le manger aussi". Vous n'êtes pas obligé d'annihiler l'histoire pour apporter de la clarté aux explorations de l'histoire Git.
ctpenrose
Il ne sera pas si facile de faire le bon choix si en écrasant vos commits, vous finissez par regrouper de nombreuses modifications apportées à différents fichiers dans un seul commit. Je suppose que cela varie beaucoup en fonction de la base de code, des modifications apportées, du nombre de personnes collaborant, etc. Je ne pense pas que nous puissions proposer une seule règle générale valable dans tous les cas.
Amy Pellegrini Le
2

Je suis d'accord avec les sentiments exprimés dans les autres réponses de ce fil pour montrer un historique clair et concis des fonctionnalités ajoutées et des bugs corrigés. Cependant, je voulais aborder un autre aspect auquel votre question a échappé mais n’a pas été explicitement énoncé. Une partie du problème que vous avez peut-être avec certaines des méthodes de travail de git est que git vous permet de réécrire l’histoire, ce qui semble étrange lorsqu’on le présente à git après avoir utilisé d’autres formes de contrôle de source où de telles actions sont impossibles. En outre, cela va également à l’encontre du principe généralement accepté du contrôle de source selon lequel, une fois que quelque chose est validé / enregistré dans le contrôle de source, vous devriez pouvoir revenir à cet état, quels que soient les changements que vous avez apportés à la suite de ce commit. Comme vous l'avez laissé entendre dans votre question, il s'agit d'une de ces situations. Je pense que Git est un excellent système de contrôle de version. Cependant, pour le comprendre, vous devez comprendre certains détails de la mise en œuvre et des décisions de conception, ce qui entraîne une courbe d'apprentissage plus abrupte. Gardez à l'esprit que git était destiné à être un système de contrôle de version distribué, ce qui aidera à expliquer pourquoi les concepteurs autorisent la réécriture de l'historique de git avec des validations de squash.

Fred Thomsen
la source
Strictement parlant, Git ne vous permet pas de changer d’histoire. Les objets engagés sont immuables. Ce ne sont que les pointeurs de branche qui sont mutables, et seulement ensuite avec une «mise à jour forcée», ce qui est généralement considéré comme quelque chose que vous ne faites que pour des raisons de développement, pas sur la branche principale. Vous pouvez toujours revenir à un état précédent à l'aide de la commande de refog, sauf si vous avez git gcété exécuté pour supprimer des objets non référencés.
Jon Purdy
Vous avez raison et j'aurais peut-être dû en parler plus haut. Cependant, je préconiserais quelque chose comme une poussée forcée ou des commits qui ont déjà été poussés vers un dépôt distant, serait qualifié d'historique de réécriture, car l'ordre et la disposition des commits sont aussi importants que les commits eux-mêmes.
Fred Thomsen
Cela est vrai pour un commit donné. Dans l’ensemble, je pense que le rebasage interactif et la branche filtre permettent de réécrire efficacement l’histoire en modifiant sa composition.
Michael Durrant
1
Pour être juste, SVN conserve l'approche "chaque commit est sacré", mais lorsque la fusion crée un commit unique avec cette fusion et masque les révisions qui y ont contribué, il apparaît donc que toutes les fusions SVN sont "rebasées". Ils ne le sont pas, il vous suffit de dire à la commande history pour vous montrer les composants fusionnés. J'aime cette approche le meilleur.
gbjbaanb
1

À cause de la perspective ... La meilleure pratique consiste à avoir un seul commit par <<issue-management-system>>problème, si possible.

Vous pouvez avoir autant d’engagements que vous le souhaitez dans votre propre branche / rapport d’activité, mais c’est votre histoire qui est pertinente pour ce que vous faites maintenant pour VOTRE perspective ... ce n’est pas l’HISTOIRE de l’ensemble de l’ÉQUIPE / PROJET ou de l’application de leur perspective à conserver dans quelques mois ...

Ainsi, chaque fois que vous souhaitez valider un correctif ou une fonctionnalité dans un référentiel commun (cet exemple concerne la branche develop), procédez comme suit:

comment rebaser votre branche de fonctionnalités pour développer rapidement

    # set your current branch , make a backup of it , caveat minute precision
    curr_branch=$(git rev-parse --abbrev-ref HEAD); git branch "$curr_branch"--$(date "+%Y%m%d_%H%M"); git branch -a | grep $curr_branch | sort -nr

    # squash all your changes at once 
    git reset $(git merge-base develop $curr_branch)

    # check the modified files to add 
    git status

    # add the modified files dir by dir, or file by file or all as shown
    git add --all 

    # check once again 
    git log --format='%h %ai %an %m%m %s'  | less

    # add the single message of your commit for the stuff you did 
    git commit -m "<<MY-ISSUE-ID>>: add my very important feature"

    # check once again 
    git log --format='%h %ai %an %m%m %s'  | less

    # make a backup once again , use seconds precision if you were too fast ... 
    curr_branch=$(git rev-parse --abbrev-ref HEAD); git branch "$curr_branch"--$(date "+%Y%m%d_%H%M"); git branch -a | grep $curr_branch | sort -nr

    # compare the old backup with the new backup , should not have any differences 
    git diff <<old-backup>>..<<new-backup-branch>>


    # you would have to git push force to your feature branch 
    git push --force 
Yordan Georgiev
la source
cela ne tente même pas de répondre à la question posée: pourquoi squit git s’engage pour les demandes de tirage? Voir Comment répondre
Moucheron
après la tentative d'explication, il devrait le faire ...
Yordan Georgiev
Je ne vois pas comment l'explication ajoutée offre quelque chose d'important par rapport aux points soulevés et expliqués dans les réponses les plus votées qui ont été postées il y a plusieurs années (les efforts visant à améliorer la première révision sont toutefois appréciés)
gnat
le mot clé est "perspective", le concept de perspective facilite beaucoup l'explication de ce type de problèmes informatiques, par exemple - votre perspective pour la réponse à cette question est celle déjà fournie, ma perspective utilise le mot clé "perspective" et fournissant un exemple pratique de la mise en œuvre de la même pratique exemplaire expliquée selon différentes perspectives ...
Yordan Georgiev
1

Je verrais si le code est rendu public ou non.

Quand les projets restent privés:

Je recommanderais de ne pas écraser et de voir la fabrication de la saucisse. Si vous utilisez de bons et de petits commits, des outils tels que git bisect sont extrêmement pratiques et les utilisateurs peuvent rapidement localiser les commits de régression et voir pourquoi vous l'avez fait (à cause du message de validation).

Quand les projets deviennent publics:

Tout écraser parce que certains commits peuvent contenir des fuites de sécurité. Par exemple, un mot de passe qui a été validé et supprimé à nouveau.

Vince V.
la source