Question Git push rejeté après la fonctionnalité de rebase de branche


OK, je pensais que c'était un scénario simple, qu'est-ce qui me manque?

j'ai un master branche et un feature branche. Je fais du travail sur master, certains sur feature, et encore plus sur master. Je me retrouve avec quelque chose comme ça (l'ordre lexicographique implique l'ordre des commits):

A--B--C------F--G  (master)
       \    
        D--E  (feature)

Je n'ai aucun problème à git push origin master garder la télécommande master mis à jour, ni avec git push origin feature (quand on feature) pour maintenir une sauvegarde à distance pour mon feature travail. Jusqu'à maintenant, nous sommes bons.

Mais maintenant je veux rebaser feature au-dessus de la F--G commet sur le maître, donc je git checkout feature et git rebase master. Encore bon. Maintenant nous avons:

A--B--C------F--G  (master)
                 \
                  D'--E'  (feature)

Problème: le moment où je veux sauvegarder le nouveau rebasé feature ramifié avec git push origin feature, la poussée est rejetée puisque l'arbre a changé en raison du rebasage. Cela ne peut être résolu avec git push --force origin feature.

Je déteste utiliser --force sans être sûr que j'en ai besoin. Alors, j'en ai besoin? Est-ce que le rebasing nécessairement impliquent que le prochain push devrait être --forceful?

Cette branche de fonctionnalité n'est pas partagée avec d'autres développeurs, donc je n'ai aucun problème de facto avec la poussée de la force, je ne vais pas perdre de données, la question est plus conceptuelle.


627
2018-01-20 10:29


origine


Réponses:


Le problème est que git push suppose que la branche distante peut être redirigée rapidement vers votre branche locale, c'est-à-dire que toute la différence entre les branches locales et distantes est en local avec de nouveaux commits à la fin comme ça:

Z--X--R         <- origin/some-branch (can be fast-forwarded to Y commit)
       \        
        T--Y    <- some-branch

Lorsque vous effectuez git rebase commits D et E sont appliqués à la nouvelle base et de nouveaux commits sont créés. Cela signifie que, après le rebasage, vous avez quelque chose comme ça:

A--B--C------F--G--D'--E'   <- feature-branch
       \  
        D--E                <- origin/feature-branch

Dans cette situation, la branche distante ne peut pas être transférée rapidement en local. Bien que, théoriquement, la branche locale peut être fusionnée à distance (évidemment vous n'en avez pas besoin dans ce cas), mais comme git push n'effectue que des fusions rapides et des erreurs.

Et quoi --force L'option ignore simplement l'état de la branche distante et la place dans le commit que vous y insérez. Alors git push --force origin feature-branch remplace simplement origin/feature-branch avec local feature-branch.

À mon avis, rebasant des branches de fonctionnalité sur master et les forcer à les rediriger vers un référentiel distant est OK tant que vous êtes le seul à travailler sur cette branche.


454
2018-01-20 10:55



Au lieu d'utiliser -f ou --force les développeurs devraient utiliser

--force-with-lease

Pourquoi? Parce qu'il vérifie les changements dans la branche distante, ce qui est absolument une bonne idée. Imaginons que James et Lisa travaillent sur la même branche de fonctionnalité et que Lisa ait poussé un commit. James rebase maintenant sa branche locale et est rejeté en essayant de pousser. Bien sûr, James pense que cela est dû à rebaser et utilise --force et réécrirait tous les changements de Lisa. Si James avait utilisé --force-with-lease, il aurait reçu un avertissement qu'il y aurait des commits faits par quelqu'un d'autre. Je ne vois pas pourquoi quelqu'un utiliserait --force au lieu de --force-with-lease en poussant après un rebase.


194
2018-05-26 12:02



J'utiliserais plutôt "checkout -b" et c'est plus facile à comprendre.

git checkout myFeature
git rebase master
git push origin --delete myFeature
git push origin myFeature

Lorsque vous supprimez, vous empêchez d'insérer une branche existante contenant un ID SHA différent. Je supprime uniquement la branche distante dans ce cas.


27
2017-10-21 22:09



Une solution à cela est de faire ce que msysGit Rebaser la fusion script fait - après la rebase, fusionner dans l'ancien chef de feature avec -s ours. Vous vous retrouvez avec le graphique de validation:

A--B--C------F--G (master)
       \         \
        \         D'--E' (feature)
         \           /
          \       --
           \    /
            D--E (old-feature)

... et votre poussée de feature sera un rapide.

En d'autres termes, vous pouvez faire:

git checkout feature
git branch old-feature
git rebase master
git merge -s ours old-feature
git push origin feature

(Pas testé, mais je pense que c'est vrai ...)


19
2018-01-20 12:13



Il se peut qu'il n'y ait pas qu'un seul développeur sur cette branche, c'est-à-dire (après la rebase) pas en ligne avec l'origine / fonctionnalité.

En tant que tel, je suggère d'utiliser la séquence suivante:

git rebase master
git checkout -b feature_branch_2
git push origin feature_branch_2

Ouais, nouvelle branche, ceci devrait résoudre ceci sans un --force, qui je pense généralement est un inconvénient principal de git.


14
2017-10-28 07:36



D'autres ont répondu à votre question. Si vous rebassez une branche, vous devrez forcer pour pousser cette branche.

Rebase et un référentiel partagé ne s'entendent généralement pas. C'est réécrire l'histoire. Si d'autres utilisent cette branche ou se sont branchés à partir de cette branche, le rebasage sera assez désagréable.

En général, rebase fonctionne bien pour la gestion de succursale locale. La gestion à distance des branches fonctionne mieux avec les fusions explicites (--no-ff).

Nous évitons également de fusionner master dans une branche d'entité. Au lieu de cela, nous rebasons vers le master mais avec un nouveau nom de branche (par exemple en ajoutant un suffixe de version). Cela évite le problème de rebasage dans le référentiel partagé.


11
2018-01-20 16:29



Quel est le problème avec un git merge master sur le feature branche? Cela préservera le travail que vous avez eu, tout en le gardant séparé de la branche principale.

A--B--C------F--G
       \         \
        D--E------H

Modifier: Ah désolé n'a pas lu votre déclaration de problème. Vous aurez besoin de la force lorsque vous avez effectué un rebase. Toutes les commandes qui modifient l'historique auront besoin de --force argument. Ceci est une sécurité intégrée pour vous empêcher de perdre votre travail (l'ancien D et E serait perdu).

Donc vous avez effectué un git rebase qui a fait ressembler l'arbre (bien que partiellement caché comme D et E ne sont plus dans une branche nommée):

A--B--C------F--G
       \         \
        D--E      D'--E'

Donc, en essayant de pousser votre nouveau feature branche (avec D' et E' dedans), vous perdriez D et E.


8
2018-01-20 10:35



Ma façon d'éviter la poussée de force est de créer une nouvelle branche et de poursuivre le travail sur cette nouvelle branche et, après une certaine stabilité, de supprimer l'ancienne branche qui a été rebasée:

  • Rebaser la branche vérifiée localement
  • Branchement de la branche rebasée à une nouvelle branche
  • Poussant cette branche comme une nouvelle branche à distance. et en supprimant l'ancienne branche sur la télécommande

7
2018-06-19 07:00



Les travaux suivants pour moi:

git push -f origin branch_name

et cela ne supprime aucun de mon code.

Mais, si vous voulez éviter cela, vous pouvez faire ce qui suit:

git checkout master
git pull --rebase
git checkout -b new_branch_name

alors vous pouvez choisir tous vos engagements pour la nouvelle branche. git cherry-pick COMMIT ID puis poussez votre nouvelle branche.


2
2017-08-19 13:33



Comme le PO comprend le problème, il cherche juste une meilleure solution ...

Que diriez-vous de cela en tant que pratique?

  • Avoir sur la branche fonctionnalité-développement réelle (où vous ne jamais rebaser et pousser-pousser, de sorte que vos collègues développeurs de fonctionnalités ne vous détestent pas). Ici, saisissez régulièrement ces changements de main avec une fusion. L'histoire de MessierOui, mais la vie est facile et personne ne s'interrompt dans son travail.

  • Avoir une deuxième fonctionnalité-développer une branche, où un Le membre de l'équipe de fonctionnalité régulièrement pousse tous les engagements de fonctionnalité à, en effet rebasé, voire forcé. Donc presque proprement basé sur un commit maître assez récent. Une fois la fonction terminée, appuyez sur cette branche sur le maître.

Il se peut qu'il existe déjà un nom de modèle pour cette méthode.


1
2017-09-25 09:57