Git fusionner le maître dans la branche de fonctionnalité

1018

Disons que nous avons la situation suivante dans Git:

  1. Un référentiel créé:

    mkdir GitTest2
    cd GitTest2
    git init
    
  2. Certaines modifications dans le master ont lieu et sont validées:

    echo "On Master" > file
    git commit -a -m "Initial commit"
    
  3. Feature1 a dérivé le maître et certains travaux sont effectués:

    git branch feature1
    git checkout feature1
    echo "Feature1" > featureFile
    git commit -a -m "Commit for feature1"
    
  4. Pendant ce temps, un bogue est découvert dans le code maître et une branche de correctif est établie:

    git checkout master
    git branch hotfix1
    git checkout hotfix1
    
  5. Le bug est corrigé dans la branche du correctif et fusionné dans le maître (peut-être après une demande de pull / révision de code):

    echo "Bugfix" > bugfixFile
    git commit -a -m "Bugfix Commit"
    git checkout master
    git merge --no-ff hotfix1
    
  6. Le développement de feature1 se poursuit:

    git checkout feature1
    

Disons que j'ai besoin du correctif dans ma branche de fonctionnalités, peut-être parce que le bogue s'y produit également. Comment puis-je y parvenir sans dupliquer les validations dans ma branche de fonctionnalités?

Je veux éviter d'obtenir deux nouveaux commits sur ma branche de fonctionnalité qui n'ont aucun rapport avec l'implémentation de la fonctionnalité. Cela me semble particulièrement important si j'utilise des demandes de tirage: tous ces commits seront également inclus dans la demande de tirage et doivent être revus bien que cela ait déjà été fait (car le correctif est déjà dans le maître).

Je ne peux pas faire de git merge master --ff-only: "fatal: impossible d'avancer rapidement, avorter.", Mais je ne sais pas si cela m'a aidé.

theomega
la source
8
Si la succursale feature1est complètement locale, jetez un œil à git rebase.
Jokester
19
Merci, en tant que débutant git, cela git rebasesemble être de la magie noire pour moi ....
theomega
13
si la branche est une fonctionnalité - seule la correction de bogue ne devrait pas s'y produire (du moins s'il ne s'agit pas d'un bogue bloquant) car le but de cette branche est d'afficher une nouvelle fonctionnalité. Le bogue sera corrigé lors de la fusion avec le maître où la validation avec le correctif est présente.
gipi
21
Il vaut probablement la peine de noter pour les débutants qu'en 3. git branch feature1et git checkout feature1pourrait être combiné en git checkout -b feature1et 4. pourrait être entièrement réduit àgit checkout -b hotfix1 master
Naruto Sempai
3
Seriez-vous prêt à revenir et à changer la réponse acceptée, car la réponse acceptée actuelle est horrible.
Omnifarious

Réponses:

1220

Comment fusionner la branche principale dans la branche de fonctionnalité? Facile:

git checkout feature1
git merge master

Il est inutile de forcer une fusion rapide ici, car cela ne peut pas être fait. Vous vous êtes engagé à la fois dans la branche de fonctionnalité et la branche principale. L'avance rapide est impossible maintenant.

Jetez un œil à GitFlow . C'est un modèle de branchement pour git qui peut être suivi, et vous l'avez déjà fait inconsciemment. C'est également une extension de Git qui ajoute quelques commandes pour les nouvelles étapes du workflow qui font des choses automatiquement que vous auriez autrement dû faire manuellement.

Alors, qu'avez-vous bien fait dans votre flux de travail? Vous avez deux branches avec lesquelles travailler, votre branche feature1 est fondamentalement la branche "develop" du modèle GitFlow.

Vous avez créé une branche de correctifs à partir de master et l'avez fusionnée. Et maintenant tu es coincé.

Le modèle GitFlow vous demande de fusionner le correctif également à la branche de développement, qui est "feature1" dans votre cas.

La vraie réponse serait donc:

git checkout feature1
git merge --no-ff hotfix1

Cela ajoute toutes les modifications qui ont été apportées à l'intérieur du correctif à la branche de fonctionnalité, mais seulement ces modifications. Ils peuvent entrer en conflit avec d'autres changements de développement dans la branche, mais ils n'entreront pas en conflit avec la branche principale si vous fusionnez éventuellement la branche de fonction vers le maître.

Soyez très prudent avec le rebasage. Ne rebasiez que si les modifications que vous avez apportées sont restées locales dans votre référentiel, par exemple si vous n'avez poussé aucune branche vers un autre référentiel. Le rebasage est un excellent outil pour organiser vos commits locaux dans un ordre utile avant de le diffuser dans le monde, mais le rebasage ultérieur gâchera les choses pour les débutants git comme vous.

Sven
la source
7
Non. Le commit corrigeant le bogue n'apparaît qu'une seule fois dans la branche du correctif, même si le nom de la branche est supprimé une fois fusionné dans les branches master et devel. La validation de fusion affiche uniquement les modifications introduites par la fusion, qui ressemble à une validation en double. Mais voici comment git fonctionne: branchez et fusionnez. Le vrai travail de développement n'a lieu que dans les validations non-fusionnées, et la fusion uniquement est acceptée si le résultat est un logiciel fonctionnel.
Sven
42
Ce devrait être la réponse acceptée. Cela fonctionne bien avec la fonction de demande de pull de GitHub.
Nostalg.io
125
Je pense que cela vaut la peine de noter qu'une git merge mastervolonté fusionnera à partir de votre copie locale de master, donc même si vous avez fait un git pulldans votre branche de fonctionnalité après que quelqu'un d'autre a fusionné une branche différente en master, vous devrez git checkout master, puis git pull, puis à git checkout feature1nouveau et ALORS git merge master.
damick
50
@damick Ou juste git fetchetgit merge origin/master
Yngvar Kristiansen
20
@damick @ yngvar-kristiansen git pull origin masterfusionnera automatiquement orgin/masteravec la branche actuelle
L422Y
614

Vous devriez pouvoir rebaser votre branche sur master:

git checkout feature1
git rebase master

Gérez tous les conflits qui surviennent. Lorsque vous arriverez aux commits avec les corrections de bugs (déjà en master), Git dira qu'il n'y a pas eu de changements et qu'ils ont peut-être déjà été appliqués. Vous continuez ensuite le rebase (tout en sautant les commits déjà en master) avec

git rebase --skip

Si vous effectuez une git logsur votre branche de fonctionnalité, vous verrez la validation de correction de bogue n'apparaître qu'une seule fois, et dans la partie principale.

Pour une discussion plus détaillée, consultez la documentation du livre Git sur git rebase( https://git-scm.com/docs/git-rebase ) qui couvre ce cas d'utilisation exact.

================ Modifier pour un contexte supplémentaire ====================

Cette réponse a été fournie spécifiquement pour la question posée par @theomega, en tenant compte de sa situation particulière. Notez cette partie:

Je veux empêcher les validations [...] sur ma branche de fonctionnalité qui n'ont aucun rapport avec l'implémentation de fonctionnalité.

Baser sa branche privée sur le maître est exactement ce qui donnera ce résultat. En revanche, la fusion de master dans sa branche ferait précisément ce qu'il ne souhaite pas spécifiquement : ajouter une validation qui n'est pas liée à l'implémentation de la fonctionnalité sur laquelle il travaille via sa branche.

Pour m'adresser aux utilisateurs qui lisent le titre de la question, sautez le contenu et le contexte réels de la question, puis ne lisez que la première réponse à l'aveuglette en supposant qu'elle s'appliquera toujours à leur (différent) cas d'utilisation, permettez-moi d'élaborer:

  • rebaser uniquement les branches privées (c'est-à-dire qui n'existent que dans votre référentiel local et n'ont pas été partagées avec d'autres). Le fait de recréer des branches partagées "casserait" les copies que d'autres personnes pourraient avoir.
  • si vous souhaitez intégrer les modifications d'une branche (qu'il s'agisse d'une branche principale ou d'une autre branche) dans une branche publique (par exemple, vous avez poussé la branche pour ouvrir une demande d'extraction, mais il y a maintenant des conflits avec le maître et vous devez mettre à jour votre branche pour résoudre ces conflits), vous devrez les fusionner (par exemple avec git merge mastercomme dans la réponse de @ Sven).
  • vous pouvez également fusionner des succursales dans vos succursales privées locales si vous le souhaitez, mais sachez que cela entraînera des commits "étrangers" dans votre succursale.

Enfin, si vous n'êtes pas satisfait du fait que cette réponse ne soit pas la mieux adaptée à votre situation même si c'était pour @theomega, l'ajout d'un commentaire ci-dessous ne sera pas particulièrement utile: je ne contrôle pas quelle réponse est sélectionnée, seul @theomega le fait.

David Sulc
la source
136
Non, ce n'est pas sûr: si vous rebase, vous modifiez l'historique de la branche, ce qui affectera les développeurs qui ont tiré la branche. inf act, git ne vous laissera pas pousser une branche rebasée par défaut: vous devez forcer la mise à jour avec -florsque vous poussez pour écraser la branche avec la version rebasée. Faites attention!
David Sulc
17
Comment les équipes professionnelles utilisant git gèrent-elles ce problème? Faites juste attention, réfléchissez bien, puis faites un -f? Ou mon flux de travail complet est-il défectueux parce que j'en ai besoin -f?
theomega
30
Eh bien, j'oserais que la règle "sacrée" est que vous ne rebasiez pas (ou ne modifiez pas l'historique des validations) sur le code qui a été partagé: c'est uniquement pour votre code local. Fondamentalement, vous devez rebaser vos modifications pour les "nettoyer" avant de les partager. Dans votre cas, vous pouvez pousser une nouvelle branche rebasée (avec un nom différent) et demander à vos collègues de baser leurs modifications sur cette branche (c'est-à-dire en rebasant leur branche locale sur la nouvelle, comme ci-dessus). Ensuite, supprimez feature1de Github.
David Sulc
19
La plupart des équipes professionnelles sur lesquelles j'ai travaillé n'utilisent presque jamais rebase - elles fusionnent tout par défaut, de sorte qu'aucune modification de l'historique ne se produit. C'est ma façon préférée de travailler. D'un autre côté, certaines équipes utilisent rebase pour `` nettoyer '' les commits avant de les pousser (mais jamais après avoir poussé).
Jonathan Hartley
11
Oui, vous ne devez JAMAIS rebaser les branches publiques. Cependant, la question d'OP semblait porter sur l'intégration de nouveaux commits effectués masterdans une branche privée (il mentionne "sa" branche locale). Dans ce cas, rebasec'est bien et c'est le même cas d'utilisation que le "nettoyage" que vous mentionnez.
David Sulc
69

Sur la base de cet article , vous devez:

  • créer une nouvelle branche basée sur la nouvelle version du master

    git branch -b newmaster

  • fusionnez votre ancienne branche de fonctionnalité en une nouvelle

    git checkout newmaster

  • résoudre les conflits sur une nouvelle branche de fonctionnalité

Les deux premières commandes peuvent être combinées à git checkout -b newmaster.

De cette façon, votre historique reste clair car vous n'avez pas besoin de fusions antérieures. Et vous n'avez pas besoin d'être aussi super prudent car vous n'avez pas besoin de refaire Git.

zimi
la source
7
serait bien si vous faites suivre la commande git associée à chaque point. Sinon, il me semble que c'est en effet l'option la plus sûre et la plus propre.
VirgileD
@zimi Et si nous avons une succursale distante? Allons-nous recréer une nouvelle branche de fonctionnalité de mise à jour? Ou pouvons-nous simplement configurer la télécommande en amont?
BILL
@VirgileD Je viens de publier ma propre réponse avec plus de détails, y compris les commandes git associées.
jkdev
29

git merge

vous pouvez suivre les étapes ci-dessous

1. fusion origin/masterbranche à featurebranche

# step1: change branch to master, and pull to update all commits
$ git checkout master
$ git pull

# step2: change branch to target, and pull to update commits
$ git checkout feature
$ git pull

# step3: merge master to feature(⚠️ current is feature branch)
$ git merge master

2. fusion featurebranche à origin/masterbranche

origin/masterest la branche principale distante, tandis que masterla branche principale locale

$ git checkout master
$ git pull origin/master

$ git merge feature
$ git push origin/master
xgqfrms
la source
On dirait que rebase est excité! Bonne vieille fusion :)!
Forever
27

La réponse de Zimi décrit ce processus de manière générale. Voici les détails:

  1. Créez et basculez vers une nouvelle branche. Assurez-vous que la nouvelle branche est basée sur masterelle inclura les correctifs récents.

    git checkout master
    git branch feature1_new
    git checkout feature1_new
    
    # Or, combined into one command:
    git checkout -b feature1_new master
    
  2. Après être passé à la nouvelle branche, fusionnez les modifications de votre branche de fonctionnalité existante. Cela ajoutera vos validations sans dupliquer les validations du correctif.

    git merge feature1
    
  3. Sur la nouvelle branche, résolvez tous les conflits entre votre fonctionnalité et la branche principale.

Terminé! Utilisez maintenant la nouvelle branche pour continuer à développer votre fonctionnalité.

jkdev
la source
2
Le problème est qu'un développeur perd du temps à générer constamment de nouvelles branches lorsqu'il doit effectuer une mise à jour par rapport à Master. Nous ferions beaucoup, beaucoup de branches, probablement 3 fois par jour pendant le travail actif. Vous devez écrire des instructions sur le nettoyage de toutes les branches de corbeille locales et sur la façon de les supprimer à distance également. Nous avons également besoin de conseils pour nommer toutes ces branches afin de ne pas nous embrouiller. Sans cela, cela transformera un système de succursales en chaos.
pauljohn32
4
Vous avez raison, cela ne devrait pas être fait tout le temps. Uniquement lorsque (1) les modifications sur master sont nécessaires pour votre fonctionnalité, ou (2) vous êtes sur le point de fusionner votre branche avec master et il peut y avoir des conflits. Et pour éviter l'encombrement, vous pouvez supprimer votre branche après sa fusion.
jkdev
11

Voici un script que vous pouvez utiliser pour fusionner votre branche principale dans votre branche actuelle.

Le script fait ce qui suit:

  • Bascule vers la branche principale
  • Tire la branche principale
  • Revient à votre branche actuelle
  • Fusionne la branche principale dans votre branche actuelle

Enregistrez ce code en tant que fichier de commandes (.bat) et placez le script n'importe où dans votre référentiel. Cliquez ensuite dessus pour l'exécuter et vous êtes prêt.

:: This batch file pulls current master and merges into current branch

@echo off

:: Option to use the batch file outside the repo and pass the repo path as an arg
set repoPath=%1
cd %repoPath%

FOR /F "tokens=*" %%g IN ('git rev-parse --abbrev-ref HEAD') do (SET currentBranch=%%g)

echo current branch is %currentBranch%
echo switching to master
git checkout master
echo.
echo pulling origin master
git pull origin master
echo.
echo switching back to %currentBranch%
git checkout %currentBranch%
echo.
echo attemting merge master into %currentBranch%
git merge master
echo.
echo script finished successfully
PAUSE
Aaron M.
la source
10

Vous pourrez peut-être faire un "choix" pour extraire les validations exactes dont vous avez besoin dans votre branche de fonctionnalités.

Faites un git checkout hotfix1pour accéder à la branche hotfix1. Ensuite, faites un git logpour obtenir le hachage SHA-1 (grande séquence de lettres et de chiffres aléatoires qui identifie de manière unique une validation) de la validation en question. Copiez cela (ou les 10 premiers caractères environ).

Ensuite, git checkout feature1pour revenir sur votre branche de fonctionnalités.

Alors, git cherry-pick <the SHA-1 hash that you just copied>

Cela va tirer ce commit, et seulement ce commit, dans votre branche de fonctionnalité. Ce changement sera dans la branche - vous venez de le "sélectionner". Ensuite, reprenez le travail, éditez, validez, poussez, etc. au contenu de votre cœur.

Lorsque, finalement, vous effectuez une autre fusion d'une branche dans votre branche de fonctionnalité (ou vice versa), Git reconnaîtra que vous avez déjà fusionné dans ce commit particulier , sachez qu'il n'a pas à le refaire, et juste "sauter".

Bob Gilmore
la source
Je ne pense pas que ce soit une bonne idée. Ensuite, IMO, la validation du correctif apparaîtra vraiment dans l'historique de votre branche de fonctionnalité, ce que vous ne voulez pas.
Martin Pecka
1
"Quand, finalement, vous effectuez une autre fusion d'une branche dans votre branche de fonctionnalité (ou vice-versa), git reconnaîtra que vous avez déjà fusionné [...]" - est-ce ainsi que cela fonctionne? Je ne pense pas que cela git mergefonctionne dans ce "replay commits", comme vous semblez le laisser entendre ("et juste le sauter"). Le mélange de la cueillette des cerises et de la fusion peut apparemment entraîner des problèmes; voir: news.ycombinator.com/item?id=3947950
Guildenstern
0

Je suis sur la branche des fonctionnalités et j'ai fait des refactorings. Je veux maintenant fusionner les modifications principales dans ma branche de fonctionnalité. Je suis loin derrière. Remarque Je ne souhaite pas extraire les modifications principales dans ma section locale car ma branche de fonction a des modules déplacés d'un endroit à un autre. J'ai trouvé que jouer ci-dessous sans tirer ne fonctionne pas. il dit "Déjà à jour".

 //below does not get the latest from remote master to my local feature branch without git pull
    git checkout master 
    git fetch 
    git checkout my-feature-branch 
    git merge master

Cela fonctionne ci-dessous, notez l'utilisation de git merge origin / master:

 git checkout master 
    git fetch 
    git checkout my-feature-branch 
    git merge origin/master
Tony
la source