«Git pull» peut-il automatiquement cacher et afficher les modifications en attente?

122

Je sais comment résoudre ça:

user@host$ git pull
Updating 9386059..6e3ffde
error: Your local changes to the following files would be overwritten by merge:
    foo.bar
Please, commit your changes or stash them before you can merge.
Aborting

Mais n'y a-t-il pas moyen de laisser git pullfaire stashet popdanser pour moi?

Si cette commande a un nom différent, c'est ok.

Créer un alias shell pour git stash; git pull; git stash popest une solution, mais je recherche une meilleure solution.

guettli
la source
qu'en est-il d'un alias git ?
Яois
20
L'exécution par git stash; git pull; git stash popprogramme est dangereuse, car s'il n'y a rien à cacher, ce git stashsera une non-opération, mais git stash popfera apparaître la dernière réserve (le cas échéant), ce qui n'est presque certainement pas ce que vous voulez. L'utilisateur torek a un excellent article à ce sujet sur Stack Overflow, mais je ne le trouve pas ...
jub0bs
1
@guettli Je n'impliquais pas que votre question était un double, je répondais simplement au commentaire de Jubobs.
VonC
2
En outre, l'opération ne devrait réussir que si la réserve peut être appliquée proprement après la traction. S'il y a des conflits, alors l'opération entière échoue de manière atomique afin que l'arborescence ne soit pas modifiée. C'est ce que je voudrais faire: soit abattre les modifications avec mes modifications locales fusionnées, soit échouer avec une erreur et me laisser décider manuellement quoi faire ensuite. Est-ce que ce genre de 'transaction' git est possible?
Ed Avis

Réponses:

185

Pour Git 2.6+ (publié le 28 septembre 2015)

le seulement git config réglage qui serait intéressant est:

rebase.autoStash

(avec Git 2.27, Q2 2020, vous avez maintenant aussi merge.autostash, voir ci-dessous)

Lorsqu'il est défini sur true, crée automatiquement une réserve temporaire avant le début de l'opération et l'applique une fois l'opération terminée.
Cela signifie que vous pouvez exécuter le rebase sur un arbre de travail sale.

Cependant, à utiliser avec précaution: l'application de cache finale après un rebase réussi peut entraîner des conflits non triviaux. La valeur par défaut est false.

combinez cela avec:

pull.rebase

Quand c'est vrai, rebase les branches au-dessus de la branche récupérée, au lieu de fusionner la branche par défaut de la télécommande par défaut lorsque "git pull" est exécuté.

git config pull.rebase true
git config rebase.autoStash true

Cela suffirait pour un simple git pullà travailler même dans un arbre sale.
Aucun alias nécessaire dans ce cas.


Voir commit 53c76dc (04 juillet 2015) par Kevin Daudt ( Ikke) .
(Fusionné par Junio ​​C Hamano - gitster- in commit e69b408 , 17 août 2015)

pull: autoriser l'arbre sale lorsqu'il est rebase.autostashactivé

rebase a appris à cacher les modifications lorsqu'il rencontre un arbre de travail sale, mais git pull --rebasene le fait pas.

Vérifiez uniquement si l'arborescence de travail est sale lorsque rebase.autostashn'est pas activé.


Remarque: si vous voulez tirer sans autostash (même si elle rebase.autoStash trueest définie), vous avez depuis git 2.9 (juin 2016):

 pull --rebase --no-autostash

Voir commit 450dd1d , commit 1662297 , commit 44a59ff , commit 5c82bcd , commit 6ddc97c , commit eff960b , commit efa195d (02 avril 2016) et commit f66398e , commit c48d73b (21 mars 2016) par Mehul Jain ( mehul2029) .
(Fusionné par Junio ​​C Hamano - gitster- in commit 7c137bb , 13 avril 2016)

Commit f66398e comprend notamment:

pull --rebase: ajouter un --[no-]autostashindicateur

Si la rebase.autoStashvariable de configuration est définie, il n'y a aucun moyen de la remplacer pour " git pull --rebase" à partir de la ligne de commande.

Apprenez " git pull --rebase" l' --[no-]autostashindicateur de ligne de commande qui remplace la valeur actuelle de rebase.autoStash, s'il est défini. Comme " git rebase" comprend l' --[no-]autostashoption, c'est juste une question de passer l'option au " git rebase" sous-jacent quand " git pull --rebase" est appelé.


Attention: avant Git 2.14 (Q3 2017), " git pull --rebase --autostash" ne se cachait pas automatiquement lorsque l'histoire locale passait rapidement à l'amont.

Voir commit f15e7cf (01 juin 2017) par Tyler Brazier ( tylerbrazier) .
(Fusionné par Junio ​​C Hamano - gitster- dans commit 35898ea , 05 juin 2017)

pull: ff --rebase --autostashfonctionne dans le repo sale

Lorsqu'un git pull --rebase --autostashdépôt sale entraînait une avance rapide, rien n'était autostashé et l'extraction échouait.
Cela était dû à un raccourci pour éviter d'exécuter le rebase lorsque nous pouvons avancer rapidement, mais l'autostash est ignoré sur ce chemin de code.


Mise à jour: Mariusz Pawelski pose dans les commentaires une question intéressante:

Donc tout le monde écrit sur le autostashmoment où vous effectuez un rebase (ou pull --rebase).

Mais personne ne se préoccupe de l'autostashing lorsque vous effectuez une traction normale avec des fusions .
Il n'y a donc pas de commutateur automatique pour cela? Ou je manque quelque chose? Je préfère faire git pull --rebasemais OP a posé des questions sur git pull " standard "

Répondre:

Le fil de discussion original traitant de cette fonction d'autostash, il a été implémenté à l'origine à la fois pour git pull(fusion) et git pull --rebase.

Mais ... Junio ​​C Hamano (mainteneur de Git) a noté que:

S'il y pull-mergeavait quelque chose qui induirait le "désagrément" qui a déclenché ce sujet, par définition, le changement local chevauche la fusion, et ce "pop caché" interne touchera les chemins touchés par la fusion et il ne sera probablement pas le résultat de "Supprimé "mais laissez les conflits à résoudre.

Je soupçonne que la pull.autostashconfiguration n'est pas un bon ajout car elle encourage un mauvais flux de travail induisant une douleur.
Dans les cas simples, cela peut ne pas faire de mal, mais lorsque les changements locaux sont complexes, cela ferait beaucoup de mal que de ne pas l'avoir, et la configuration prive de l'incitation à choisir.

L'équation est quelque peu différente pour "pull-rebase", car "rebase" vous insiste pour commencer à partir d'un arbre de travail propre, donc la gêne "télécharger puis arrêter" semble plus grande. Je soupçonne que le relâchement pourrait être une solution plus productive au problème réel.

Donc, concernant un pull-merge classique, il vaut mieux:

encouragez l'utilisateur à réfléchir à la nature du WIP qu'il a dans l'arborescence de travail avant d'exécuter " git pull" .
Est-ce une bête trop complexe qui peut interférer avec ce que font les autres, ou est-ce un changement insignifiant qu'il peut cacher et le faire revenir?

Si le premier, il sera bien mieux de faire " checkout -b", continuez à travailler jusqu'à ce que le changement local prenne une forme un peu meilleure et "commit", avant de tirer dans la branche d'origine.

Dans ce dernier cas, il vaut mieux faire:

  • " git pull",
  • après avoir trouvé des conflits, exécutez
    • git stash,
    • git merge FETCH_HEAD et
    • git stash pop

Cela étant dit, avec Git 2.27 (Q2 2020), " git pull" a appris à avertir lorsqu'aucune pull.rebaseconfiguration n'existe, et ni --[no-]rebaseni --ff-onlyn'est donné (ce qui entraînerait une fusion).

Voir commit d18c950 (10 mars 2020) par Alex Henrie ( alexhenrie) .
(Fusionné par Junio ​​C Hamano - gitster- dans commit 1c56d6f , 27 mars 2020)

pull: avertir si l'utilisateur n'a pas dit s'il fallait rebaser ou fusionner

Signé par: Alex Henrie

Souvent, les utilisateurs novices de Git oublient de dire " pull --rebase" et se retrouvent avec une fusion inutile en amont.

Ce qu'ils veulent généralement, c'est " pull --rebase" dans les cas les plus simples, ou " pull --ff-only" mettre à jour la copie des branches d'intégration principales et rebaser leur travail séparément.
La pull.rebasevariable de configuration existe pour les aider dans les cas les plus simples, mais il n'existe aucun mécanisme pour en informer ces utilisateurs.

Émettez un message d'avertissement lorsqu'aucune --[no-]rebaseoption de la ligne de commande et aucune pull.rebasevariable de configuration n'est donnée.
Cela gênera ceux qui ne veulent jamais " pull --rebase", qui n'ont rien eu à faire de spécial, mais le coût des inconvénients n'est payé qu'une seule fois par utilisateur, ce qui devrait être un coût raisonnable pour aider un certain nombre de nouveaux utilisateurs.


Avec Git 2.27 (Q2 2020), " git merge" apprend l' --autostashoption " " et le nouveau merge.autostashparamètre.

Voir commettre d9f15d3 , engager f8a1785 , engager a03b555 , engager 804fe31 , engager 12b6e13 , commettre 0dd562e , commettre 0816f1d , commettre 9bb3dea , commettre 4d4bc15 , engager b309a97 , engager f213f06 , engager 86ed00a , engager facca7f , engager be1bb60 , engager efcf6cf , engager c20de8b , commit bfa50c2 , commit 3442c3d , commit 5b2f6d9 (07 avril 2020), commit 65c425a(04 avril 2020), et commit fd6852c , commit 805d9ea (21 mars 2020) par Denton Liu ( Denton-L) .
(Fusionné par Junio ​​C Hamano - gitster- dans commit bf10200 , 29 avril 2020)

pull: passer --autostash pour fusionner

Signature par: Denton Liu

Avant, --autostashseulement travaillé avec git pull --rebase.

Cependant, dans le dernier patch, la fusion a également été apprise --autostash, il n'y a donc aucune raison pour que nous ayons plus cette restriction.
Apprenez à tirer pour passer --autostashpour fusionner, comme pour le rebase.

Et:

rebase: utiliser apply_autostash()depuis sequencer.c

Signature par: Denton Liu

La apply_autostash()fonction in builtin/rebase.cest assez similaire à la apply_autostash()fonction en sequencer.cce sens qu'ils sont presque interchangeables, sauf pour le type d'argument qu'ils acceptent. Rendez la sequencer.cversion externe et utilisez-la dans rebase.

La version rebase a été introduite dans 6defce2b02 ("rebase intégré: --autostashoption de support ", 04/09/2018, Git v2.20.0-rc0 - fusion répertoriée dans le lot # 8 ) dans le cadre de la conversion du shell en C.
Il a choisi de dupliquer la fonction car, à l'époque, il y avait un autre projet en cours de conversion du rebase interactif du shell vers C également et ils ne voulaient pas entrer en conflit avec eux en refactorisant la sequencer.cversion de apply_autostash().
Puisque les deux efforts sont accomplis depuis longtemps, nous pouvons maintenant les combiner librement.

VonC
la source
Depuis 2.4.2, cela n'est pas encore implémenté. Peut-être un jour. rebase.autoStashs'applique uniquement lors de l'utilisation de rebase. pull.rebases'applique uniquement lors de l'utilisation de pull.
Randal Schwartz
"Ce serait suffisant pour qu'un simple git pull fonctionne même dans un arbre sale." Comme Randal l'a commenté, ce n'est pas encore vrai. Le pull.c du maître actuel choisit toujours de die_on_unclean_work_tree.
Pradhan
1
@Pradhan Je suis d'accord. L'implémentation vient juste d'arriver en master ce matin et devrait être prête pour git 2.6. J'ai modifié la réponse pour que cela soit clair.
VonC
J'ai confirmé qu'autostash fonctionne avec git 2.5.5.
Joshua Hoblitt
1
Donc, tout le monde écrit sur l'autostash quand vous le faites rebase(ou pull --rebase). Mais personne ne se préoccupe de l'autostashing lorsque vous faites normalement pulldes fusions. Il n'y a donc pas de commutateur automatique pour cela? Ou je manque quelque chose? Je préfère faire git pull --rebasemais OP a posé des questions sur "standard"git pull
Mariusz Pawelski
41

Pour gagner quelques secondes pour les explorateurs à venir, voici un résumé (merci à @VonC):

git pull --rebase --autostash
Vitaliy Ulantikov
la source
6
Le fait est: après un git config pull.rebase trueet git config rebase.autoStash true, tout ce dont vous aurez besoin est git pull. Juste git pull. Aucune autre option requise.
VonC
3
Il semble que vous ayez besoin d'au moins Git 2.9 pour l' --autostashoption. Les -c rebase.autoStash=truetravaux dans Git 2.6 et versions ultérieures.
ntc2
15

Comme indiqué dans le commentaire ci-dessus, la définition des deux valeurs de configuration ne fonctionne pas actuellement git pull, car la configuration d'autostash ne s'applique qu'aux rebases réels. Ces commandes git font ce que vous voulez:

git fetch
git rebase --autostash FETCH_HEAD

Ou définissez-le comme un alias:

git config alias.pullr '!git fetch; git rebase --autostash FETCH_HEAD'

Alors fais:

git pullr

Bien entendu, cet alias peut être renommé à volonté.

user397114
la source
7

Avec Git 2.6+, vous pouvez utiliser les éléments suivants:

alias gup='git -c rebase.autoStash=true pull --rebase'

Cela --rebaserend l'utilisation de git-pull à la rebaseplace de merge, donc les paramètres / options comme --ff-onlyne s'appliquent pas.

J'utilise un alias pour tirer avec --ff-onlypar défaut ( git pull --ff-only), et je peux ensuite utiliser gup(d'en haut) au cas où une fusion à avance rapide n'est pas possible ou s'il y a des modifications cachées.

bleui
la source
Quelle est la principale différence entre git pull --ff-onlyetgit pull pull --rebase --autostash
alper le
0

Comme vous l'avez déjà mentionné, c'est la façon de procéder. Vous pouvez l'utiliser dans un alias pour vous éviter de taper et utiliser un raccourci ou vous pouvez l'utiliser sur une seule ligne (peut également être un alias)

git stash && git pull --rebase && git stash pop

Il fera la même chose que vous, mais en une seule ligne (&&) et si vous le définissez comme alias, il sera encore plus court.

Les lignes suivantes afficheront les changements entrants / sortants avant de tirer / pousser

git log ^master origin/master
git log master ^origin/master
CodeWizard
la source
8
Cette approche n'est pas sûre: s'il n'y a rien à cacher, la première commande ne fera rien, puis stash popsupprimera des éléments aléatoires d'avant.
John Zwinck
Juste pour être très clair: même s'il git stashne cache rien, il ne "retourne" toujours aucun code d'erreur, donc le && continuera toujours avec git pullet git stash popet affichera un cache précédent. Il vaut donc mieux ne pas l'utiliser à moins d'être sûr que cela cachera quelque chose!
MoonLite