Comment choisir une gamme de commits et fusionner dans une autre branche?

j'ai la disposition suivante du dépôt:

  • branche master (production)
  • intégration
  • en cours

ce que je veux réaliser, c'est choisir une gamme de propagations à partir de la branche de travail et la fusionner dans la branche d'intégration. Je suis assez nouveau à git et je ne peux pas comprendre comment faire exactement (la sélection de cerise de gamme de commit dans une opération pas la fusion) sans déconner le référentiel. Tous les pointeurs ou des pensées à ce sujet? Merci!

507
la source

7 ответов

quand il s'agit d'une gamme de commits, est était pas pratique.

Comme mentionnés ci-après par Keith Kim , Git 1.7.2+ a introduit la possibilité de piocher dans une série de commits (mais vous devez toujours être conscient de la conséquence de cherry-picking pour la fusion )

git cherry-pick "appris à choisir une gamme de commits

(par exemple " cherry-pick A..B " et " cherry-pick --stdin "), ainsi fait " git revert "; ceux-ci ne supportent pas le plus nicer sequencing control " rebase [-i] " a, cependant.

damian commente et nous avertit:

dans la " cherry-pick A..B "forme, A doit être plus ancien que B .

S'ils sont du mauvais ordre, la commande échouera silencieusement .

si vous voulez choisir la gamme B à D (inclus) qui serait B^..D .

Voir " Git créer une branche à partir de la gamme de la précédente s'engage? " comme illustration.

Jubobs , mentionne le dans les commentaires :

cela suppose que B n'est pas un Root commit; vous obtiendrez une erreur " unknown revision " autrement.

Note: à partir de Git 2.9.x / 2.10 (Q3 2016), vous pouvez sélectionner une gamme de commit directement sur une branche orpheline (empty head): voir " Comment faire de la branche existante un orphelin dans git ".


réponse Originale à cette question (janvier 2010)

A rebase --onto serait mieux, où vous rejouez la gamme donnée de commit sur le dessus de votre branche d'intégration, comme Charles Bailey décrit ici .

(aussi, cherchez "Voici comment vous transplanter une branche thématique basée sur une branche à une autre" dans la git rebase man page , pour voir un exemple pratique de git rebase --onto )

si votre branche actuelle est l'intégration:

# Checkout a new temporary branch at the current location
git checkout -b tmp

# Move the integration branch to the head of the new patchset
git branch -f integration last_SHA-1_of_working_branch_range

# Rebase the patchset onto tmp, the old location of integration
git rebase --onto tmp first_SHA-1_of_working_branch_range~1 integration

qui rejouera tout entre:

  • après le parent de first_SHA-1_of_working_branch_range (d'où le ~1 ): le premier commit que vous voulez rejouer
  • jusqu'à integration "(qui pointe vers le dernier commit que vous voulez rejouer, de la branche working )

à " tmp " (qui indique où integration pointait avant)

S'il y a un conflit quand l'un d'eux commet est rejoué:

  • soit résoudre et exécuter " git rebase --continue ".
  • ou sauter ce patch, et à la place exécuter " git rebase --skip "
  • ou annuler le tout avec un " git rebase --abort "et remettre la branche integration sur la branche tmp )

après que rebase --onto , integration sera de retour à la dernière commit de la branche d'intégration (c'est-à-dire tmp "commits branche + tous les rejoués)

avec "cherry-picking" ou rebase --onto , n'oubliez pas qu'il a des conséquences sur les fusions suivantes, comme décrit ici .


pur " cherry-pick solution " est discuté ici , et impliquerait quelque chose comme:

si vous voulez utiliser une approche patch, alors" git format-patch|git am "et" git cherry " sont vos options.

Actuellement, git cherry-pick accepte seulement un commit unique, mais si vous voulez choisir la gamme B à D qui serait B^..D en git lingo, donc

git rev-list --reverse --topo-order B^..D | while read rev 
do 
  git cherry-pick $rev || break 
done 

mais de toute façon, quand vous avez besoin de " rejouer" une série de commits, le mot "replay" devrait vous pousser à utiliser les " rebase " de Git.

659
répondu VonC 2018-04-28 09:44:24
la source

à partir de git v1.7.2 cerise pick peut accepter une gamme de commits:

git cherry-pick appris à choisir une gamme de commits (par exemple cherry-pick A..B et cherry-pick --stdin ), ainsi fait git revert ; ceux-ci ne supportent pas le contrôle de séquençage nicer rebase [-i] a, cependant.

119
répondu Keith Kim 2014-09-23 02:22:29
la source

Êtes-vous sûr que vous ne voulez pas fusionner les branches? Si la branche a quelques récentes s'engage vous ne voulez pas, vous pouvez simplement créer une nouvelle branche avec une TÊTE à l'endroit que vous voulez.

maintenant, si vous voulez vraiment choisir une gamme de commits, pour quelque raison que ce soit, une façon élégante de le faire est de simplement tirer un patchset et de l'appliquer à votre nouvelle branche d'intégration:

git format-patch A..B
git checkout integration
git am *.patch

c'est essentiellement ce que git-rebase est faire de toute façon, mais sans la nécessité de jouer à des jeux. Vous pouvez ajouter --3way à git-am si vous avez besoin de fusionner. Assurez-vous il n'y a pas d'autres *.patch les fichiers déjà dans le répertoire où vous faites cela, si vous suivez les instructions mot à mot...

24
répondu djs 2010-01-04 12:32:52
la source

supposons que vous avez deux branches,

"branchA" : comprend les commits que vous souhaitez copier à partir de "commitA" à "commitB"

"branchB": la branche que vous voulez que les commits soient transférés de "branchA"

1)

 git checkout <branchA>

2) Obtenir les IDs de "commitA" et" commib "

3)

git checkout <branchB>

4)

git cherry-pick <commitA>^..<commitB>

5) dans le cas vous avez un conflit, résolvez-le et tapez

git cherry-pick --continue

pour poursuivre le processus de cueillette.

9
répondu KostasA 2017-08-01 17:29:48
la source

j'ai enveloppé VonC code dans un court script bash, git-multi-cherry-pick , pour faciliter le fonctionnement:

#!/bin/bash

if [ -z  ]; then
    echo "Equivalent to running git-cherry-pick on each of the commits in the range specified.";
    echo "";
    echo "Usage:  "151900920" start^..end";
    echo "";
    exit 1;
fi

git rev-list --reverse --topo-order  | while read rev 
do 
  git cherry-pick $rev || break 
done 

je suis en train d'utiliser ceci alors que je reconstruis l'histoire d'un projet qui avait à la fois du code tiers et des personnalisations mélangées ensemble dans le même tronc svn. Je sépare maintenant le code de base de tiers, les modules de tiers et les personnalisations sur leurs propres branches git pour une meilleure compréhension des personnalisations à venir. git-cherry-pick est utile dans cette situation puisque j'ai deux arbres dans le même dépôt, mais sans ancêtre commun.

6
répondu Adam Franco 2017-05-23 14:33:32
la source

toutes les options ci-dessus vous inviteront à résoudre les conflits de fusion. Si vous fusionnez les changements engagés pour une équipe, il est difficile de résoudre les conflits de fusion de développeurs et de poursuivre. Cependant, "git merge" fera la fusion en un coup, mais vous ne pouvez pas passer une plage de révisions comme argument. nous devons utiliser les commandes" git diff "et" git apply " pour effectuer la plage de fusion de revs. J'ai observé que "git apply" échouera si le fichier patch a des différences pour trop de fichiers, donc nous avons pour créer un patch par fichier et ensuite appliquer. Notez que le script ne pourra pas supprimer les fichiers supprimés dans la branche source. C'est un cas rare, vous pouvez supprimer manuellement de tels fichiers de la branche cible. Le statut de sortie de "Git apply" n'est pas zéro s'il n'est pas capable d'appliquer le patch, cependant si vous utilisez l'option-3way il retombera à la fusion à 3 voies et vous n'avez pas à vous soucier de cet échec.

ci-dessous est le script.

enter code here



  #!/bin/bash

    # This script will merge the diff between two git revisions to checked out branch
    # Make sure to cd to git source area and checkout the target branch
    # Make sure that checked out branch is clean run "git reset --hard HEAD"


    START=
    END=

    echo Start version: $START
    echo End version: $END

    mkdir -p ~/temp
    echo > /tmp/status
    #get files
    git --no-pager  diff  --name-only ${START}..${END} > ~/temp/files
    echo > ~/temp/error.log
    # merge every file
    for file in `cat  ~/temp/files`
    do
      git --no-pager diff --binary ${START}..${END} $file > ~/temp/git-diff
      if [ $? -ne 0 ]
      then
#      Diff usually fail if the file got deleted 
        echo Skipping the merge: git diff command failed for $file >> ~/temp/error.log
        echo Skipping the merge: git diff command failed for $file
        echo "STATUS: FAILED $file" >>  /tmp/status
        echo "STATUS: FAILED $file"
    # skip the merge for this file and continue the merge for others
        rm -f ~/temp/git-diff
        continue
      fi

      git apply  --ignore-space-change --ignore-whitespace  --3way --allow-binary-replacement ~/temp/git-diff

      if [ $? -ne 0 ]
       then
#  apply failed, but it will fall back to 3-way merge, you can ignore this failure
         echo "git apply command filed for $file"
       fi
       echo
       STATUS=`git status -s $file`


       if [ ! "$STATUS" ]
       then
#   status is null if the merged diffs are already present in the target file
         echo "STATUS:NOT_MERGED $file"
         echo "STATUS: NOT_MERGED $file$"  >>  /tmp/status
       else
#     3 way merge is successful
         echo STATUS: $STATUS
         echo "STATUS: $STATUS"  >>  /tmp/status
       fi
    done

    echo GIT merge failed for below listed files

    cat ~/temp/error.log

    echo "Git merge status per file is available in /tmp/status"
2
répondu Yoganand Bijapur 2016-09-07 12:08:39
la source

une autre option pourrait être de fusionner avec notre stratégie à la propagation avant la portée et ensuite une fusion "normale" avec la dernière propagation de cette portée (ou branche quand c'est la dernière). Supposons donc que seulement 2345 et 3456 commits of master soient fusionnés dans la branche feature:

master:
1234
2345
3456
4567

en fonction de la branche:

git merge -s ours 4567
git merge 2345
0
répondu Koos Vriezen 2015-08-16 15:47:03
la source

Autres questions sur git git-merge git-cherry-pick