web-dev-qa-db-fra.com

git rebase et git Push: avance non rapide, pourquoi utiliser?

J'ai une succursale qui devrait être disponible pour les autres contributeurs et qui devrait constamment rester à jour avec le maître.

Malheureusement, chaque fois que je fais "git rebase" et que j'essaie ensuite de pousser, cela entraîne un message "d'avance non rapide" et un avortement de la poussée. La seule façon de pousser ici est d'utiliser --force. Cela signifie-t-il que je devrais utiliser 'git merge' au lieu de rebaser si ma branche est devenue publique et que d'autres y travaillent?

68
snitko

Quelques notes sur le fonctionnement de git (non technique):

Lorsque vous rebasez, git prend les commits en question et les "réengage" en plus d'un historique clair. Ceci afin d'empêcher l'historique de montrer:

Description: tree -> mywork -> merge -> mywork -> merge -> mywork -> merge
Commit SHA1: aaaa -> bbbb   -> cccc  -> dddd   -> eeee  -> ffff   -> gggg

Après un rebase, cela peut ressembler à ceci (ou similaire):

Description: tree -> rebase
Commit SHA1: aaaa -> hhhh

Le problème est que le nouveau commit que vous essayez de pousser est PAS un descendant du commit sur la pointe de la branche vers laquelle vous poussez.

Maintenant, vous savez que les mêmes informations se trouvent dans les commits, mais git est responsable en écrasant non seulement ces commits (bbbb-gggg dans l'exemple ci-dessus).


Modèle de référentiel partagé

Si vous utilisez un référentiel partagé, des choses comme celle-ci peuvent devenir très confuses. Laissez-moi vous expliquer pourquoi. Supposons qu'un autre développeur ait abaissé la branche et qu'il ait validé aaaa -> gggg dans sa branche. Ensuite, ils font un commit iiii

En attendant, vous avez rebasé et forcé une poussée, ce qui a donné à l'arbre l'apparence suivante:

Description: tree -> rebase
Commit SHA1: aaaa -> hhhh

Lorsque l'autre développeur essaie de pousser, il reçoit un message "pas d'avance rapide". Quand il fait une fusion, les deux histoires sont RELINKED ensemble, et vous vous retrouvez avec un désordre

Quelque chose comme ça (désordonné):

Description: tree -> rebase -> mywork -> merge -> mywork -> merge -> mywork -> merge -> devwork -> merge 
Commit SHA1: aaaa -> hhhh   -> bbbb   -> cccc  -> dddd   -> eeee  -> ffff   -> gggg -> iiii    -> jjjj

En d'autres termes, si d'autres tirent ET poussent, il vaut mieux que vous vous en teniez à la fusion git, ou ÉVITEZ DE POUSSER qu'après le rebase (et seulement rebaser votre travail).


Modèle de référentiel publiquement visible

Peut-être que vous utilisez un modèle différent (plus grincheux) où vous voulez juste que les gens puissent retirer votre repo. Dans ce cas, git Push --force n'est pas trop mal, car alors ils peuvent gérer le suivi. Ils peuvent rebaser leurs changements pour être au top de vos changements avant de vous donner leurs correctifs. Il empêche votre repo de tout gâcher.

Cependant, il peut y avoir une meilleure façon pour vous. git Push --mirror

Sur http://www.kernel.org/pub/software/scm/git/docs/git-Push.html

Au lieu de nommer chaque référence à Push, spécifie que toutes les références sous $ GIT_DIR/refs/(qui incluent mais ne se limitent pas à refs/heads /, refs/remotes/et refs/tags /) doivent être reflétées dans le référentiel distant. Les références locales nouvellement créées seront poussées vers l'extrémité distante, les références mises à jour localement seront mises à jour de force sur l'extrémité distante et les références supprimées seront supprimées de l'extrémité distante. Il s'agit de la valeur par défaut si l'option de configuration remote..mirror est définie.


Une des grandes choses à propos de git est qu'il est très flexible et permet de nombreux types de workflows différents. Mais sa véritable force réside dans le fait qu'il s'agit d'un modèle distribué, donc je pense que le plus de ROI peut être récolté en l'utilisant de cette façon.

100
gahooa

Non, le rebase est parfaitement légal avec les référentiels publics et peut même être souhaitable pour garder l'historique fluide. Gardez à l'esprit que vous ne devez pas utiliser le rebase pour réécrire l'historique des validations publiées à distance. Autrement dit, le rebasage ne peut être appliqué qu'à vos propres commits locaux que vous n'avez jamais publiés. Vous utilisez rebase pour placer vos validations au-dessus d'eux lors de la récupération, puis, peut-être, les y ajuster. Une autre raison pour laquelle vous pouvez recevoir un tel message est que la branche que vous poussez a été mise à jour et que vous devez synchroniser - récupérer et rebaser vos validations en plus de ce que vous avez récupéré.

2
Val