myflec: un framework de dotfiles Bash pour gens qui déploient leur home
Mon $HOME est versionné, déployé depuis des templates et poussé vers trois forges. Pas parce que j’aime le yak-shaving, mais parce que j’ai cassé trop de machines pour faire confiance à “ça devrait aller”. myflec
(“My Favorite Linux Environment Configuration”) est le framework Bash né de cette habitude: un loader, un modèle de backup, une procédure de deploy et un modèle d’identité. Tout est ennuyeux exprès, tout est shell natif.
La vieille base
Ce n’est pas un projet jeune. Le compte GitHub qui le porte a été créé en septembre 2011 et les habitudes sont plus vieilles que le nom. L’ancêtre survivant le plus net, c’est vim-apthogen
(2016): un netinstall en curl | bash qui bootstrapait tout un ~/.vim par symlinks, piloté par des listes déclaratives à paliers (.apthogen.list, puis .required.list, .minimal.list, .highly.list, .recomended.list, .whynot.list) et des menus d’installation. La signature d’auteur de l’époque est visible dans chaque script: un header heredoc Version / Authors / Description / Dependencies et un .vimrc qui portait déjà command W w !sudo tee et command Q qa, les mêmes alias que la config de 2018 gardait et que l’actuelle a toujours.
myflec est la forme actuelle de cette lignée: déclarer ce qu’on veut dans des listes, laisser un script bootstrap, dégrader gracieusement quand il manque un truc. Ce qui a changé: la cible (~/.bashrc.d et $HOME au lieu de ~/.vim), le modèle de backup (un repo bare git au lieu des symlinks) et quinze ans de discipline de deploy accumulée. Les principes n’avaient pas besoin d’être inventés; ils avaient besoin d’une passe de supervision adulte.
Le loader: core d’abord, outils après
~/.bashrc.d/ est un répertoire de modules et le loader les source dans un ordre qui compte:
for _myflec_file in "$HOME"/.bashrc.d/_*.bash; do
_myflec_load "$_myflec_file"
done
for _myflec_file in "$HOME"/.bashrc.d/*.bash; do
case "$(basename "$_myflec_file")" in _*) continue ;; esac
_myflec_load "$_myflec_file"
done
Les modules préfixés par underscore sont le core: helpers, environnement, la fonction de chargement elle-même. Ils chargent d’abord pour que tous les modules suivants puissent s’en servir. Puis les modules outils chargent par ordre alphabétique et chaque outil optionnel est gardé par command -v starship >/dev/null 2>&1 pour qu’une machine sans l’outil dégrade gracieusement au lieu d’imprimer quatre erreurs à chaque prompt. Pas de variables de framework qui fuient: le loader unset sa propre fonction à la fin.
Le backup: un repo bare dans votre home
Le classique, formalisé: git --git-dir=$HOME/.dotfiles --work-tree=$HOME. Vos dotfiles vivent dans un repo bare dont le work tree est votre home; git status ne montre que les fichiers trackés, rien ne bouge. Par-dessus, myflec livre les commandes que je voulais vraiment:
dotfiles-backup "message": add, commit, push en une étape.dotfiles-addbackup <url>/dotfiles-removebackup: des push URLs pour plusieurs forges (le repo est répliqué vers GitHub, GitLab et NotABug; perdre une forge ne perd pas les dotfiles).dotfiles-init <url> [extra-push-urls]: bootstrap d’une machine neuve depuis rien.
Le deploy: dry run, backup, vérification
Déployer un template de dotfiles sur une machine est une opération destructive, donc la procédure myflec deploy est structurée comme les règles globales que j’utilise partout: dry run d’abord contre la vraie cible avec la liste de transfert complète lue sans filtre, backup automatique de tout ce qui sera écrasé (rsync --backup vers un répertoire de backup), puis vérification post-déploiement que la fonction marche toujours: ssh -G <host> après un changement de config SSH, git config user.email après un changement de git config. Écraser un .ssh/config vivant sans chemin de retour arrière, ce n’est pas un deploy, c’est un pari.
Les secrets ne voyagent jamais: les fichiers d’identité et templates (.gitconfig, .gitconfig.d) restent dehors via myflec.exclude.lst et le matériel secret vit dans .ssh/ plus un env géré par fnox
, jamais dans l’arbre tracké.
Le modèle d’identité: une identité par arbre de projets
La partie que j’utilise le plus est aussi celle qui a la plus longue section du README: jongler avec les identités pro et perso. La pile:
git includeIf "gitdir:~/projets/company/"dans.gitconfigchoisit l’identité par préfixe de répertoire; un répertoire.gitconfig.d/contient un fichier par identité.- Les alias d’hôtes SSH (
github.com-work) routent chaque remote vers la bonne clé. - Le README documente la matrice complète (répertoire projet, identité git, remote SSH) avec un diagramme Mermaid, parce que le jour où vous avez trois forges et deux employeurs, “quelle clé a signé ce push” demande une image.
Le housekeeping comme CI
Deux petites touches qui gardent le framework honnête: un assets/demo.tape VHS
régénère le GIF de démo du README en CI (demo.yml) dès que la config change, pour que la doc ne mente jamais et lint.yml garde les scripts shellcheck-clean. Un repo de dotfiles sans CI est un repo qu’on cesse de croire en année deux.
Mon home, versionné
- L’ordre est une fonctionnalité. Les modules core qui chargent avant les outils, c’est ce qui rend le reste composable.
- L’astuce bare-git est le seul modèle de backup que je n’ai jamais abandonné: pas de danse de symlinks, pas de scripts d’install, la sémantique git jusqu’au bout.
- Deploy = dry run + backup + check fonctionnel. Le succès au niveau fichier n’est pas le succès.
- Les identités appartiennent aux arbres, pas aux machines.
includeIfpasse à l’échelle des projets; l’identité globale de.gitconfigne passe pas à l’échelle de la vraie vie.
[edit: 2026] L’implémentation Ansible de tout ceci: le rôle myflec .