Git Attitude

La gestion de sources qui fait du bien

Le point sur les évolutions depuis Git 1.7

| Commentaires

Vous êtes nombreux à utiliser Git sans bien suivre ce qui change d’une version à l’autre. Parfois, vous vous contentez aussi de la version disponible sur votre distribution Linux, même quand celle-ci date un peu.

Faisons le point sur les évolutions depuis Git 1.7, histoire de voir ce que vous loupez :-)

Mise à jour : la version anglaise de cet article est ici

Déjà, où en suis-je et comment mettre à jour ?

À l’heure où j’écris ceci, la version courante est la 2.1.0, qui date du 15/08/2014.

Le site officiel maintient des builds officiels pour Mac et Windows (ce dernier étant souvent un poil en retard, par exemple là tout de suite c’est la 1.9.4), et bien sûr les sources pour ceux qui veulent compiler ça eux-mêmes.

Notez que sur Mac, j’ai tendance à installer et mettre à jour via Homebrew, qui est généralement à jour sous 48h.

Vous pouvez tester votre version en cours :

1
2
$ git --version
git version 2.1.0

Pour mettre à jour sur Windows, installez simplement le dernier download fourni par le site officiel.

Sur Mac, utilisez soit l’installeur officiel si vous passiez par là, soit une mise à jour Homebrew si vous êtes comme moi :

1
2
3
4
5
6
7
8
$ brew update
$ brew upgrade git
==> Upgrading 1 outdated package, with result:
git 2.1.0
$ git --version
git version 2.1.0

Sur Linux, si vous passez par les paquets officiels (ou des PPA enregistrés), utilisez la commande d’installation ou de mise à jour adaptée (généralement apt-get sur Debian/Ubuntu, yum sur Fedora, etc.).

Un mot sur Debian et Ubuntu

Pour Debian et Ubuntu, les versions officielles accusent souvent un bon retard, surtout les LTS, en restant scotchées à leur version de sortie initiale :

  • 10.04 LTS « Lucid Lynx » a la 1.7.0 (septembre 2010)
  • 12.04 LTS « Precise Pangolin » a la 1.7.9 (janvier 2012)
  • 14.04 LTS « Trusty Tahr » a la 1.9.1 (mars 2014)

Je ne saurais trop vous recommander d’enregistrer tout de suite le PPA officiel :

1
$ sudo add-apt-repository ppa:git-core/ppa

Si vous n’avez pas la commande add-apt-repository, commencez par installer le paquet nécessaire :

1
2
3
$ sudo apt-get install python-software-properties
# Et si vous avez 14.04 ou au-delà…
$ sudo apt-get install software-properties-common

Vous aurez ainsi la dernière version (le PPA est mis à jour sous 3-4 jours en moyenne après la sortie centrale).

Liste choisie des évolutions à connaître

On ne va pas juste paraphraser les release notes : je me concentre sur les nouveautés fonctionnelles (pas les correctifs et améliorations de performances), en choisissant celles qui me semblent présenter un intérêt particulier.

Spécifiquement, je laisse de côté tout ce qui est foreign interface (interfaçage entre Git et les autres systèmes de gestion de version) et outils graphiques (gitk, git-gui, git-web), ainsi que les commandes de plomberie, pour me concentrer sur celles de porcelaine (celles que l’utilisateur normal est susceptible d’utiliser fréquemment).

Plutôt que de dérouler un titre par version, je vous fais trois gros intervalles, volontairement calés sur les versions de base des Ubuntu LTS récentes.

D’une manière générale, plus on avance dans les versions, plus les complétions Bash et ZSH et les prompts avancés s’améliorent. Par exemple, à bien des égards, le prompt Bash officiel fourni par __git_ps1 enterre fonctionnelement celui de Oh My ZSH.

Entre 1.7.0 et 1.7.9

Il y a eu un paquet de 1.7.x (12 !), mais le gros des modifs utiles est apparu dans la 1.7.2, qui a longtemps constitué mon « minimum vital ».

Pas mal de protections contres les pièges classiques des submodules ont fait leur apparition à cette période :

  • git diff et git status sont plus détaillés et explicites sur les modifs locales apportées aux submodules, ce qui contribue à réduire les risques d’oubli de commit/push sur ceux-ci. Diverses options et variables de configuration permettent de personnaliser ces nouveaux comportements.
  • git fetch --recurse-submodules fait son apparition en 1.7.4, histoire de gagner un peu de temps.
  • Joli garde-fou depuis 1.7.7 dans git push en cas de commits locaux non pushés sur les submodules : git push --recurse-submodules=check.
  • Depuis la 1.7.8, les dossiers Git des submodules ne sont plus directement dans leur checkout, mais dans le .git/modules/ du dépôt conteneur, et déréférencés par gitfiles (leur .git est un fichier texte contenant une ligne gitdir: chemin-du-dossier-git-déporté). Ça permet de recaler le commit utilisé d’un submodule au niveau parent sans avoir besoin d’en avoir fait le checkout ; dans la pratique, je trouve ça assez edge case, mais connaître ce déport de stockage évite les surprises en inspectant les dossiers de submodules…

Les logs ont aussi connu des améliorations importantes :

  • La syntaxe de révision :/pattern, qui prenait jusqu’en 1.7.1 un texte simple, est interprétée comme regex depuis 1.7.2, et n’est plus limitée au seul début du message de commit (nettement plus pratique).
  • Apparition des colorations de git log --decorate en 1.7.2.
  • Apparition du pendant regex de git log -S : git log -G, en 1.7.4. Indispensable !
  • git log accepte des globs (ex. *.rb) comme chemins depuis la 1.7.5.
  • Apparition de log.abbrevCommit en 1.7.6, qui évite les SHA complets dans les logs mais en fait un peu partout…

Côté fusions, rebases, push et pull, quelques trucs importants, voire centraux, ont débarqué :

  • Apparition du sympathique mode --keep pour git reset (variation de git reset --merge, qu’on appelle plus récemment git merge --abort).
  • git cherry-pick (et incidemment git revert) sont depuis 1.7.2 capables d’exploiter les stratégies de fusion (--strategy), ce qui est super pratique dans le cadre des subtrees notamment.
  • Apparition de l’importante configuration merge.ff, qui pilote l’approche par défaut aux fast-forwards de git merge, en 1.7.6.
  • Depuis 1.7.6, git rebase sans paramètre est depuis 1.7.6 équivalent à git rebase @{u}, donc rebase sur l’upstream. À mon sens pas très utile (je voudrais fetcher avant, donc faire en fait un git pull --rebase ou équivalent), mais potentiellement dangereux car ce n’est plus une no-op. On trouvera la même évolution plus récemment pour git merge, pfff…
  • Apparition du synonyme upstream, qui remplacera plus tard tracking comme valeur de configuration pour push.default, en 1.7.5 (je recommande d’ailleurs upstream plutôt que le nouveau défaut, simple).
  • La configuration critique pull.rebase n’est apparue qu’en 1.7.9 (uniquement avec true et false à ce stade).
  • core.autocrlf évite désormais de pourrir des fichiers aux fins de ligne mixtes : seuls les fichiers 100% LF seront manipulés.

Certaines améliorations de confort me semblent aussi dignes d’être mentionnées :

  • Le script officiel de complétion, qui est très pointu, est devenu compatible Zsh (et plus seulement Bash) en 1.7.4.
  • Dans le même esprit que git checkout -, la 1.7.6 apporte git merge -, pour fusionner la branche qu’on vient de quitter (très fréquent, bien pratique). D’autres commandes suivront plus récemment.
  • La 1.7.7 nous a enfin donné l’option --include-untracked / -u sur git stash !
  • Depuis 1.7.8, il est possible de fournir un glob à git branch, à condition de le préfixer par --list : git branch --list pr-*.
  • Depuis 1.7.9, git commit --amend --no-edit est une autre manière de faire le traditionnel git commit --amend -C HEAD.
  • Grosses améliorations fonctionnelles sur git notes, notamment pour les persister au travers de réécritures d’historique (rebase, amend…).

Entre 1.7.9 et 1.9.1

C’est depuis la 1.7.10 qu’un merge qui réussit en terminal se sent obligé d’ouvrir l’éditeur sur le message de commit… Perso ça me saoûle profond et je le désactive en assurant un GIT_MERGE_AUTOEDIT=no dans mon environnement.

Notamment dans la période 1.8.x, il y a eu énormément de nouveautés et d’améliorations. Voici ma sélection…

Côté log et consorts (diff, notamment), pas mal de petites nouveautés et améliorations sympathiques :

  • git log -S / -G honorent enfin -i (insensible à la casse) depuis 1.7.10
  • Depuis la 1.8.2, on peut auto-désactiver les codes couleurs de nos formats git log en les préfixant, par exemple %C(auto,blue) au lieu de juste %C(blue). Pas révolutionnaire, mais pratique.
  • Depuis 1.8.3, le code couleur spécial %C(auto) est utilisé par le format de log %d (décorations) pour restituer les couleurs nativement employées (ex. vert pour les branches locales, rouge pour les distantes, jaune pour les tags, bleu pour les symboliques…). Petit bonus sympa.
  • La 1.8.4 introduit, à titre expérimental, git log -L, pour suivre l’histo d’une portion plus ou moins avancée d’un fichier.
  • On peut s’intéresser depuis 1.9.0 à « tout sauf un chemin », par exemple dans log, avec une spécification négative : git log -- . ':!dir' (attention aux quotes autour de la syntaxe, car ! est interpolé par la plupart des shells).
  • Depuis 1.9.0, on peut exclure des branches de git log et ses copains à l’aide de --exclude=<glob>, par exemple git log --exclude='*/*' --branches.
  • Il est possible de définir globalement le nombre de lignes de contexte des diffs avec diff.context depuis la 1.8.1.

Côté push et pull, quelques nouveautés dont une absolument critique :

  • Apparition du mode de push simple dans la 1.7.11, qui deviendra le défaut en 2.0. Je comprends l’intérêt pour les débutants (et encore), mais perso je préfère upstream, vu que je me réserve le droit de pusher sur une branche non éponyme.
  • Enfin un mode zéro-défaut de pull grâce à pull.rebase=preserve, merci 1.8.5 !

La tendance à rajouter des garde-fous contre les pièges des submodules continue :

  • Après son introduction en 1.7.7 avec la seule valeur check, le pratique git push --recurse-submodules=… apprend la valeur on-demand, qui fait les pushes manquants.
  • L’ensemble des sous-commandes de git submodule ont cessé en 1.8.4 d’exiger qu’on les lance depuis la racine du dépôt. Parce que merde, hein.

Et parce que les subtrees sont une alternative intéressante aux submodules mais peuvent être difficiles à manipuler, la 1.7.11 intègre le script de contrib git subtree dans la distro officielle. Je ne suis toutefois fan que de sa capacité à reporter le log partiel des modifs locales vers l’upstream ; pour le reste, je trouve qu’il pourrit joyeusement le graphe.

Côté configuration, attributs et fichiers ignorés, on voit aussi quelques trucs sympa débarquer :

  • La configuration globale (par utilisateur) de Git n’est plus nécessairement dans ~/.gitconfig depuis 1.7.12 : en conformité avec XDG, elle peut être dans ~/.config/git/config, accompagnée d’autres fichiers auto-détectés par leurs configurations respectives, comme attributes (pour core.attributesfile) et ignore (pour core.excludesfiles) par exemple.
  • On peut enfin utiliser **/ dans .gitignore (et .gitattributes) depuis la 1.8.2, pour indiquer une profondeur quelconque. Ça peut bien sûr être préfixé par un chemin parent, sans quoi c’est superflu.

Comme toujours, la complétion et le prompt évoluent vers davantage de puissance, avec notamment les points suivants :

  • C’est depuis la 1.7.12 qui la complétion et les prompts ont été découpés en scripts indépendants.
  • Des scripts de complétion dédiés à Zsh et Tcsh sont apparus en 1.8.1.
  • Une amélioration très utile du prompt mérite d’être signalée à partir de 1.8.3 : lors d’un rebase interactif, il indique précisément où on en est (ex. REBASE-i 3/8), un vrai bonheur. Dans le même esprit, git status est plus détaillé lors d’un rebase (ou d’un bisect, d’ailleurs).

Quelques autres évolutions orientées confort d’utilisation :

  • Depuis la 1.7.12, git help bascule sur l’affichage HTML en navigateur quand man n’est pas disponible (ex. Windows). On peut le forcer avec git help -w.
  • Pour réécrire tout l’historique d’une branche, c’était galère faute de point de base. Depuis 1.7.12, git rebase --root le permet facilement.
  • Il est possible d’abréger HEAD en @ (pratique sur Mac !) depuis la 1.8.5.
  • Tout comme merge et checkout, cherry-pick autorise l’argument - depuis la 1.8.5, pour chopper la tête de la branche précédente.

Enfin, vous avez peur de virer trop de trucs avec git clean ? Depuis 1.8.4, on a le bien pratique git clean -i, qui est interactif.

Entre 1.9.1 et 2.1.0

À partir de la 1.9.0, Git a adopté le semver, donc les versions de 3ème niveau (ex. 1.9.1, 1.9.2) n’apportent que des correctifs. Pour trouver des nouveautés et améliorations, il faut aller au 1er (ex. 2.0.0) ou 2ème (ex. 2.1.0) niveau.

Notez qu’à partir de ce niveau, sur Debian/Ubuntu par exemple vous serez obligés de recourir à une installation alternative, idéalement le PPA (voir début d’article).

On parle ici de 2–3 gros changements et un poil de confort.

  • git rebase rejoint dans la 2.0 merge, checkout et cherry-pick dans le club des commandes acceptant - pour dire « la branche précédente » (pour rappel, la syntaxe universelle serait @{-1}).
  • À partir de la 2.0, git tag --list sait trier les tags en tant que numéros de versions, de sorte que v2.10.3 serait considéré ultérieur à v2.9.4, par exemple. Il suffit de préciser --sort=version:refname. Pour rappel, l’option --sort peut préfixer sa valeur par - pour inverser l’ordre. Si vous taguez principalement des versions et voulez ce comportement par défaut, depuis la 2.1 vous avez une variable de configuration tag.sort pour ça.
  • La 2.0 change la valeur originale de push.default à simple. Encore une fois, je recommande plutôt upstream pour les non-débutants (voire pour tous).
  • Autre changement important de la 2.0 : git add -A / -u sans chemin fourni traite maintenant par défaut tout le dépôt, au lieu du dossier courant et ses sous-dossiers comme auparavant. Gaffe à vos scripts, aliases et habitudes !
  • Attention, depuis la 2.1, git merge seul n’est plus une no-op (enfin, un refus plus exactement) : si un upstream est défini (la branche tracke une distante), c’est lui qu’on merge. Il rejoint ici l’approche de git rebase.

Mettez-vous à jour !

Avec Git comme avec la plupart de vos logiciels importants, avoir une version récente est très utile. Pensez à vous mettre à jour régulièrement (le début de l’article vous rappelle comment faire techniquement).

J’espère qu’à la lecture de cet article, vous avez trouvé plein de raisons de mettre à jour votre Git si ce n’est déjà fait, et peut-être découvert quelques possibilités cool que vous ignoriez.

Bon Git !

C’est l’hallu ?

Vous vous rendez compte en lisant cet article que vous ne connaissez pas tout plein d’options sympa, voire de commandes utiles ?

Pourquoi ne pas venir donner un gros coup de fouet à votre compréhension de fond et vos compétences opérationnelles Git grâce à notre formation Git Total, la référence absolue du marché ?

Commentaires

Ils nous font confiance : Kelkoo, MisterGoodDeal, PriceMinister, Blablacar / Comuto, Sarenza, Voyages-SNCF, LeMonde.fr, Fnac DIRECT, 20minutes, Orange, l’OCDE, Cisco, Alcatel-Lucent, Dassault Systèmes, EADS, Atos, Lagardère Interactive, Lesieur, L’Occitane en Provence, Météo France, 4D, Securitas, Digitas, Vivaki, Fullsix, Ekino, TBWA \ Paris, Valtech, Is Cool Entertainment, Open Wide…