push --force-with-bail par défaut

130

Je viens d'apprendre git push --force-with-lease. C'est assez génial. Mais, bien sûr, je n'utilise pas la force si souvent, et j'ai donc peur d'oublier cette fonctionnalité astucieuse la prochaine fois que j'en aurai besoin.

Existe-t-il un moyen de configurer git afin git push -fqu'il l'utilise automatiquement à --force-with-leasemoins que je ne le remplace intentionnellement avec --no-force-with-lease?

(Je ne peux pas imaginer vouloir jamais utiliser la force sans bail!)

Dan Fabulich
la source

Réponses:

141

AFAIK il n'y a pas de configuration disponible pour dire à git de toujours utiliser à la force-with-leaseplace de force. Cela semble être un bon exemple de demande de fonctionnalité; si vous n'avez aucun problème pour plonger dans la base de code git, vous pouvez l'implémenter vous-même et le soumettre pour examen.

EDIT Dans l'état actuel des choses, cela est toujours vrai en avril 2019.

Jusque-là, la seule option que je vois est, comme si souvent, de créer un aliasqui sert cet objectif.

Créer un alias

Pour créer un alias, on utiliserait git config --global alias.<alias-name> <command>, dans notre cas, je suggérerais quelque chose de similaire.

git config --global alias.pushf "push --force-with-lease"

Cela créera une entrée dans votre .gitconfigfichier global (que vous pouvez généralement trouver dans votre répertoire personnel ). Après cela, vous pouvez simplement utiliser git pushfpour forcer avec bail .

Mets tes mains sales

Si vous souhaitez implémenter la fonctionnalité vous-même mais que vous ne savez pas par où commencer, vous devez d'abord jeter un œil au répertoire de documentation dans le référentiel git . Vous trouverez ici les instructions de codage et des informations sur la manière de soumettre des correctifs .

Vous pouvez trouver tous ces liens et plus encore sur la page officielle de la communauté .

Sascha Wolf
la source
25
Une note sur ce n'est pas une fonctionnalité: l'argument commun contre la réécriture des commandes standard ("push --force") est que vous vous y habituez, oubliez leur origine, et un jour les utilisez accidentellement de cette manière sur un nouveau système. Tout comme l' aliasing rmà rm -ivotre .bashrc; vous oublierez et supprimerez un jour un fichier important sur un serveur. Aller avec votre propre alias n'a pas ce problème :)
hraban
2
Anecdote personnelle / mot d'avertissement: j'ai essayé de l'aliaser pushfmais j'ai toujours vérifié que je ne faisais pas de push -f, car il ressemblait à l'alias. Certains membres de l'équipe utilisaient de push -ftoute façon, pensant que l'alias n'était qu'un raccourci cosmétique pour cela. En fin de compte, nous avons aliasé la forme la plus sûre à la pushflplace et avons cessé de nous en préoccuper.
kelvin le
31

J'ai peur d'oublier cette fonctionnalité astucieuse la prochaine fois que j'en aurai besoin.

Git 2.13 (Q2 2017) explique pourquoi il n'y a pas de "protection" contre l'oubli de cette option push, car même si vous ne l' oubliez pas au git pushniveau, elle risque d'être ignorée.

Voir commit f17d642 (19 avril 2017) par Ævar Arnfjörð Bjarmason ( avar) .
(Fusionné par Junio ​​C Hamano - gitster- in commit 46bdfa3 , 26 avril 2017)

push: document et test --force-with-leaseavec plusieurs télécommandes

Document et test pour les cas où il y a deux télécommandes pointant vers la même URL, et une récupération en arrière-plan et les suivantes git push --force-with-leasene devraient pas écraser les références non mises à jour que nous n'avons pas récupérées.

Certains éditeurs comme le VSC de Microsoft ont une fonction de récupération automatique en arrière-plan, ce qui contourne les protections offertes par --force-with-lease&--force-with-lease=<refname> , comme indiqué dans la documentation ajoutée ici.

Donc, la documentation pour l'git push instant comprend:

note générale sur la sécurité: fournir cette option sans valeur attendue, c'est à dire as --force-with-leaseou --force-with-lease=<refname> interagit très mal avec tout ce qui tourne implicitement git fetchsur la télécommande pour être poussé en arrière-plan, par exemple git fetch origin sur votre référentiel dans un cronjob.

La protection qu'il offre --forcegarantit que les modifications ultérieures sur lesquelles votre travail n'était pas basé ne sont pas écrasées, mais cela est trivialement vaincu si un processus d'arrière-plan met à jour les références en arrière-plan. Nous n'avons rien d'autre que les informations de suivi à distance à utiliser comme heuristique pour les références que vous êtes censé avoir vues et que vous êtes prêt à écraser.

Si votre éditeur ou un autre système s'exécute git fetchen arrière-plan pour vous, un moyen d'atténuer ce problème consiste simplement à configurer une autre télécommande:

git remote add origin-push $(git config remote.origin.url)
git fetch origin-push

Maintenant, lorsque le processus d'arrière-plan s'exécute, git fetch originles références origin-pushne seront pas mises à jour, et donc les commandes telles que:

git push --force-with-lease origin-push

Échouera sauf si vous exécutez manuellement git fetch origin-push.
Cette méthode est bien sûr entièrement vaincue par quelque chose qui s'exécute git fetch --all, dans ce cas, vous devrez soit la désactiver, soit faire quelque chose de plus fastidieux comme:

git fetch              # update 'master' from remote
git tag base master    # mark our base point
git rebase -i master   # rewrite some commits
git push --force-with-lease=master:base master:master

C'est-à-dire créer une basebalise pour les versions du code en amont que vous avez vues et que vous souhaitez écraser, puis réécrire l'historique, et enfin forcer les modifications à savoir mastersi la version distante est toujours à base, indépendamment de ce que votre local remotes/origin/mastera été mis à jour dans le Contexte.

VonC
la source
30

Ma solution était de créer un script wrapper et d'utiliser un alias pour que je l'utilise toujours à la place du réel git.

Chaque fois que j'essaye git push -f, je vois ce qui suit:

⚡ git push -f
use this instead so you don't cause race conditions in the 
repo: git push --force-with-lease

Certains avantages de ce script sont:

  • ça m'entraîne à utiliser habituellement --force-with-lease, donc je ne me fais pas harceler quand je me trompe
  • si, pour une raison quelconque, nous devons vraiment forcer la poussée, git push --forcecela fonctionnera.

Comment l'implémenter:

  1. créer un script personnalisé qui passera par tous les paramètres à git, sauf pour -f
  2. alias ce script donc nous l'utilisons au lieu de git

Ces instructions supposent Linux ou Mac, exécutant bash. Je n'ai pas essayé cela avec zsh ou Windows, mais je suppose que cela fonctionnera là aussi.

~/.bash_profile:

alias git=~/.git_wrapper.sh

~./git_wrapper.sh:

#!/bin/bash
for arg in "$@"; do
    if [ "$arg" = "push" ]; then
        ispush=1
    elif [ "$ispush" = 1 -a "$arg" = '-f' ]; then
        echo "use this instead so you don't cause race conflicts in the repo: git push --force-with-lease"
        exit 1
    fi
done

git "$@"

Avec ces changements, redémarrez votre terminal et gitdevrait maintenant être à la hauteur lorsque vous essayez de forcer le push.

Jessica Knight
la source
17
Cela semble pratique. +1. Peut-être remplacer «hey idiot» par «hey, you sweet but simple soul» ou quelque chose comme ça;)
VonC
5

Pour les personnes utilisant OMYZSH, vous pouvez simplement utiliser ggfl.

Nicolas
la source
3

Je veux qu'on me rappelle que je ne devrais pas utiliser -f, mais je ne veux pas être dupe en pensant que cela -fsignifie --force-with-lease. Voici donc mon avis:

git() {
  if [[ $@ == 'push -f'* ]]; then
    echo Hey stupid, use --force-with-lease instead
  else
    command git "$@"
  fi
}

Ajoutez à votre .bash_profile, .bashrcou .zshrc.

neu242
la source
1

Vous pouvez créer une fonction bash qui remplace gitet utilise à la --force-with-leaseplace de--force

# replaces `git push --force` with `git push --force-with-lease`
git() {
  if [[ $@ == 'push -f'* || $@ == 'push --force'* ]]; then
    command git push --force-with-lease
  else
    command git "$@"
  fi
}

ou, sur une seule ligne:

git() { if [[ $@ == 'push -f'* || $@ == 'push --force'* ]]; then command git push --force-with-lease; else command git "$@"; fi; }

Ajoutez-le simplement à votre fichier ~/.bashrcou ~/.zshrc.

paulodiovani
la source