J'utilise git sur un nouveau projet qui possède deux branches de développement parallèles, mais actuellement expérimentales :
master
: importation du code existant plus quelques modifications dont je suis généralement sûr.exp1
: branche expérimentale n°1exp2
: branche expérimentale n°2exp1
et exp2
représentent deux approches architecturales très différentes. Jusqu'à ce que j'avance, je n'ai aucun moyen de savoir laquelle (si l'une ou l'autre) fonctionnera. Lorsque je progresse dans une branche, j'ai parfois des modifications qui pourraient être utiles dans l'autre branche et j'aimerais les fusionner.
Quel est le meilleur moyen de fusionner des modifications sélectives d'une branche de développement à l'autre tout en laissant derrière soi tout le reste?
Approches que j'ai envisagées :
git merge --no-commit
suivi d'un déstockage manuel d'un grand nombre de modifications que je ne veux pas rendre communes entre les branches.
Copie manuelle des fichiers communs dans un répertoire temporaire, suivie de git checkout
pour passer à l'autre branche, puis d'une nouvelle copie manuelle du répertoire temporaire dans l'arbre de travail.
Une variation de ce qui précède. Abandonnez les branches exp
pour le moment et utilisez deux dépôts locaux supplémentaires pour l'expérimentation. Cela rend la copie manuelle des fichiers beaucoup plus simple.
Ces trois approches semblent fastidieuses et sujettes aux erreurs. J'espère qu'il existe une meilleure approche, quelque chose de semblable à un paramètre de chemin de filtrage qui rendrait git-merge
plus sélectif.
Vous utilisez la commande [cherry-pick][1] pour obtenir des commits individuels d'une branche.
Si le ou les changements que vous voulez ne sont pas dans des commits individuels, alors utilisez la méthode montrée ici pour [diviser le commit en commits individuels][2]. En gros, vous utilisez git rebase -i
pour obtenir le commit original à modifier, puis git reset HEAD^
pour rétablir sélectivement les changements, et enfin git commit
pour commiter ce bit comme un nouveau commit dans l'historique.
[Il y a une autre bonne méthode ici][3] dans le Red Hat Magazine, où ils utilisent git add --patch
ou peut-être git add --interactive
qui vous permet d'ajouter juste des parties d'un hunk, si vous voulez diviser différents changements dans un fichier individuel (cherchez "split" dans cette page).
Après avoir divisé les modifications, vous pouvez maintenant choisir celles que vous voulez.
[1] : http://schacon.github.com/git/git-cherry-pick.html [2] : http://plasmasturm.org/log/530/ [3] : http://web.archive.org/web/20130727101330/http://magazine.redhat.com:80/2008/05/02/shipping-quality-code-with-git/
Je n'aime pas les approches ci-dessus. L'utilisation du cherry-pick est très bien pour choisir un seul changement, mais c'est une douleur si vous voulez apporter tous les changements sauf les mauvais. Voici mon approche.
Il n'y a pas d'argument --interactive
que vous pouvez passer à git merge.
Voici l'alternative :
Vous avez des modifications dans la branche 'feature' et vous voulez en transférer certaines, mais pas toutes, dans 'master' d'une manière non négligeable (c'est-à-dire que vous ne voulez pas choisir et valider chacune d'entre elles).
git checkout feature
git checkout -b temp
git rebase -i master
# Above will drop you in an editor and pick the changes you want ala:
pick 7266df7 First change
pick 1b3f7df Another change
pick 5bbf56f Last change
# Rebase b44c147..5bbf56f onto b44c147
#
# Commands:
# pick = use commit
# edit = use commit, but stop for amending
# squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
git checkout master
git pull . temp
git branch -d temp
Donc, il suffit d'envelopper cela dans un script shell, de changer master en $to et de changer feature en $from et vous êtes prêt à partir :
#!/bin/bash
# git-interactive-merge
from=$1
to=$2
git checkout $from
git checkout -b ${from}_tmp
git rebase -i $to
# Above will drop you in an editor and pick the changes you want
git checkout $to
git pull . ${from}_tmp
git branch -d ${from}_tmp
La réponse de 1800 INFORMATION est tout à fait correcte. En tant que novice de git, cependant, "utiliser git cherry-pick" n'a pas été suffisant pour que je comprenne sans creuser un peu plus sur internet. J'ai donc pensé poster un guide plus détaillé au cas où quelqu'un d'autre serait dans le même bateau.
Mon cas d'utilisation était de vouloir tirer sélectivement des changements de la branche Github de quelqu'un d'autre dans la mienne. Si vous avez déjà une branche locale avec les changements, vous n'avez qu'à faire les étapes 2 et 5-7.
Créez (si ce n'est pas déjà fait) une branche locale avec les modifications que vous souhaitez intégrer.
$ git branch mybranch <base branch>
Basculez dans cette branche.
$ git checkout mybranch
Récupérez les changements que vous voulez depuis le compte de l'autre personne. Si vous ne l'avez pas déjà fait, vous voudrez les ajouter en tant que remote.
$ git remote add repos-w-changes <git url>
Récupérez tout ce qui se trouve dans leur branche.
$ git pull repos-w-changes branch-i-want
Regardez les journaux de livraison pour voir les changements que vous voulez :
$ git log
Revenez à la branche dans laquelle vous voulez transférer les changements.
$ git checkout originalbranch
Choisissez vos commits, un par un, avec les hashs.
$ git cherry-pick -x hash-of-commit
Conseil du chapeau : [http://www.sourcemage.org/Git_Guide] [1]