J'utilise git sur un nouveau projet qui a deux branches de développement parallèles - mais actuellement expérimentales -:
master
: import de base de code existante plus quelques mods dont je suis généralement sûrexp1
: branche expérimentale # 1exp2
: branche expérimentale # 2
exp1
et exp2
représentent deux approches architecturales très différentes. Jusqu'à ce que je progresse, je n'ai aucun moyen de savoir lequel (le cas échéant) fonctionnera. Au fur et à mesure que je progresse dans une branche, j'ai parfois des modifications qui seraient utiles dans l'autre branche et que je voudrais fusionner uniquement.
Quelle est la meilleure façon de fusionner des changements sélectifs d'une branche de développement à une autre tout en laissant de côté tout le reste?
Approches que j'ai envisagées:
git merge --no-commit
suivi d'une désorganisation manuelle 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, puis
git checkout
pour passer à l'autre branche, puis plus de copie manuelle du répertoire temporaire dans l'arborescence de travail.Une variation de ce qui précède. Abandonnez les
exp
branches pour l'instant et utilisez deux référentiels 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 y a une meilleure approche; quelque chose qui ressemble à un paramètre de chemin de filtre qui le rendrait git-merge
plus sélectif.
la source
git merge -s ours --no-commit
suivis par certains negit read-tree
serait-elle pas une bonne solution pour cela? Voir stackoverflow.com/questions/1214906/…Réponses:
Vous utilisez la commande cherry-pick pour obtenir des validations individuelles d'une branche.
Si les modifications souhaitées ne se trouvent pas dans des validations individuelles , utilisez la méthode indiquée ici pour diviser la validation en validations individuelles . En gros, vous utilisez
git rebase -i
pour obtenir le commit d'origine à modifier, puisgit reset HEAD^
pour annuler sélectivement les modifications, puisgit commit
pour valider ce bit en tant que nouveau commit dans l'historique.Il existe une autre méthode intéressante ici dans Red Hat Magazine, où ils utilisent
git add --patch
ou éventuellementgit add --interactive
qui vous permet d'ajouter seulement des parties d'un morceau, si vous souhaitez fractionner différentes modifications dans un fichier individuel (recherchez dans cette page «fractionner»).Après avoir divisé les modifications, vous pouvez désormais choisir celles que vous souhaitez.
la source
J'ai eu exactement le même problème que celui mentionné ci-dessus. Mais j'ai trouvé cela plus clair en expliquant la réponse.
Sommaire:
Extraire le (s) chemin (s) de la branche que vous souhaitez fusionner,
Astuce: Cela fonctionne également sans
--
comme vu dans le post lié.ou pour fusionner sélectivement des mecs
Vous pouvez également utiliser la réinitialisation, puis ajouter avec l'option
-p
,Finalement, engagez
la source
foo.c
fairegit reset HEAD foo.c
pour désindexer ce fichier et vous pouvez alors diff il. J'ai découvert cela après l'avoir essayé et je suis revenu ici pour chercher une réponse à celagit diff --cached
git checkout -p <revision> -- <path>
sera la même chose que d'émettre les trois premières commandes que vous avez décrites :)Pour fusionner de manière sélective des fichiers d'une branche dans une autre branche, exécutez
où
branchX
est la branche à partir de laquelle vous souhaitez fusionner dans la branche actuelle.L'
--no-commit
option mettra en scène les fichiers qui ont été fusionnés par Git sans réellement les valider. Cela vous donnera la possibilité de modifier les fichiers fusionnés comme vous le souhaitez, puis de les valider vous-même.Selon la façon dont vous souhaitez fusionner les fichiers, il existe quatre cas:
1) Vous voulez une vraie fusion.
Dans ce cas, vous acceptez les fichiers fusionnés comme Git les a fusionnés automatiquement, puis vous les validez.
2) Il y a certains fichiers que vous ne souhaitez pas fusionner.
Par exemple, vous souhaitez conserver la version dans la branche actuelle et ignorer la version dans la branche à partir de laquelle vous fusionnez.
Pour sélectionner la version dans la branche actuelle, exécutez:
Cela va récupérer la version de
file1
dans la branche actuelle et écraser l'file1
automerged par Git.3) Si vous voulez la version dans branchX (et non une vraie fusion).
Courir:
Cela récupérera la version de
file1
inbranchX
et écraserafile1
la fusion automatique par Git.4) Le dernier cas est si vous souhaitez sélectionner uniquement des fusions spécifiques
file1
.Dans ce cas, vous pouvez éditer
file1
directement la modification , la mettre à jour avec ce que vous souhaitez que la versionfile1
devienne, puis valider.Si Git ne peut pas fusionner un fichier automatiquement, il signalera le fichier comme "non fusionné " et produira une copie où vous devrez résoudre les conflits manuellement.
Pour expliquer plus en détail avec un exemple, disons que vous souhaitez fusionner
branchX
dans la branche actuelle:Vous exécutez ensuite la
git status
commande pour afficher l'état des fichiers modifiés.Par exemple:
Où
file1
,file2
etfile3
sont les fichiers que git a réussi à fusionner automatiquement.Cela signifie que les modifications apportées à
master
etbranchX
pour ces trois fichiers ont été combinées sans aucun conflit.Vous pouvez vérifier comment la fusion a été effectuée en exécutant le
git diff --cached
;Si vous trouvez une fusion indésirable, vous pouvez
git commit
Si vous ne souhaitez pas fusionner
file1
et souhaitez conserver la version dans la branche actuelleCourir
Si vous ne souhaitez pas fusionner
file2
et souhaitez uniquement la versionbranchX
Courir
Si vous souhaitez
file3
être fusionné automatiquement, ne faites rien.Git l'a déjà fusionné à ce stade.
file4
ci-dessus est une fusion ratée de Git. Cela signifie qu'il y a des changements dans les deux branches qui se produisent sur la même ligne. C'est là que vous devrez résoudre les conflits manuellement. Vous pouvez ignorer la fusion effectuée en modifiant directement le fichier ou en exécutant la commande d'extraction pour la version dans la branche que vous souhaitezfile4
devenir.Enfin, n'oubliez pas
git commit
.la source
git merge --no-commit branchX
n'est qu'une avance rapide, le pointeur sera mis à jour, et le --no-commit est donc ignoré en silence--no-ff
pour empêcher ce comportement?Je n'aime pas les approches ci-dessus. L'utilisation de la cerise sur le gâteau est idéale pour choisir un seul changement, mais c'est pénible si vous souhaitez apporter tous les changements, à l'exception de certains mauvais. Voici mon approche.
Il n'y a aucun
--interactive
argument que vous pouvez passer pour git merge.Voici l'alternative:
Vous avez des changements dans la «fonctionnalité» de la branche et vous voulez en apporter une partie, mais pas tous, au «maître» d'une manière non bâclée (c'est-à-dire que vous ne voulez pas choisir et valider chacun d'eux)
Enveloppez simplement cela dans un script shell, changez master en $ to et changez la fonctionnalité en $ from et vous êtes prêt à partir:
la source
git rebase -i $to
àgit rebase -i $to || $SHELL
, afin que l'utilisateur puisse appelergit --skip
etc, si nécessaire si le rebase échoue. Il convient également de chaîner les lignes avec&&
au lieu de nouvelles lignes.Il y a une autre voie à suivre:
C'est un mélange entre
git checkout
etgit add -p
et pourrait être exactement ce que vous recherchez:la source
Bien que certaines de ces réponses soient plutôt bonnes, j'ai l'impression qu'aucune n'a réellement répondu à la contrainte d'origine d'OP: sélectionner des fichiers particuliers dans des branches particulières. Cette solution fait cela, mais peut être fastidieuse s'il y a beaucoup de fichiers.
Disons que vous avez les
master
,exp1
et lesexp2
branches. Vous souhaitez fusionner un fichier de chacune des branches expérimentales dans master. Je ferais quelque chose comme ça:Cela vous donnera des différences dans le fichier pour chacun des fichiers que vous souhaitez. Rien de plus. Rien de moins. Il est utile que vous ayez des changements de fichier radicalement différents entre les versions - dans mon cas, le changement d'une application de Rails 2 à Rails 3.
EDIT : cela fusionnera les fichiers, mais fera une fusion intelligente. Je n'ai pas été en mesure de comprendre comment utiliser cette méthode pour obtenir des informations de diff dans le fichier (peut-être que ce sera toujours le cas pour des différences extrêmes. De petites choses ennuyeuses comme les espaces blancs sont fusionnées à moins que vous n'utilisiez l'
-s recursive -X ignore-all-space
option)la source
git checkout exp1 path/to/file_a path/to/file_x
git checkout feature <path>/*
pour obtenir des groupes de fichiers.La réponse de 1800 INFORMATION est tout à fait correcte. En tant que git noob, cependant, "utiliser git cherry-pick" ne m'a pas suffi pour comprendre cela sans creuser un peu plus sur Internet, donc j'ai pensé publier un guide plus détaillé au cas où quelqu'un d'autre serait dans un bateau similaire.
Mon cas d'utilisation voulait tirer sélectivement les modifications de la branche github de quelqu'un d'autre dans la mienne. Si vous avez déjà une branche locale avec les modifications, il vous suffit de faire les étapes 2 et 5-7.
Créez (sinon créé) une branche locale avec les modifications que vous souhaitez apporter.
$ git branch mybranch <base branch>
Passez-y.
$ git checkout mybranch
Déroulez les modifications que vous souhaitez du compte de l'autre personne. Si vous ne l'avez pas déjà fait, vous voudrez les ajouter en tant que télécommande.
$ git remote add repos-w-changes <git url>
Retirez tout de leur branche.
$ git pull repos-w-changes branch-i-want
Affichez les journaux de validation pour voir les modifications que vous souhaitez:
$ git log
Revenez à la branche dans laquelle vous souhaitez insérer les modifications.
$ git checkout originalbranch
Cherry choisit vos commits, un par un, avec les hachages.
$ git cherry-pick -x hash-of-commit
Astuce chapeau: http://www.sourcemage.org/Git_Guide
la source
git cherry
commande (voir d'abord le manuel) pour identifier les commits que vous n'avez pas encore fusionnés.Voici comment remplacer un
Myclass.java
fichier enmaster
branche parMyclass.java
enfeature1
branche. Cela fonctionnera même s'ilMyclass.java
n'existe pasmaster
.Notez que cela écrasera - et non fusionnera - et ignorera plutôt les modifications locales dans la branche principale.
la source
theirs
écraserours
=> +1 Cheers;)2. Manual copying of common files into a temp directory followed by ...copying out of the temp directory into the working tree.
La manière simple, pour fusionner réellement des fichiers spécifiques de deux branches, n'est pas simplement de remplacer des fichiers spécifiques par ceux d'une autre branche.
Première étape: diff les branches
git diff branch_b > my_patch_file.patch
Crée un fichier patch de la différence entre la branche actuelle et branch_b
Deuxième étape: appliquer le correctif sur les fichiers correspondant à un modèle
git apply -p1 --include=pattern/matching/the/path/to/file/or/folder my_patch_file.patch
notes utiles sur les options
Vous pouvez utiliser
*
comme caractère générique dans le modèle d'inclusion.Les barres obliques n'ont pas besoin d'être échappées.
En outre, vous pouvez utiliser --exclude à la place et l'appliquer à tout sauf aux fichiers correspondant au modèle, ou inverser le correctif avec -R
L'option -p1 est un maintien de la commande de correctif * unix et le fait que le contenu du fichier de correctif précède chaque nom de fichier avec
a/
oub/
(ou plus selon la façon dont le fichier de correctif a été généré) que vous devez supprimer afin qu'il puisse comprendre le vrai fichier vers le chemin d'accès au fichier auquel le patch doit être appliqué.Consultez la page de manuel pour git-apply pour plus d'options.
Troisième étape: il n'y a pas de troisième étape
Évidemment, vous voudriez valider vos modifications, mais qui dira que vous n'avez pas d'autres ajustements liés à faire avant de faire votre validation.
la source
Voici comment vous pouvez faire en sorte que l'historique suive seulement quelques fichiers d'une autre branche avec un minimum d'agitation, même si une fusion plus "simple" aurait apporté bien plus de changements que vous ne voulez pas.
Tout d'abord, vous prendrez la décision inhabituelle de déclarer à l'avance que ce que vous êtes sur le point de valider est une fusion, sans git faire quoi que ce soit aux fichiers de votre répertoire de travail:
. . . où "nom_branche" correspond à tout ce que vous prétendez fusionner. Si vous deviez vous engager immédiatement, cela ne ferait aucun changement mais cela montrerait toujours l'ascendance de l'autre branche. Vous pouvez ajouter plus de branches / tags / etc. à la ligne de commande si vous en avez besoin également. À ce stade cependant, il n'y a pas de changement à valider, alors récupérez les fichiers des autres révisions, ensuite.
Si vous fusionnez à partir de plusieurs autres branches, répétez au besoin.
Maintenant, les fichiers de l'autre branche sont dans l'index, prêts à être validés, avec l'historique.
et vous aurez beaucoup d'explications à faire dans ce message de validation.
Veuillez noter cependant, au cas où ce ne serait pas clair, que c'est une mauvaise chose à faire. Ce n'est pas dans l'esprit de ce qu'est une "branche", et le choix des cerises est une façon plus honnête de faire ce que vous feriez ici. Si vous vouliez faire une autre "fusion" pour d'autres fichiers sur la même branche que vous n'avez pas apportée la dernière fois, cela vous arrêtera avec un message "déjà à jour". C'est un symptôme de ne pas créer de branche quand nous devrions avoir, dans la branche "de" devrait être plus d'une branche différente.
la source
git merge --no-ff --no-commit -s outs branchname1
) est exactement ce que je cherchais! Merci!Je sais que je suis un peu en retard, mais c'est mon flux de travail pour la fusion de fichiers sélectifs.
la source
Le moyen le plus simple consiste à définir votre référentiel sur la branche avec laquelle vous souhaitez fusionner, puis à exécuter,
Si vous courez
vous verrez le fichier déjà mis en scène ...
Ensuite, exécutez
Facile.
la source
J'ai trouvé que ce message contenait la réponse la plus simple. Faites simplement:
Exemple:
Voir le post pour plus d'informations.
la source
Il est étrange que git ne dispose toujours pas d'un outil aussi pratique "prêt à l'emploi". Je l'utilise beaucoup lors de la mise à jour d'une ancienne branche de version (qui a encore beaucoup d'utilisateurs de logiciels) par seulement quelques corrections de bugs de la branche de version actuelle. Dans ce cas, il est souvent nécessaire d'obtenir rapidement quelques lignes de code du fichier dans le tronc, en ignorant beaucoup d'autres modifications (qui ne sont pas censées entrer dans l'ancienne version) ... Et bien sûr , la fusion interactive à trois voies est nécessaire dans ce cas,
git checkout --patch <branch> <file path>
n'est pas utilisable à cette fin de fusion sélective.Vous pouvez le faire facilement:
Ajoutez simplement cette ligne à la
[alias]
section de votre fichier global.gitconfig
ou local.git/config
:Cela implique que vous utilisez Beyond Compare. Changez simplement pour le logiciel de votre choix si nécessaire. Ou vous pouvez le changer en fusion automatique à trois voies si vous n'avez pas besoin de la fusion sélective interactive:
Ensuite, utilisez comme ceci:
Cela vous donnera la véritable opportunité de fusion arborescente sélective de n'importe quel fichier dans une autre branche.
la source
Ce n'est pas exactement ce que vous cherchiez, mais cela m'a été utile:
C'est un mélange de quelques réponses.
la source
git checkout HEAD file1
pour conserver la version actuelle et ne pas fusionner le fichierfile1
, on peut utiliser l'-p
option pour sélectionner une partie du fichier à fusionner. merci pour l'astuce!Je ferais un
De cette façon, vous pouvez limiter la plage de validations pour un modèle de fichier à partir d'une branche.
Volé à: http://www.gelato.unsw.edu.au/archives/git/0701/37964.html
la source
J'ai eu exactement le même problème que celui mentionné ci-dessus. Mais j'ai trouvé ce blog git plus clair en expliquant la réponse.
Commande à partir du lien ci-dessus:
la source
J'aime la réponse «git-interactive-merge» ci-dessus, mais il y en a une plus facile. Laissez git faire cela pour vous en utilisant une combinaison de rebase d'interactif et sur:
Donc, le cas est que vous voulez C1 et C2 de la branche 'fonctionnalité' (point de branche 'A'), mais rien du reste pour l'instant.
Ce qui, comme ci-dessus, vous dépose dans l'éditeur interactif où vous sélectionnez les lignes de «sélection» pour C1 et C2 (comme ci-dessus). Enregistrez et quittez, puis il poursuivra le rebase et vous donnera la branche 'temp' et également HEAD à master + C1 + C2:
Ensuite, vous pouvez simplement mettre à jour master vers HEAD et supprimer la branche temporaire et vous êtes prêt à partir:
la source
Et alors
git reset --soft branch
? Je suis surpris que personne ne l'ait encore mentionné.Pour moi, c'est le moyen le plus simple de sélectionner de manière sélective les modifications d'une autre branche, car, cette commande place dans mon arbre de travail, toutes les modifications de différence et je peux facilement choisir ou annuler celle dont j'ai besoin. De cette façon, j'ai un contrôle total sur les fichiers validés.
la source
Je sais que cette question est ancienne et qu'il existe de nombreuses autres réponses, mais j'ai écrit mon propre script appelé «pmerge» pour fusionner partiellement les répertoires. C'est un travail en cours et j'apprends toujours les scripts git et bash.
Cette commande utilise
git merge --no-commit
puis désapplique les modifications qui ne correspondent pas au chemin fourni.Utilisation:
git pmerge branch path
Exemple:
git merge develop src/
Je ne l'ai pas testé intensivement. Le répertoire de travail doit être exempt de toute modification non validée et de fichiers non suivis.
la source
Vous pouvez utiliser
read-tree
pour lire ou fusionner l'arborescence distante donnée dans l'index actuel, par exemple:Pour effectuer la fusion, utilisez
-m
plutôt.Voir aussi: Comment fusionner un sous-répertoire dans git?
la source
Une approche simple pour la fusion / validation sélective par fichier:
git checkout dstBranch git merge srcBranch // make changes, including resolving conflicts to single files git add singleFile1 singleFile2 git commit -m "message specific to a few files" git reset --hard # blow away uncommitted changes
la source
Si vous n'avez pas trop de fichiers modifiés, cela ne vous laissera aucun commit supplémentaire.
1. Branche en double temporairement
$ git checkout -b temp_branch
2. Réinitialiser au dernier commit souhaité
$ git reset --hard HEAD~n
, oùn
est le nombre de commits dont vous avez besoin pour revenir en arrière3. Extraire chaque fichier de la branche d'origine
$ git checkout origin/original_branch filename.ext
Vous pouvez maintenant valider et forcer push (pour écraser à distance), si nécessaire.
la source
Si vous avez seulement besoin de fusionner un répertoire particulier et de laisser tout le reste intact tout en préservant l'historique, vous pouvez éventuellement essayer ceci ... créer un nouveau
target-branch
hors dumaster
avant d'expérimenter.Les étapes ci-dessous supposent que vous avez deux branches
target-branch
etsource-branch
, et le répertoiredir-to-merge
que vous souhaitez fusionner se trouve dans lesource-branch
. Supposez également que vous avez d'autres répertoires commedir-to-retain
dans la cible que vous ne souhaitez pas modifier et conserver l'historique. Suppose également qu'il existe des conflits de fusion dans le fichierdir-to-merge
.la source
Lorsque seuls quelques fichiers ont changé entre les validations actuelles des deux branches, je fusionne manuellement les modifications en parcourant les différents fichiers.
git difftoll <branch-1>..<branch-2>
la source