impossible de pousser pour créer une branche après le rebase

131

Nous utilisons git et avons une branche principale et des branches de développeur. Je dois ajouter une nouvelle fonctionnalité, puis rebaser les commits vers le maître, puis pousser le maître vers le serveur CI.

Le problème est que si j'ai des conflits pendant le rebase, je ne peux pas pousser vers ma branche de développeur distante (sur Github) une fois le rebase terminé, jusqu'à ce que je tire ma branche distante. Cela provoque des validations en double. Lorsqu'il n'y a pas de conflit, fonctionne comme prévu.

question: après le rebase et la résolution des conflits, comment synchroniser mes branches de développeur locales et distantes sans créer de duplication de commits

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

ÉDITER

Il semble donc que cela interrompra 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 les poussées vers la branche distante pour myNewFeature

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

Cela incitera-t-il les autres développeurs à détester le développeur1?

Mat
la source
pas une solution mais juste une pensée. qui est we? faites-vous partie d'une équipe qui ne se limite pas à vous? theydites (aux gens qui en savent plus que moi) que si vous partagez votre code, vous ne devriez pas l'utiliser rebase. Pourquoi tu ne fais pas juste git pullet git merge?
AdamT
désolé, nous = équipe de développement
Matt
1
alors oui, vous ne devriez probablement pas rebaser lorsque vous partagez du code. cela peut vous amener à faire des choses comme ce qui est énuméré ci-dessous ( forcela poussée)
AdamT
oh désolé, quand ils disent rewriting history, c'est unrebase
AdamT
Comme il l'a dit, c'est une branche de développement qui lui est propre, donc cela ne devrait pas être un problème à moins que quelqu'un ne soit censé fusionner cela.
Learath2

Réponses:

93

Tout d'abord, vous et ceux avec qui vous travaillez devez convenir si une branche de sujet / développement est destinée au développement partagé ou simplement à la vôtre. Les autres développeurs savent qu'il ne faut pas fusionner sur mes branches de développement car elles seront rebasées à tout moment. Habituellement, 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 la télécommande, je ferai 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 besoin de changer de branche de développement. Deuxièmement, c'est un mécanisme de sécurité pour m'assurer de ne pas écraser les changements non cachés / validés. De plus, si je ne peux pas effectuer une fusion rapide vers la branche principale, cela signifie que quelqu'un a rebasé le maître distant (pour lequel il doit être sévèrement fouetté) ou que je me suis accidentellement engagé à maîtriser et que je dois nettoyer ma fin.

Ensuite, lorsque la télécommande a changé et que j'ai rapidement avancé vers la dernière, je rebase:

git checkout devel0
git rebase master
git push -f origin devel0

D'autres développeurs savent alors qu'ils devront rebaser leurs branches de développement à partir de ma dernière:

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

Ce qui se traduit par une histoire beaucoup plus propre:

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

Ne fusionnez pas les commits dans les deux sens à votre guise. Non seulement cela crée des validations en double et rend l'historique impossible à suivre, mais il devient presque 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.

Il semble également que d'autres développeurs effectuent des commits dans vos branches de développement. Pouvez-vous le confirmer?

Le seul moment pour fusionner est lorsque votre branche thématique est prête à être acceptée master.

Sur une note latérale. Si plusieurs développeurs s'engagent dans le même référentiel, vous devriez 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é.

Trevor Norris
la source
1
"De plus, il semble que d'autres développeurs effectuent des validations dans vos branches de développement. Pouvez-vous le confirmer?" OUI ils sont ...
Matt
Vous avez également porté à mon attention un autre problème. Travailler entre le bureau et la maison. Je fais des fusions aux deux endroits et à la fin de la journée je pousse pour pouvoir reprendre là où je m'étais arrêté. Ensuite, quand il est temps de rebaser, tous ces commits créent de la confusion. Je dois traiter mes branches comme une seule branche et rebaser
Matt
@Matt Ouais, ces deux problèmes vont vraiment gâcher votre flux de travail. Pour le premier, je communiquerais aux autres développeurs que seul le propriétaire peut s'engager sur une branche nommée (par exemple 'matt / devel'). À mon humble avis, aucun développeur ne devrait s'engager dans la même branche de toute façon. Crée juste de la confusion. Pour ce qui est plus tard, le rebasage et la poussée forcée devraient maintenir les deux emplacements à jour.
Trevor Norris
Très bonne réponse. J'ai une question secondaire, pourquoi utilisez-vous le --forcedrapeau lorsque vous le faites git push -f origin devel0?
Nobita
2
@Nobita Quand un git pushne peut pas avancer rapidement (c'est-à-dire que l'historique sha ne correspond pas), vous devez forcer push pour écraser l'historique précédent avec le nouvel historique généré à partir de git rebase.
Trevor Norris
50

Vous devez forcer le push car vous avez déplacé les commits plus bas dans la ligne git s'attend à ce que vous ajoutiez des commits à la pointe de la branche. git push -f origin myNewFeaturerésoudra votre problème.

Astuce: ci-dessus est un usage légitime de la force de poussée. Ne réécrivez jamais l'histoire sur un référentiel accessible au public ou beaucoup de gens vous détesteront.

Learath2
la source
1
Je trouve que c'est le moyen le plus optimal de maintenir le flux de travail.
Syed Priom
1
Merci mon pote. J'ai utilisé cette commande pour forcer ma branche locale rebasée à la même branche distante.
wei
11
l'utilisation git push --force-with-leaseest beaucoup plus sûre que l'utilisationgit push --force
git push --force-with-lease origin HEAD- en supposant que votre branche cible est déjà
passée à la
31

La principale chose à garder à l'esprit ici est ce que font le pull et le rebase dans les coulisses.

Un pull fera essentiellement deux choses: récupérer et fusionner. Lorsque vous incluez --rebase, il effectuera un rebase au lieu de la fusion.

Un rebase est un peu comme cacher toutes vos modifications locales depuis que vous avez créé une branche, faire avancer rapidement votre branche vers le dernier commit sur la cible et désinstaller vos modifications dans l'ordre en haut.

(Cela explique pourquoi vous pouvez recevoir plusieurs invites de résolution de conflit lorsque vous effectuez un rebase 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 commit qui est rebasé afin de préserver autrement vos commits. )

Vous ne voulez jamais pousser les modifications rebasées vers les branches distantes car il s'agit de réécrire l'historique. Ofcoarse, jamais n'est 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 travailler sur un environnement spécifique par exemple.

Cela vous obligera parfois à pousser les modifications rebasées en utilisant la 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 succursale distante. Cela peut signifier que vous travaillez ensemble au départ avec des fusions et que vous les rebasez dans un format de validation plus gérable juste avant de maîtriser et de supprimer votre branche active.

N'oubliez pas que vous pouvez presque toujours utiliser le GC de git en profitant de:

git reflog

C'est une énorme bouée de sauvetage car vous pouvez revenir à un état plus stable si vous vous perdez dans toute votre gestion de rebase / conflit.

Matthew Sanders
la source
L'option supprimer et recréer ci-dessus a bien fonctionné pour moi. Aucun forçage autorisé sur mon repo!
Simon Holmes
2

Vous devez effectuer une poussée forcée, 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 - vous n'êtes généralement pas censé publier des branches où vous réécrivez l'histoire (ou plutôt ne réécrivez pas l'histoire une fois publiée). Une façon serait d'utiliser un nom de branche comme wip/myNewFeature, puis de mentionner que les wipbranches seront rebasées en maître de temps en temps.

ThiefMaster
la source
l'utilisation git push --force-with-leaseest beaucoup plus sûre que l'utilisationgit push --force
@MrCholo Les gens ne commenceront pas à l'utiliser tant que git n'aura pas ajouté une option courte, comme -fpour une poussée forcée normale :)
ThiefMaster
ha ouais, je l'ai utilisé dans un script automatisé tho
2

La réponse générale qui a déjà été donnée - à utiliser git push -f origin myNewFeaturepour pousser des changements rebasés - est un bon point de départ. J'écris cette réponse pour aborder la question de savoir si cela interrompra votre flux de travail.

Si nous supposons que vous allez utiliser git pull --rebase ...(ou une variante à ce sujet) suivi d'une poussée forcée vers la branche distante, alors la chose qui rompt le flux de travail dans votre exemple est la fusion de developer2 myNewFeaturedans 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 cela en a) établissant une règle à partir de laquelle vous ne fusionnez que master, ou b) en créant une developbranche collective , sur laquelle vous basez votre propre myNewFeaturebranche, et en établissant une règle à partir de laquelle vous ne fusionnez que develop. mastersera alors réservé uniquement pour les jalons ou les versions (ou quelle que soit la manière dont vous souhaitez le configurer), et developsera l'endroit où vous pousserez chaque fonctionnalité lorsqu'elle est prête à être intégrée dans d'autres branches de fonctionnalités.

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

cosmiqueFluke
la source
1

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
Sylvain Lesage
la source