Comment puis-je utiliser git rebase sans nécessiter une poussée forcée?

92

Dans une tentative d'atteindre git nirvana, je passe la journée à apprendre à tirer parti du rebase pour les situations où je fusionne actuellement.

Lorsque j'exécute ce que je considère comme un flux git 101 (que je précise ci-dessous), je dois le faire push --forcelorsque je repousse mes modifications à l'origine.

Je ne suis pas le seul - je sais que c'est un terrain couvert (voir 1 , 2 , 3 , 4 , 5 ), et je comprends les raisons techniques pour lesquelles une force est nécessaire. Mon problème est le suivant: il y a beaucoup (beaucoup) d'entrées de blog chantant les louanges du rebase et comment cela a changé leur vie (voir 1 , 2 , 3 , 4 pour en énumérer quelques-uns), mais aucun d'entre eux ne mentionne ce qui push --forcefait partie de leur flux. Cependant, presque toutes les réponses aux questions de stackoverflow existantes disent des choses comme "ouais, si vous voulez rebaser, vous devez utiliser push --force".

Compte tenu du nombre et de la religiosité des partisans du rebase, je dois croire que l'utilisation de `` push --force '' n'est pas une partie inhérente d'un flux de rebase, et que si l'on doit souvent forcer leurs poussées, ils font quelque chose de mal. .

push --forceest une mauvaise chose .

Alors, voici mon flux. De quelle manière pourrais-je obtenir les mêmes résultats sans force?

Exemple simple

Deux branches:

  • v1.0 - une branche de publication, ne contient que des correctifs
  • master - tout pour la prochaine version majeure.

J'ai quelques correctifs et quelques commits pour la prochaine version.

premerge

J'aimerais incorporer les correctifs dans mon master afin qu'ils ne soient pas perdus pour la prochaine version. Pré-illumination, je voudrais simplement:

git checkout master
git merge v1.0

Mais maintenant j'essaye

git checkout master
git rebase v1.0

Alors maintenant je suis ici:

entrez la description de l'image ici

Temps pour:

git push

Pas de dé.

Roy Truelove
la source

Réponses:

43

Le rebasage est un excellent outil, mais il fonctionne mieux lorsque vous l'utilisez pour créer des fusions à avance rapide pour les branches de sujet sur le maître. Par exemple, vous pouvez rebaser votre branche add-new-widget par rapport à master:

git checkout add-new-widget
git rebase -i master

avant d'effectuer une fusion rapide de la branche dans le maître. Par exemple:

git checkout master
git merge --ff-only add-new-widget

L'avantage de ceci est que votre historique n'aura pas beaucoup de commits de fusion complexes ou de conflits de fusion, car toutes vos modifications seront rebasées sur la pointe de master avant la fusion. Un avantage secondaire est que vous avez rebasé, mais vous n'avez pas à utilisergit push --force car vous ne gâchez pas l'historique de la branche principale.

Ce n'est certainement pas le seul cas d'utilisation du rebase, ou le seul flux de travail, mais c'est l'une des utilisations les plus sensées que j'ai vues. YMMV.

Todd A. Jacobs
la source
4
Merci CG, je pense que "l'utiliser pour créer des fusions à avance rapide" est la clé. Cela ne s'applique pas à mon cas ci-dessus où j'ai deux branches actives - une branche de développement et une branche de publication, mais cela semble très bien s'appliquer aux branches de sujet temporaires qui ne sont nécessaires que pendant une période de temps limitée, et peuvent ensuite être supprimés une fois qu'ils ont été fusionnés. Merci encore.
Roy Truelove
1
Je comprends cela, mais la question initiale demeure. Je pense que la vraie réponse est celle donnée par @Fabien Quatravaux
IsmailS
4
Eh bien, vous devrez toujours forcer la branche 1.0, non? Du moins, c'est comme ça que les choses ont tendance à tourner pour moi tout le temps. La méthode Fabiens empêcherait que cela se produise.
joerx
23

@CodeGnome a raison. Vous ne devez pas rebaser master sur la branche v1.0 mais branche v1.0 sur master, cela fera toute la différence.

git checkout -b integrate_patches v1.0
git rebase master
git checkout master
git merge integrate_patches

Créez une nouvelle branche qui pointe vers la v1.0, déplacez cette nouvelle branche au-dessus de master, puis intégrez la nouvelle version des patchs V1.0 à la branche master. Vous vous retrouverez avec quelque chose comme:

o [master] [integrate_patches] Another patch on v1.0
o A patch on v1.0
o Another change for the next major release
o Working on the next major release
|  o [v1.0] Another path on v1.0
|  o A patch on v1.0
| /
o Time for the release

Cette façon d'utiliser rebase est recommandée par la documentation officielle de git .

Je pense que vous avez raison git push --force: vous ne devriez l'utiliser que si vous avez fait une erreur et poussé quelque chose que vous ne vouliez pas.

Fabien Quatravaux
la source
Je pense que c'est la meilleure réponse au problème spécifique du PO. Vous créez une branche de fusion temporaire et rebasez là-dessus, puis fusionnez dans le maître et poussez vers l'origine. La branche temporaire n'a pas besoin d'être poussée vers l'origine. Le seul conseil supplémentaire que je donnerais est d'avoir une branche develop ou qa où le code fusionné / rebasé peut être qualifié. Après qualification, ce code serait alors fusionné uniquement avec master. Cela permet un correctif logiciel facile si votre processus de qualification prend trop de temps. Il s'agit essentiellement du processus "git flow".
Javid Jamae
Merci Fabien, excellente réponse. Pour ceux d'entre nous qui veulent juste intégrer les modifications masteret ne git checkout my-branch; git rebase master; git checkout master; git merge my-branch
craignent
17

Vous devez forcer le push si vous rebasez et que vous avez déjà publié vos modifications, non?

J'utilise rebase tout un tas, mais je publie soit sur quelque chose de privé où une poussée forcée n'a pas d'importance (par exemple: mon propre clone sur GitHub, dans le cadre d'une pull request), soit je rebase avant de pousser pour la première fois.

C'est le cœur du flux de travail où vous utilisez le rebase, mais ne forcez pas beaucoup le push: ne publiez pas les choses tant qu'elles ne sont pas prêtes, ne rebasez pas après avoir poussé.

Daniel Pittman
la source
Merci Dan. Pourriez-vous me dire comment réaliser ce qui précède alors? N'est-ce tout simplement pas un scénario où le rebase s'applique?
Roy Truelove
2
Si vous isolez tout votre travail dans des branches de rubrique, cela met en place un bon scénario pour le rebasage. Vous avez de rebasenouvelles modifications apportées à votre branche de rubrique, mais lorsque vous avez terminé les modifications de cette branche, vous mergeretournez la branche dans la branche de développement principale.
redhotvengeance
1
Le problème est que vous avez publié la branche - vous devez donc forcer le push vers le référentiel. Vous devez renoncer à l'un des deux: publier comme vous le faites ou rebaser. Désolé.
Daniel Pittman
On dirait que le rebasage ne fonctionne pas pour ce scénario. La v1.0 n'est pas une branche de sujet, c'est une branche de publication, donc elle ne mourra jamais et doit être publiée.
Roy Truelove
5

Je pense qu'il existe un bon cas d'utilisation pour ce modèle de rebase-puis-force-push qui n'est pas le résultat d'une erreur de poussée: travailler vous-même sur une branche de fonctionnalités à partir de plusieurs emplacements (ordinateurs). Je fais cela souvent, car je travaille parfois au bureau sur mon ordinateur de bureau, et parfois à la maison / site client sur mon ordinateur portable. J'ai besoin de rebaser de temps en temps pour suivre la branche principale et / ou pour rendre les fusions plus propres, mais j'ai aussi besoin de pousser de force lorsque je quitte une machine pour aller travailler sur une autre (où je tire). Fonctionne comme un charme, tant que je suis le seul à travailler sur la branche.

8 quarante
la source
2
J'ai ce même flux de travail (travaillant à partir de plusieurs ordinateurs / emplacements). Alors, supposons que vous travaillez sur une branche de sujet appelée «mytopic». Tant que vous rebasez toujours une branche jetable locale (qui n'est qu'une branche de mytopic) sur "master" et que vous la fusionnez ensuite dans mytopic, vous n'aurez jamais à forcer le push. OP a un scénario légèrement différent, donc dans un cas comme celui-là, une poussée forcée peut être nécessaire. Cependant, je pense que OP rebase dans le mauvais sens - s'il l'a fait comme je l'ai décrit, aucune poussée de force ne serait nécessaire.
bwv549
3

Voici ce que j'utilise (en supposant que le nom de votre branche est foobar ):

git checkout master              # switch to master
git rebase   foobar              # rebase with branch
git merge -s ours origin/master  # do a basic merge -- but this should be empty
git push origin master           # aaand this should work
parfumé
la source
2
Rebasing master a l'air bizarre.
Emil Vikström
2
gitn'est pas sans personnalité
évocateur
1
git merge -s ours origin/<branch>était ce qui l'a arrangé pour nous
Max
0

tl; dr fusionne avec les branches partagées, rebase avec des branches individuelles. --force-with-leaseest une alternative plus sûre à la force et devrait vous aider à atteindre ledit nirvana git sans la nature destructrice de la force.

Une règle générale que j'ai vue travailler pour les flux de travail de diverses équipes est d'utiliser mergepour les branches partagées (c'est-à-dire, maître ou développement) et à utiliser rebaselorsque vous travaillez sur votre propre branche de fonctionnalités. Voici un cycle de vie typique d'une branche de fonctionnalités

git checkout master
git checkout -b new-feature
git commit -am "commit new work"
git push -u origin new-feature
# have code reviewed, run CI, etc.,
# meanwhile master has new commits
git checkout master
git pull
git rebase -i master # -i for interactive rebase allows you to squash intermediate commits
git push --force-with-lease
git merge master

Une version anglaise simple de ce que nous avons fait ici:

  1. Création d'une nouvelle branche de master
  2. Travail terminé sur la branche et poussé vers la télécommande
  3. rebasé hors du maître
  4. Poussez le travail à distance avec force-with-lease
  5. fusionner dans master avec un journal git très propre, réduisant l'encombrement de plusieurs fusions de notre branche partagée pour que notre branche "rattrape" le dernier master (branche partagée)

La 4ème étape est VRAIMENT importante et l'une des principales raisons pour lesquelles j'ai commencé à préconiser l'utilisation du rebase. force-with-leasevérifie la télécommande pour voir si de nouveaux commits ont été ajoutés. Si tongit push s'avère que vous êtes destructeur, cela ne poussera pas!

J'espère que cela donne à quelqu'un plus de confiance pour utiliser le rebase.

lucasnad27
la source