Comment fusionner ou sélectionner de manière sélective des changements dans une autre twig de Git?

J’utilise git sur un nouveau projet qui a deux twigs 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ûr
  • exp1 : twig expérimentale # 1
  • exp2 : twig expérimentale # 2

exp1 et exp2 représentent deux approches architecturales très différentes. Jusqu’à ce que je sois plus avancé, je n’ai aucun moyen de savoir lequel (si l’un ou l’autre) fonctionnera. Au fur et à mesure que je progresse dans une twig, j’ai parfois des modifications qui seraient utiles dans l’autre twig et je voudrais les fusionner.

Quelle est la meilleure façon de fusionner des changements sélectifs d’une twig de développement à une autre tout en laissant de côté tout le rest?

Approches que j’ai considérées:

  1. git merge --no-commit suivi d’un désassemblage manuel d’un grand nombre de modifications que je ne souhaite pas rendre communes entre les twigs.

  2. Copie manuelle des fichiers communs dans un répertoire temporaire suivie d’une git checkout pour passer à l’autre twig, puis copie plus manuelle du répertoire temporaire dans l’arborescence de travail.

  3. Une variation sur ce qui précède. Abandonnez les twigs exp 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 à des erreurs. J’espère qu’il y a une meilleure approche; quelque chose qui s’apparente à un paramètre de chemin de filtrage qui rendrait git-merge plus sélectif.

    Vous utilisez la commande cherry-pick pour obtenir des commits individuels d’une twig.

    Si les modifications souhaitées ne sont pas validées individuellement, utilisez la méthode indiquée ici pour fractionner le commit en des validations individuelles . En gros, vous utilisez git rebase -i pour obtenir l’engagement initial à éditer, puis git reset HEAD^ pour annuler sélectivement les modifications, puis git commit à valider ce bit en tant que nouveau commit dans l’historique.

    Il existe une autre méthode intéressante dans Red Hat Magazine, où ils utilisent git add --patch ou éventuellement git add --interactive ce qui vous permet d’append des parties d’un morceau si vous souhaitez diviser différentes modifications dans un fichier individuel (search dans cette page pour “split”).

    Après avoir divisé les modifications, vous pouvez désormais sélectionner celles que vous souhaitez.

    J’ai eu exactement le même problème que mentionné ci-dessus. Mais j’ai trouvé cela plus clair en expliquant la réponse.

    Résumé:

    • Vérifiez les chemins de la twig que vous souhaitez fusionner,

       $ git checkout source_branch -- ... 
    • ou pour fusionner sélectivement des mecs

       $ git checkout -p source_branch -- ... 

      Sinon, utilisez reset puis ajoutez avec l’option -p ,

       $ git reset ... $ git add -p ... 
    • Enfin, commettez

       $ git commit -m "'Merge' these changes" 

    Pour fusionner de manière sélective des fichiers d’une twig à une autre, exécutez

     git merge --no-ff --no-commit branchX 

    branchX est la twig que vous souhaitez fusionner dans la twig en cours.

    L’option --no-commit mettra en scène les fichiers qui ont été fusionnés par Git sans les engager réellement. Cela vous donnera la possibilité de modifier les fichiers fusionnés comme vous le souhaitez, puis de les valider vous-même.

    Selon la manière dont vous souhaitez fusionner des fichiers, il existe quatre cas:

    1) Vous voulez une vraie fusion.

    Dans ce cas, vous acceptez les fichiers fusionnés de la manière dont Git les a fusionnés automatiquement et les a validés.

    2) Il y a des fichiers que vous ne voulez pas fusionner.

    Par exemple, vous souhaitez conserver la version dans la twig actuelle et ignorer la version de la twig à partir de laquelle vous effectuez la fusion.

    Pour sélectionner la version dans la twig actuelle, exécutez:

     git checkout HEAD file1 

    Cela permettra de récupérer la version de file1 dans la twig en cours et de remplacer le file1 généré automatiquement par Git.

    3) Si vous voulez la version dans branchX (et non une vraie fusion).

    Courir:

     git checkout branchX file1 

    Cela permettra de récupérer la version de file1 dans branchX et de remplacer le branchX fusionné automatiquement par Git.

    4) Le dernier cas est si vous souhaitez sélectionner uniquement des fusions spécifiques dans file1 .

    Dans ce cas, vous pouvez éditer directement le file1 , le mettre à jour selon ce que vous souhaitez que la version de file1 devienne, puis valider.

    Si Git ne peut pas fusionner automatiquement un fichier, il signalera le fichier comme “non fusionné ” et produira une copie où vous devrez résoudre les conflits manuellement.


    Pour expliquer davantage avec un exemple, disons que vous voulez fusionner branchX dans la twig courante:

     git merge --no-ff --no-commit branchX 

    Vous exécutez ensuite la commande git status pour afficher l’état des fichiers modifiés.

    Par exemple:

     git status # On branch master # Changes to be committed: # # modified: file1 # modified: file2 # modified: file3 # Unmerged paths: # (use "git add/rm ..." as appropriate to mark resolution) # # both modified: file4 # 

    file1 , file2 et file3 sont les fichiers git ont fusionné automatiquement avec succès.

    Cela signifie que les modifications branchX aux fichiers master et branchX 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 la commande git diff --cached ;

     git diff --cached file1 git diff --cached file2 git diff --cached file3 

    Si vous trouvez que certains fusionnent indésirable alors vous pouvez

    1. éditer le fichier directement
    2. enregistrer
    3. git commit

    Si vous ne souhaitez pas fusionner file1 et souhaitez conserver la version dans la twig actuelle

    Courir

     git checkout HEAD file1 

    Si vous ne voulez pas fusionner file2 et que vous souhaitez uniquement la version dans branchX

    Courir

     git checkout branchX file2 

    Si vous voulez que file3 soit fusionné automatiquement, ne faites rien.

    Git l’a déjà fusionné à ce stade.

    file4 ci-dessus est une fusion ratée par Git. Cela signifie qu’il y a des changements dans les deux twigs qui se produisent sur la même ligne. C’est là que vous devrez résoudre les conflits manuellement. Vous pouvez supprimer la fusion effectuée en modifiant directement le fichier ou en exécutant la commande checkout pour la version de la twig que vous voulez que file4 devienne.

    Enfin, n’oubliez pas de git commit .

    Je n’aime pas les approches ci-dessus. Utiliser cherry-pick est très utile pour choisir un seul changement, mais c’est pénible si vous souhaitez apporter toutes les modifications, à l’exception de certaines d’entre elles. Voici mon approche

    Il n’y a pas d’argument --interactive vous pouvez passer à git merge.

    Voici l’alternative:

    Vous avez des changements dans les fonctionnalités de votre twig et vous voulez les faire «maisortingser», mais pas toutes (c.-à-d. Que vous ne voulez pas choisir et valider chacune d’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, emballez-le simplement dans un script shell, changez le maître en $ et changez la fonctionnalité en $ depuis 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 

    Il y a une autre façon de faire:

     git checkout -p 

    C’est un mélange entre git checkout et git add -p et peut-être tout à fait ce que vous cherchez:

      -p, --patch Interactively select hunks in the difference between the  (or the index, if unspecified) and the working tree. The chosen hunks are then applied in reverse to the working tree (and if a  was specified, the index). This means that you can use git checkout -p to selectively discard edits from your current working tree. See the “Interactive Mode” section of git-add(1) to learn how to operate the --patch mode. 

    Bien que certaines de ces réponses soient plutôt bonnes, je pense qu’aucune d’entre elles n’a répondu à la contrainte d’origine de OP: sélectionner des fichiers particuliers dans des twigs particulières. Cette solution le fait, mais peut être fastidieuse s’il y a beaucoup de fichiers.

    Disons que vous avez les twigs master , exp1 et exp2 . Vous voulez fusionner un fichier de chacune des twigs expérimentales en master. Je ferais quelque chose comme ça:

     git checkout master git checkout exp1 path/to/file_a git checkout exp2 path/to/file_b # save these files as a stash git stash # merge stash with master git merge stash 

    Cela vous donnera des diffs dans le fichier pour chacun des fichiers que vous voulez. Rien de plus. Rien de moins. Il est utile de modifier radicalement les fichiers entre les versions – dans mon cas, changer une application de Rails 2 à Rails 3.

    EDIT : cela va fusionner les fichiers, mais fait une fusion intelligente. Je n’ai pas réussi à comprendre comment utiliser cette méthode pour obtenir des informations sur les différences dans le fichier (peut-être que ce serait toujours le cas pour les différences extrêmes. Les petites choses comme les espaces sont fusionnées sauf si vous utilisez l’ -s recursive -X ignore-all-space option -s recursive -X ignore-all-space )

    La réponse de 1800 INFORMATION est tout à fait correcte. Comme git noob, “utiliser git cherry-pick” ne me suffisait pas pour comprendre cela sans un peu plus de recherche sur Internet, alors j’ai pensé publier un guide plus détaillé au cas où quelqu’un bateau similaire.

    Mon cas d’utilisation voulait attirer sélectivement des modifications de la twig github de quelqu’un d’autre dans la mienne. Si vous avez déjà une twig locale avec les modifications, il vous suffit de suivre les étapes 2 et 5 à 7.

    1. Créez (si non créé) une twig locale avec les modifications que vous souhaitez apporter.

      $ git branch mybranch

    2. Mettez-y dedans.

      $ git checkout mybranch

    3. Déroulez les modifications que vous voulez du compte de l’autre personne. Si vous ne l’avez pas encore fait, vous voudrez les append en tant que télécommande.

      $ git remote add repos-w-changes

    4. Retirez tout de leur twig.

      $ git pull repos-w-changes branch-i-want

    5. Affichez les journaux de validation pour voir quelles modifications vous souhaitez:

      $ git log

    6. Revenez à la twig dans laquelle vous souhaitez extraire les modifications.

      $ git checkout originalbranch

    7. Cherry cueille tes commits, un par un, avec les hashes.

      $ git cherry-pick -x hash-of-commit

    Astuce Hat: http://www.sourcemage.org/Git_Guide

    Voici comment remplacer le fichier Myclass.java dans la twig principale avec Myclass.java dans la twig Myclass.java . Cela fonctionnera même si Myclass.java n’existe pas sur master .

     git checkout master git checkout feature1 Myclass.java 

    Notez que cela écrasera – et non fusionnera – et ignorera plutôt les modifications locales dans la twig principale.

    Le moyen le plus simple de fusionner des fichiers spécifiques à partir de deux twigs ne consiste pas simplement à remplacer des fichiers spécifiques par des fichiers provenant d’une autre twig.

    Première étape: Diff les twigs

    git diff branch_b > my_patch_file.patch

    Crée un fichier patch de la différence entre la twig en cours et branch_b

    Deuxième étape: appliquer le correctif sur les fichiers correspondant à un motif

    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 motif d’inclusion.

    Les slashes n’ont pas besoin d’être échappés.

    En outre, vous pouvez utiliser –exclude à la place et l’appliquer à tout, sauf aux fichiers correspondant au modèle, ou inverser le patch avec -R.

    L’option -p1 correspond à la commande de correctif * unix et au fait que le contenu du fichier de correctif ajoute chaque nom de fichier à a/ ou b/ (ou plus, selon la façon dont le fichier de correctif a été généré). il peut trouver le vrai fichier dans le chemin d’access au fichier auquel le correctif doit être appliqué.

    Consultez la page de manuel relative à git-apply pour plus d’options.

    Troisième étape: il n’y a pas de troisième étape

    Évidemment, vous voudriez commettre vos modifications, mais qui peut dire que vous n’avez pas d’autres réglages à effectuer avant de faire votre validation.

    Voici comment vous pouvez obtenir l’historique pour suivre quelques fichiers d’une autre twig avec un minimum de tracas, même si une fusion plus “simple” aurait apporté beaucoup plus de changements que vous ne voulez pas.

    Tout d’abord, vous prendrez l’initiative inhabituelle de déclarer à l’avance que ce que vous êtes sur le sharepoint faire est une fusion, sans que vous ne fassiez quoi que ce soit aux fichiers de votre répertoire de travail:

     git merge --no-ff --no-commit -s ours branchname1 

    . . . où “branchname” est ce dont vous prétendez être la fusion. Si vous vous engagez tout de suite, cela ne changerait rien mais cela montrerait encore des ancêtres de l’autre twig. Vous pouvez append plus de twigs / tags / etc. sur la ligne de commande si vous en avez besoin également. Cependant, à ce stade, il n’y a aucune modification à valider. Procurez-vous ensuite les fichiers des autres révisions.

     git checkout branchname1 -- file1 file2 etc 

    Si vous fusionniez à partir de plusieurs autres twigs, répétez les opérations si nécessaire.

     git checkout branchname2 -- file3 file4 etc 

    Maintenant, les fichiers de l’autre twig sont dans l’index, prêts à être validés, avec l’historique.

     git commit 

    et vous aurez beaucoup d’explications à faire dans ce message de validation.

    S’il vous plaît noter que, si ce n’était pas clair, que c’est une chose foirée à faire. Ce n’est pas dans l’esprit de ce qu’est une “twig”, et le choix des cerises est une manière plus honnête de faire ce que vous feriez, ici. Si vous voulez faire une autre “fusion” pour d’autres fichiers sur la même twig que vous n’avez pas apscope la dernière fois, cela vous arrêtera avec un message “déjà à jour”. C’est un symptôme de ne pas twigr lorsque nous devrions avoir, dans la twig “de” devrait être plus d’une twig différente.

    Je sais que je suis un peu en retard mais c’est mon workflow pour fusionner des fichiers sélectifs.

     #make a new branch ( this will be temporary) git checkout -b newbranch # grab the changes git merge --no-commit featurebranch # unstage those changes git reset HEAD (you can now see the files from the merge are unstaged) # now you can chose which files are to be merged. git add -p # remember to "git add" any new files you wish to keep git commit 

    J’ai trouvé ce post contenant la réponse la plus simple. Faire simplement:

     $ #git checkout   

    Exemple:

     $ #pulling .gitignore file from branchB into current branch $ git checkout branchB .gitignore 

    Voir le post pour plus d’informations.

    Le plus simple est de définir votre repo sur la twig avec laquelle vous souhaitez fusionner, puis de l’exécuter,

     git checkout [branch with file] [path to file you would like to merge] 

    Si tu cours

     git status 

    vous verrez le fichier déjà mis en scène …

    Puis courir

     git commit -m "Merge changes on '[branch]' to [file]" 

    Simple.

    Il est étrange que Git ne dispose toujours pas d’un outil aussi pratique “prêt à l’emploi”. Je l’utilise beaucoup lorsque je mets à jour une ancienne version de twig (qui a encore beaucoup d’utilisateurs de logiciels) par quelques corrections de bugs de la twig de la 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 changements (qui ne sont pas censés entrer dans l’ancienne version) … Et bien sûr, une fusion interactive à trois voies est nécessaire dans ce cas, git checkout --patch n’est pas utilisable pour cette fusion sélective.

    Vous pouvez le faire facilement:

    Ajoutez simplement cette ligne à la section [alias] dans votre .gitconfig global .gitconfig ou local .git/config :

     [alias] mergetool-file = "!sh -c 'git show $1:$2 > $2.theirs; git show $(git merge-base $1 $(git rev-parse HEAD)):$2 > $2.base; /C/BCompare3/BCompare.exe $2.theirs $2 $2.base $2; rm -f $2.theirs; rm -f $2.base;' -" 

    Cela implique que vous utilisez Beyond Compare. Changez simplement le logiciel de votre choix si nécessaire. Ou vous pouvez le transformer en fusion automatique à trois voies si vous n’avez pas besoin de la fusion sélective interactive:

     [alias] mergetool-file = "!sh -c 'git show $1:$2 > $2.theirs; git show $(git merge-base $1 $(git rev-parse HEAD)):$2 > $2.base; git merge-file $2 $2.base $2.theirs; rm -f $2.theirs; rm -f $2.base;' -" 

    Ensuite, utilisez comme ceci:

     git mergetool-file   

    Cela vous donnera la véritable opportunité de fusion sélective arborescente de n’importe quel fichier dans une autre twig.

    J’ai eu exactement le même problème que mentionné ci-dessus. Mais j’ai trouvé ce blog plus clair en expliquant la réponse.

    Commande à partir du lien ci-dessus:

     #You are in the branch you want to merge to git checkout   

    Ce n’est pas exactement ce que vous cherchiez, mais cela m’a été utile:

     git checkout -p  --  ... 

    C’est un mélange de quelques réponses.

    Je ferais un

    git diff commit1..commit2 filepattern | git-apply –index && git commit

    De cette façon, vous pouvez limiter la plage de validation pour un modèle de fichier à partir d’une twig.

    Volé de: http://www.gelato.unsw.edu.au/archives/git/0701/37964.html

    J’aime la réponse «git-interactive-merge» ci-dessus, mais il y en a une plus facile. Laissez git le faire pour vous en utilisant une combinaison de rebase de interactive et sur:

      A---C1---o---C2---o---o feature / ----o---o---o---o master 

    Donc, le cas est que vous voulez C1 et C2 de la twig ‘feature’ (sharepoint twigment ‘A’), mais aucun des autres pour le moment.

     # git branch temp feature # git checkout master # git rebase -i --onto HEAD A temp 

    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). Sauvegardez et quittez, puis il procédera à la rebase et vous donnera la twig ‘temp’ ainsi que HEAD au master + C1 + C2:

      A---C1---o---C2---o---o feature / ----o---o---o---o-master--C1---C2 [HEAD, temp] 

    Ensuite, vous pouvez simplement mettre à jour master pour HEAD et supprimer la twig temp et vous êtes prêt à aller:

     # git branch -f master HEAD # git branch -d temp 

    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 des répertoires. C’est un travail en cours et j’apprends encore les scripts git et bash.

    Cette commande utilise git merge --no-commit , puis annule 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é de manière approfondie. Le répertoire de travail doit être exempt de modifications non validées et de fichiers non suivis.

     #!/bin/bash E_BADARGS=65 if [ $# -ne 2 ] then echo "Usage: `basename $0` branch path" exit $E_BADARGS fi git merge $1 --no-commit IFS=$'\n' # list of changes due to merge | replace nulls w newlines | ssortingp lines to just filenames | ensure lines are unique for f in $(git status --porcelain -z -uno | tr '\000' '\n' | sed -e 's/^[[:graph:]][[:space:]]\{1,\}//' | uniq); do [[ $f == $2* ]] && continue if git reset $f >/dev/null 2>&1; then # reset failed... file was previously unversioned echo Deleting $f rm $f else echo Reverting $f git checkout -- $f >/dev/null 2>&1 fi done unset IFS 

    Vous pouvez utiliser read-tree pour lire ou fusionner l’arborescence distante donnée dans l’index actuel, par exemple:

     git remote add foo git@example.com/foo.git git fetch foo git read-tree --prefix=my-folder/ -u foo/master:trunk/their-folder 

    Pour effectuer la fusion, utilisez plutôt -m .

    Voir aussi: Comment fusionner un sous-répertoire dans git?

    Lorsque seuls quelques fichiers ont été modifiés entre les commits actuels des deux twigs, je fusionne manuellement les modifications en parcourant les différents fichiers.

    git difftoll ..

    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