web-dev-qa-db-fra.com

ne peut pas pousser à la branche après rebase

Nous utilisons git et avons une branche master et des branches developer. J'ai besoin d'ajouter une nouvelle fonctionnalité, puis de rebaser les commits en maître, puis de transmettre le maître au serveur CI.

Le problème est que si des conflits surviennent lors de la création d'une base, je ne peux pas transmettre à ma branche développeur distante (sur Github) une fois la base terminée, jusqu'à ce que je tire ma branche distante. Cela provoque des validations en double. Lorsqu'il n'y a pas de conflits, fonctionne comme prévu.

question: après la résolution de rebase et de conflit, comment synchroniser mes branches de développeur locales et distantes sans créer de validations en double

Installer:

// master branch is the main branch
git checkout master
git checkout -b myNewFeature

// I will work on this at work and at home
git Push Origin myNewFeature

// work work work on myNewFeature
// master branch has been updated and will conflict with myNewFeature
git pull --rebase Origin master

// we have conflicts
// solve conflict
git rebase --continue

//repeat until rebase is complete
git Push Origin myNewFeature

//ERROR
error: failed to Push some refs to '[email protected]:ariklevy/dropLocker.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git Push --help' for details.

// do what git says and pull
git pull Origin myNewFeature

git Push Origin myNewFeature

// Now I have duplicate commits on the remote branch myNewFeature

MODIFIER

On dirait que cela va interrompre le flux de travail:

developer1 travaillant sur myNewFeature developer2 travaillant sur hisNewFeature utilisent tous deux master comme branche principale

developer2 fusionne myNewFeature dans hisNewFeature

developer1 rebase, résout les conflits, puis force le transfert vers la branche distante pour myNewFeature

quelques jours plus tard, developer2, fusionne à nouveau myNewFeature dans hisNewFeature.

Est-ce que cela va amener les autres développeurs à détester developer1?

98
Matt

Tout d’abord, vous et les personnes avec qui vous travaillez devez vous mettre d’accord pour dire si un domaine/une branche de développement est destiné au développement partagé ou simplement au vôtre. D'autres développeurs savent ne pas fusionner avec mes branches de développement car elles seront rebasonnées à tout moment. En règle générale, le flux de travail est le suivant:

o-----o-----o-----o-----o-----o       master
 \
   o-----o-----o                      devel0
                \
                  o-----o-----o       devel1

Ensuite, pour rester à jour avec remote, je vais faire ce qui suit:

 git fetch Origin
 git checkout master
 git merge --ff Origin/master

Je fais cela pour deux raisons. D'abord parce que cela me permet de voir s'il y a des changements à distance sans avoir à changer de branche de développement. Deuxièmement, il s’agit d’un mécanisme de sécurité qui évite d’écraser les modifications non stockées/validées. De plus, si je ne parviens pas à effectuer une fusion rapide vers la branche maître, cela signifie que quelqu'un a rebasalisé le maître distant (pour lequel il doit être fouetté sévèrement) ou que je me suis accidentellement engagé à maîtriser et à nettoyer ma fin.

Ensuite, lorsque la télécommande a changé et que je suis rapidement passée au dernier, je me rebase:

git checkout devel0
git rebase master
git Push -f Origin devel0

Les autres développeurs savent alors qu'ils vont avoir besoin de rebaser leurs branches de développement de mes dernières:

git fetch <remote>
git checkout devel1
git rebase <remote>/devel0

Ce qui entraîne une histoire beaucoup plus propre:

o-----o                                 master
       \
         o-----o-----o                  devel0
                      \
                        o-----o-----o   devel1

Ne pas fusionner se commet à votre guise. Cela crée non seulement des validations en double et rend l'historique impossible à suivre, mais il est également pratiquement impossible de trouver des régressions à partir d'un changement spécifique (c'est pourquoi vous utilisez le contrôle de version en premier lieu, n'est-ce pas?). Le problème que vous rencontrez est le résultat de cela.

En outre, il semble que d’autres développeurs puissent s’engager dans vos branches de développement. Pouvez-vous confirmer cela?

Le seul moment pour la fusion est lorsque votre branche de sujet est prête à être acceptée dans master.

Sur une note de côté. Si plusieurs développeurs s'engagent dans le même référentiel, vous devez tous envisager d'avoir des branches nommées pour distinguer les branches de développement des développeurs. Par exemple:

git branch 'my-name/devel-branch'

Ainsi, toutes les branches de sujet des développeurs résident dans leur propre ensemble imbriqué.

77
Trevor Norris

Vous devez forcer le Push lorsque vous avez déplacé les commits plus loin dans la ligne que git s'attend à ce que vous ajoutiez des commits au sommet de la branche. git Push -f Origin myNewFeature résoudra votre problème.

Conseil: ci-dessus, un usage légitime de la force. Ne jamais réécrire l'historique sur un référentiel accessible au public ou beaucoup de gens vont vous détester. 

39
Learath2

La principale chose à garder à l'esprit est ce que pull et rebase font en coulisses.

Un pull fera essentiellement deux choses: chercher et fusionner. Lorsque vous incluez --rebase, il effectuera une rebase au lieu de la fusion.

Un rebase est un peu comme si vous stockiez toutes vos modifications locales depuis que vous aviez créé une branche, transférant rapidement votre branche vers le dernier commit sur la cible et annulant l'ordre de vos modifications.

(Cela explique pourquoi vous pouvez obtenir plusieurs invites de résolution de conflit lorsque vous effectuez une modification de base par rapport à la résolution de conflit que vous pouvez obtenir avec une fusion. Vous avez la possibilité de résoudre un conflit sur CHAQUE validation qui est en cours de modification afin de préserver vos validations. )

Vous ne voulez jamais envoyer les modifications basées sur les bases aux branches distantes car il s'agit d'une réécriture de l'historique. Ofcoarse, n'est jamais un peu fort car il y a presque toujours des exceptions. Le cas où vous devez maintenir une version distante de votre référentiel local pour fonctionner sur un environnement spécifique, par exemple.

Cela nécessitera que vous appliquiez parfois les modifications basées sur un rebasement de force:

git Push -f Origin newfeature

Ou, dans certains cas, votre administrateur peut avoir supprimé la possibilité de forcer. Vous devez donc supprimer et recréer:

git Push Origin :newfeature
git Push Origin newfeature

Dans les deux cas, vous devez être absolument sûr de savoir ce que vous faites si quelqu'un d'autre collabore avec vous sur votre branche distante. Cela peut signifier que vous travaillez initialement ensemble avec des fusions et des modifications dans un format de validation plus facile à gérer, juste avant de maîtriser et de supprimer votre branche active.

Rappelez-vous que vous pouvez presque toujours utiliser le GC de git en profitant des avantages suivants:

git reflog

Ceci est un énorme épargnant de vie, car vous pouvez revenir à un état plus stable si vous vous perdez dans toute votre gestion des rebases/conflits.

27
Matthew Sanders

Vous devez effectuer un push forcé, c'est-à-dire git Push -f Origin myNewFeature

Oh, et vous feriez mieux de vous assurer que les gens ne basent rien sur votre branche de développement - en général, vous n'êtes pas censé publier de branches sur lesquelles vous réécrivez l'histoire (ou plutôt ne pas réécrire l'histoire une fois publiée). Une solution consisterait à utiliser un nom de branche tel que wip/myNewFeature, puis à mentionner que les branches wip seront redéfinies en bases de temps à autre.

2
ThiefMaster

La réponse générale qui a déjà été donnée, à savoir utiliser git Push -f Origin myNewFeature lors du transfert de modifications basées sur un rebasement, est un bon point de départ. J'écris cette réponse pour indiquer si la modification va interrompre votre flux de travail.

Si nous supposons que vous allez utiliser git pull --rebase ... (ou une variante de celle-ci) suivi d'un envoi forcé vers la branche distante, l'élément qui rompt le flux de travail dans votre exemple est developer2 est la fusion de myNewFeature dans hisNewFeature. Il est logique de pouvoir rebaser votre propre branche de fonctionnalité tant que personne d'autre ne travaille sur cette branche. Vous avez donc besoin de règles pour délimiter le territoire de la branche.

Vous pouvez contourner ce problème en a) établissant une règle selon laquelle vous ne fusionnez jamais que depuis master ou b) en créant une branche collective develop, sur laquelle vous basez votre propre branche myNewFeature et établissez une règle que vous ne fusionnez jamais depuis develop. master sera alors réservé uniquement aux jalons ou aux versions (ou de toute autre manière que vous souhaitez configurer), et develop sera l'endroit où vous activez chaque fonctionnalité lorsqu'elle est prête à être intégrée dans d'autres branches.

Je pense que cela pourrait être considéré comme une version simplifiée du workflow Gitflow.

1
cosmicFluke

Je suis d'accord avec MrCholo et peut-être que Trevor Norris pourrait envisager de mettre à jour sa bonne réponse pour remplacer 

git Push -f Origin devel0

avec

git Push --force-with-lease Origin devel0
0
Sylvain Lesage