Git minimum viable pour le développement basé sur le tronc
Moins c'est plus quand il s'agit d'un outil puissant - et trop compliqué - comme Git
Eli est co-fondateur et co-PDG de trunk.io . Il a occupé des postes de direction en ingénierie chez Microsoft, Uber et Google (qui a acquis la startup qu'il a cofondée). Son objectif principal est d'aider les équipes à créer de meilleurs logiciels, plus rapidement.

Développer dans un environnement collaboratif est une opération compliquée qui implique le suivi et la coordination du travail de plusieurs développeurs. Beaucoup d'entre nous utilisent Git pour le contrôle de version afin de garder un contrôle sur tous ces changements. Mais selon les propres mots de Linus , Git est "le gestionnaire d'informations de l'enfer". Il offre tellement d'options et d'états étranges que vous pouvez facilement vous retrouver dans un mauvais endroit au point où vous devez recloner à partir de zéro - même si vous n'avez rien fait de mal.
Beaucoup d'entre nous savent qu'un développeur a étudié la refspec Git et l'arborescence Merkle sous-jacente sur laquelle elle est basée, mais être un savant Git ne fait probablement pas partie de votre description de poste. Je peux parfaitement conduire une voiture sans comprendre le fonctionnement réel de la transmission, et en fin de compte, Git n'est qu'un moyen d'arriver à ses fins.
Pour tirer le meilleur parti de Git, vous devez l'utiliser le moins possible en matière de développement basé sur le tronc. Limitez les commandes que vous utilisez, maintenez votre branche de fonctionnalités à jour correctement et standardisez l'utilisation en équipe. Individuellement, vous pouvez profiter de la liberté de faire ce que vous voulez. Mais en équipe, le prix de la liberté se paie en friction.
Limitez vos actions Git
La pratique la plus simple à mettre en œuvre pour une efficacité maximale de Git consiste à s'en tenir à un sous-ensemble de commandes. Git peut faire beaucoup de choses, mais la grande majorité de sa puissance n'existe que pour vous aider à sortir de situations terribles. Le nombre de commandes autorisées par Git par rapport au nombre de commandes que vous devriez réellement invoquer est assez différent.
Une fois, un CTO m'a demandé de donner un cours de git avancé à son équipe d'ingénieurs. Ma réponse était simple :
au moment où vous avez besoin d'un git avancé - les roues sont déjà sorties de la voiture. concentrons-nous plutôt sur l'utilisation correcte de core git.
Voici les 10 commandes git que j'utilise pour faire mon travail tout en minimisant le nombre de fois où j'atterris dans l'enfer de Git :
Gestion de succursale
git checkout -t -b {branch-name}
Créez une branche, définissez l'amont sur la branche actuelle et basculez vers celle-ci. Vous pouvez également le faire via la commande `git branch`, mais cela prend plusieurs commandes. Comme je veux toujours basculer vers une branche lorsque je la crée, cette commande est plus succincte. Créez et contrôlez la branche d'un seul coup. J'ai l'habitude de nommer toutes mes succursales eli/{work-being-done}
.
git checkout {branch-name}
Passez à une succursale.
git branch -vv
Visualisez vos branches actuelles et leurs amonts.
git branch -D {branch-name}
Supprimez une branche locale, généralement pour nettoyer les branches obsolètes/fusionnées dans la branche principale.
Pousser et tirer
git fetch origin main:main
Tirez la télécommande main
dans votre local main
, même lorsque vous n'êtes pas actuellement sur la main
branche ! C'est le ; très utile lorsque vous essayez de fusionner le dernier main
dans une branche PR.
git push origin
Poussez mon code sur la télécommande ; probablement faire tourner beaucoup de machines dans CI pour vérifier mon travail.
git pull
Mettre à jour ma branche locale avec la télécommande du même nom.
S'engager
git add -A .
Ajouter tout ce sur quoi je travaille (fichiers nouveaux et modifiés).
git commit -am "work"
Voir ici pour une plongée profonde dans mes réflexions sur les messages de validation locaux
git merge main
Beaucoup plus à ce sujet ci-dessous. Je suis pragmatique et pas un rebaseur et heureux de brouiller ma branche locale avec les événements de main
.
Gardez votre branche de fonctionnalités à jour correctement
Dans mon dernier article , j'ai expliqué comment gérer le code d'atterrissage sur main
. Mais souvent pendant le développement, et certainement avant la fusion, vous devez être au courant des dernières modifications main
car :
- Vous avez besoin d'une fonctionnalité qui a atterri
main
pour faire votre travail de fonctionnalité. - Quelque chose
main
a changé et si vous ne le récupérez pas, vous le casserez lorsque vous essaierez d'obtenir votre code. - Vous voulez juste rester frais parce que vous êtes ingénieur et que vous aimez les nouvelles choses brillantes.
Porte 1 : git merge
C'est ma stratégie de fusion préférée. C'est simple, fiable et sans fioritures. Une base git merge
prend toutes les modifications qui se sont produites dans main
et les fusionne en tant que validations à côté de vos modifications. Vous pouvez lire jusqu'à la nausée sur les inconvénients de cette solution sans fioritures, mais honnêtement, je hausse les épaules et dis "Je m'en fiche de ça". Si vous fusionnez vos branches de travail, main
toutes ces absurdités sur la pollution de git-log deviennent exactement cela.
Honnêtement, peu importe comment/pourquoi/ce qui est arrivé dans ma branche professionnelle. Ce qui compte, c'est - est-ce que ça se construit, est-ce que ça marche, et est-ce que le code fait ce que je veux qu'il fasse ? Le reste est académique.
En pratique, et je suis un ingénieur très pragmatique, git merge
permet de gérer proprement les conflits de fusion et de se remettre à construire. Vous résolvez tous les conflits de fusion une fois - et vous êtes prêt à partir. C'est la meilleure option pour les débutants, les utilisateurs avancés occupés et ceux d'entre vous qui ne rêvent pas de devenir des gourous de Git.
Porte 2 : git rebase
C'est de loin la pire option. Ok je sais; il y a pratiquement toute une génération qui voit rebaser vs fusionner quelque chose comme des onglets vs des espaces. Mais dans les "vrais" projets, où une ou plusieurs équipes fusionnent quotidiennement vers un référentiel, le rebase nécessite de résoudre n conflits de fusion au lieu d' un avec une fusion ou un rebase de squash (plus de détails ci-dessous).
De plus, tout rebasage réécrit l'historique Git, ce qui signifie que si votre branche a une contrepartie distante, vous devez git push --force
écraser son historique avec le nouvel historique rebasé de votre branche. C'est bien en théorie, mais cela peut potentiellement supprimer accidentellement votre travail précédent d'une manière extrêmement difficile à récupérer. C'est simplement beaucoup plus dangereux que de fusionner et honnêtement, ça me donne mal à la tête rien que d'y penser.
Pour les besoins de cet article, j'ai essayé de rebaser juste pour me rappeler à quel point je n'aime pas ce flux de travail. Regardez ce qu'une simple commande rebase crache dans mon terminal :

Il y a tellement de problèmes avec ce terminal. Je reçois des notes sur les hachages de validation - je ne veux pas les voir. Je reçois quatre lignes d'indices jaunes pour me rappeler comment tout cela fonctionne. Et je suis maintenant dans un flux de travail juste pour obtenir le code main
dans ma branche. L'arbre de décision est stupidement compliqué; git rebase --skip
- qu'est-ce que c'est?! Pourquoi serait-il acceptable de sauter un commit ? Vous savez quoi? Ne me le dis pas car j'ai du travail.
Porte 3 : git squash rebase
Vous ne voulez certainement pas ce qu'il y a derrière la porte n ° 2, mais certaines personnes sont des rebaseurs inconditionnels. Mon co-fondateur, le co-PDG David Apirian, m'a montré son entrée secrète dans les coulisses pour rebaser et c'est plutôt génial. Nous appellerons cela le squash rebase .
J'ai réitéré l'importance de la simplicité de Git, mais avec cette approche, vous pouvez avoir votre rebase et le manger aussi. Vous obtenez la superposition magique d'un rebase sans la folie d'un flux de rebase standard. Avec un rebase squash, vous pouvez :
- Consultez un diff de vos commits locaux avant de pousser vers GitHub.
- Annulez facilement votre dernier commit.
- Évitez de polluer la vue de GitHub de votre pull request avec une tonne de petits commits locaux.
Étape 1 — écrasez tous vos commits locaux :
git reset --soft $(git merge-base HEAD main) &&
git commit -am "" --allow-empty-message
git rebase main
Vous pouvez rassembler tout cela dans une seule commande uber pour extraire le dernier main, écraser tous vos commits et rebaser sur le dernier main :
git reset --soft $(git merge-base HEAD main) &&
git commit -am "" --allow-empty-message &&
git fetch origin main:main &&
git rebase main
[alias]
smartcommit = !git add -A . && git commit -am "" --allow-empty-message
squash = !git reset --soft $(git merge-base HEAD main) && git commit -am "" --allow-empty-message
squashrebase = !git squash && git fetch origin main:main && git rebase main
smart = !git smartcommit && git squashrebase
L'un des aspects les plus cool de toujours écraser vos commits locaux est qu'au sommet de vous git log
se trouve tout le travail que vous avez fait dans la branche. Votre travail local ressemble maintenant plus à ce à quoi ressemblera le PR fusionné de squash lorsqu'il atterrira dans main
.
Vous pouvez à tout moment afficher le dernier commit de HEAD avec votre branche locale et voir tout le travail que vous avez fait sur main
. Ceci est similaire à la vue détaillée que GitHub vous donne de ce qui a changé, mais vous permet de rester dans votre terminal et d'éviter de basculer de manière confuse entre deux interfaces utilisateur différentes.
Je dois admettre que la première fois que David m'a montré ce flux de travail, j'ai été impressionné. Il avait surtout tué le rebase
dragon et la possibilité de visualiser localement tous les fichiers que vous avez modifiés dans votre branche est super cool.
Alors que le rebasage squash vous aide à maintenir un meilleur état de flux, la grande majorité des développeurs feraient mieux de simplement fusionner. L'utilisation incorrecte du rebase ou du squash rebase entraîne des frictions qui tuent la productivité.
Les pièges de l'aide de la branche GitHub
GitHub propose ce paramètre ☝️ pour proposer de fusionner main
automatiquement dans votre branche si elle est obsolète. Ce réglage est souvent contre-productif. Je veux que ma branche locale soit la seule source de vérité pour mes relations publiques, et personne d'autre (y compris GitHub) ne devrait y insister. Travailler avec GitHub sur ma branche personnelle devrait être une rue à sens unique. Je code localement et pousse.
Si vous configurez GitHub pour commencer à envoyer des mises à jour à votre branche de travail, vous demandez au trafic de commencer à se diriger dans la mauvaise direction. Et c'est une recette pour la douleur.
Ce problème se pose également lorsque les réviseurs de code vous laissent de petites suggestions de commit sur votre pull request et que vous les appliquez allègrement. Si vous effectuez ensuite des travaux sur votre succursale locale avant d'apporter ces modifications… vous avez ouvert un petit sac de git of bless.
Je découvre souvent que je me suis accidentellement fait cela lorsque j'essaie de repousser mes mises à jour vers la télécommande et que git me dit que je ne suis pas synchronisé. A ce stade, j'ai deux options :
git push --force
et faites exploser tout ce qui se trouve sur la télécommande et non sur votre succursale locale. Généralement, tout ce qui contient le mot force est destructeur et découragé.git merge origin/{my-work-branch}
pour fusionner les modifications distantes dans la vue locale de la branche.
Ce paramètre GitHub ️☝️ nécessite que les PR soient à jour main
avant de fusionner avec celui-ci. Cela « résout » généralement le potentiel d'avoir un cassé main
; cependant, cela ne fonctionne qu'avec des repos à très faible vitesse. Une fois qu'une poignée de développeurs essaient de fusionner plusieurs PR par jour, ils se retrouvent dans une course pour fusionner main
- ou se retrouvent constamment à effectuer une fusion/rebase main
dans leur branche pour être à nouveau "à jour", et essentiellement faire la course avec leurs collègues être le premier à fusionner. Douloureux. En règle générale, si vous souhaitez cette fonctionnalité mais que vous n'êtes pas un développeur solo, vous souhaitez probablement une file d'attente de fusion à la place, ce qui est le moyen évolutif d'obtenir une connexion sans interruption. C'est quelque chose que nous estimions suffisamment important pour produire avec Trunk Merge .
Minimiser Git pour une valeur maximale
En gardant votre utilisation de Git aussi simple que possible, vous donnez moins de corde aux développeurs et plus de temps pour faire le travail de développement qui compte vraiment. Faites en sorte que Git joue un rôle de soutien et ne devienne pas le protagoniste. Pour maintenir un environnement de développement sain et collaboratif, n'oubliez pas de :
- Choisissez la plus petite surface de Git à utiliser et respectez-la.
- Gérez toujours vos modifications en amont de la même manière.
- Standardisez les pratiques au sein de votre équipe afin que vos pairs ne dérapent pas non plus.