HOWTO · Git
Git Push --force-with-lease contre Git Push --force
Dans cet article, nous discuterons de la différence entre les commandes git push --force-with-lease et git push --force.
Sur cette page
Lorsqu’un rebase ou un amend modifie des commits déjà publiés, un push normal peut être rejeté, car la branche distante ne peut plus avancer directement depuis votre branche locale. git push --force et git push --force-with-lease peuvent tous deux remplacer la pointe de la branche distante. La différence tient à la vérification par Git d’une valeur distante attendue avant la mise à jour. Pour une réécriture intentionnelle, préférez la forme avec lease, puis examinez et réconciliez l’état distant si Git rejette le push.
Fonctionnement de git push --force
Un push normal protège les commits distants en exigeant que la mise à jour fasse avancer la branche. git push --force désactive cette protection pour la référence poussée : la branche distante est définie sur le commit que vous indiquez, même si cela retire des commits de son historique visible. Si un membre de l’équipe a poussé du travail que vous n’avez pas intégré, celui-ci risque de devenir inaccessible depuis cette branche.
La commande agit sur la destination indiquée. Par exemple, git push --force origin feature cible la branche feature sur origin ; sans nom de branche explicite, la référence modifiée peut être moins évidente. N’utilisez cette option que si le remplacement de l’historique de la branche est intentionnel et coordonné avec toutes les personnes qui l’utilisent. Un push forcé ne crée pas de conflit de fusion et ne combine pas les commits distants à votre place.
Fonctionnement de git push --force-with-lease
git push --force-with-lease origin feature autorise lui aussi une mise à jour qui ne peut pas avancer directement, mais vérifie d’abord que la branche distante a toujours la valeur attendue. Dans le cas courant, Git déduit cette valeur de la référence locale de suivi distant, par exemple origin/feature. Si la valeur de la branche sur le serveur est différente, Git rejette la mise à jour au lieu de la remplacer.
Cette vérification est utile, mais ne prouve pas que personne n’a poussé du travail que vous n’avez pas vu. Si une récupération en arrière-plan met à jour origin/feature après votre dernier examen, le lease par défaut peut accepter une réécriture fondée sur cette nouvelle valeur récupérée. Indiquer explicitement l’identifiant d’objet attendu rend la comparaison plus délibérée : git push --force-with-lease=refs/heads/feature:<expected-object-id> origin HEAD:refs/heads/feature. Dans le cadre de votre méthode de travail en équipe, obtenez et vérifiez la valeur attendue ; ne copiez pas un identifiant sans vérifier ce qu’il désigne.
Utiliser --force-with-lease après une réécriture de l’historique
Supposons que la branche partagée soit A---B---C, qu’un collaborateur ajoute D après C et que vous rebasiez votre travail local pour obtenir A---B---C'. Votre C' local et le D distant correspondent alors à deux pointes différentes. Le lease vise à vous empêcher de remplacer silencieusement D si l’état distant que vous vous attendiez à trouver est toujours C.
Commencez par examiner la branche et récupérer son état actuel. Décidez ensuite si le commit du collaborateur doit faire partie de votre historique réécrit. Vous pouvez rebaser votre travail sur la branche récupérée ou convenir avec l’équipe d’une autre méthode d’intégration. Une fois l’historique résolu et vérifié, poussez le résultat voulu avec un lease. Si le lease rejette le push, récupérez et examinez de nouveau l’état distant ; ne réessayez pas immédiatement avec --force.
Exécutez cette démonstration autonome pour créer une branche locale, la publier dans un dépôt temporaire sans répertoire de travail, modifier sa pointe avec amend, puis la mettre à jour avec un lease :
set -e
root="$(mktemp -d)"
trap 'rm -rf "$root"' EXIT
git init --bare "$root/remote.git" >/dev/null 2>&1
git init -b feature "$root/work" >/dev/null 2>&1
cd "$root/work"
git config user.name "Example Developer"
git config user.email "developer@example.com"
printf 'first version\n' > README.md
git add README.md
git commit -m "Add first version" >/dev/null 2>&1
git remote add origin "$root/remote.git"
git push -u origin feature >/dev/null 2>&1
git commit --amend -m "Rewrite first version" >/dev/null 2>&1
git push --force-with-lease origin feature >/dev/null 2>&1
Les chemins sont temporaires et le script supprime son environnement de démonstration à la fin. Dans un vrai dépôt, examinez les commits et coordonnez-vous avec les personnes concernées avant de remplacer un historique partagé.
Choisir une option de push forcé en toute sécurité
Pour une branche personnelle sans collaborateurs, un push forcé direct peut convenir si le remplacement de sa pointe distante est bien voulu. Sur une branche partagée, choisissez --force-with-lease après avoir vérifié l’état distant attendu et coordonné la réécriture. Si cela permet d’éviter de réécrire une branche partagée, préférez une pull request ou un autre processus de revue.
Indiquez explicitement le dépôt distant et la branche, récupérez l’état distant avant de décider et examinez le graphe des commits avant de pousser. Un rejet du lease est un signal de prudence : comparez votre branche locale à la branche distante récupérée, conservez les commits nécessaires et ne réessayez qu’après avoir décidé comment les intégrer. Des synchronisations régulières réduisent les surprises, mais ne remplacent pas l’examen de l’historique que le push va publier.
Récupérer ou prévenir la perte de commits
Si un push forcé a retiré un commit de la pointe de la branche, cessez les opérations de nettoyage et recherchez une référence qui l’a conservé. Dans votre clone local, git reflog peut afficher des positions récentes de la branche ; le clone d’un autre membre de l’équipe, une sauvegarde distante ou une fonction de récupération de l’hébergeur peut également contenir ce commit. Si vous le retrouvez, créez une branche à partir de celui-ci avant de décider comment le restaurer ou l’intégrer. Les entrées du reflog expirent et restent locales : la récupération n’est donc pas garantie.
Pour prévenir les pertes, convenez des personnes autorisées à réécrire une branche partagée, informez les collaborateurs avant la mise à jour et conservez une référence connue lorsqu’une réécriture doit être examinée. Un lease réduit une catégorie d’écrasements accidentels ; une coordination claire et un point de récupération vérifié couvrent les risques qu’il ne peut pas détecter.
Questions fréquentes
Quelle est la différence entre git push --force et git push --force-with-lease ? La première commande remplace la référence distante sans vérifier sa valeur actuelle. La seconde vérifie une valeur attendue et rejette la mise à jour si la valeur distante ne lui correspond pas.
Quand puis-je utiliser git push --force ? Utilisez cette commande uniquement si vous comptez remplacer la pointe de la branche cible, comprenez quels commits risquent de ne plus figurer sur cette branche et vous êtes coordonné avec les collaborateurs concernés. Pour un travail partagé, préférez un lease et examinez l’état attendu.
Un push forcé est-il dangereux sur une branche partagée ? Il peut rendre des commits invisibles depuis la branche et perturber le travail des collaborateurs. Un lease aide lorsque la valeur distante diffère de la valeur attendue, mais une récupération que vous n’avez pas examinée peut mettre à jour la valeur attendue par défaut.
Comment réduire les conflits et les mauvaises surprises ? Récupérez et examinez l’état distant, intégrez les commits des collaborateurs à l’historique réécrit lorsque c’est approprié, communiquez le plan et utilisez des processus de revue pour les changements partagés.
Puis-je annuler un push forcé ? Il n’existe pas d’annulation automatique. Vous pourrez peut-être retrouver le commit précédent dans un reflog, un autre clone ou une fonction de récupération de l’hébergeur, puis créer une référence et coordonner sa restauration. Cela dépend de la présence d’une référence qui pointe encore vers ce commit.