Question Comment sélectionner une gamme de commits et fusionner dans une autre branche?


J'ai la disposition de dépôt suivante:

  • branche maîtresse (production)
  • l'intégration
  • travail

Ce que je veux faire, c’est choisir parmi une série de commits de la branche de travail et les fusionner dans la branche d’intégration. Je suis assez nouveau à git et je ne peux pas comprendre comment faire exactement cela (le choix de la cerise de commit varie dans une opération pas la fusion) sans déconner le dépôt. Des pointeurs ou des réflexions à ce sujet? Merci!


494
2018-01-03 09:50


origine


Réponses:


En ce qui concerne une gamme de commits, le choix des cerises est  était pas pratique.

Comme mentionné ci-dessous par Keith Kim, Git 1.7.2+ a introduit la possibilité de sélectionner une gamme de commits (mais vous devez toujours connaître conséquence de la cueillette des cerises pour la future fusion)

git cherry-pick "a 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 meilleur contrôle de séquençage"rebase [-i]"a, cependant.

damian  commentaires et nous met en garde:

Dans le "cherry-pick A..B" forme, A devrait être plus vieux que B.
S'ils sont dans le mauvais ordre, la commande échouera silencieusement.

Si vous voulez choisir le gamme B par D (compris) ce serait B^..D.
Voir "Git créer une branche à partir de la gamme des commits précédents?" pour illustrer.

Comme Jubobs mentions dans les commentaires:

Cela suppose que B n'est pas un commit racine; vous aurez un "unknown revision"erreur sinon.

Note: à partir de Git 2.9.x / 2.10 (Q3 2016), vous pouvez sélectionner une plage de validation directement sur une branche orpheline (tête vide): voir "Comment rendre une branche existante orpheline en git".


Réponse initiale (janvier 2010)

UNE rebase --onto serait mieux, où vous rejouez la gamme donnée de commit sur votre branche d'intégration, comme Charles Bailey décrit ici.
(aussi, recherchez "Voici comment vous transplanter une branche de sujet basée sur une branche à une autre" dans le git rebase man page, pour voir un exemple pratique de git rebase --onto)

Si votre agence 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

Cela va rejouer 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, à partir du working branche)

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

S'il y a un conflit lors de la relecture de l'un de ces commits:

  • soit le résoudre et exécuter "git rebase --continue".
  • ou ignorez ce patch et lancez plutôt "git rebase --skip"
  • ou annuler le tout avec un "git rebase --abort"(et remettre le integration branche sur le tmp branche)

Après ça rebase --onto, integration sera de retour lors de la dernière validation de la branche d’intégration (c’est-à-dire "tmp"branche + tous les commits rejoués)

Avec la cueillette des cerises ou rebase --onto, n'oubliez pas qu'il a des conséquences sur les fusions ultérieures, comme décrit ici.


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

Si vous souhaitez utiliser une approche par patch, alors "git format-patch | git am" et "git cherry" sont vos options.
  Actuellement, git cherry-pick n'accepte qu'un seul commit, mais si vous voulez choisir la plage B par D ce 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, lorsque vous devez "rejouer" une série de commits, le mot "replay" devrait vous pousser à utiliser le "rebase"fonctionnalité de Git.


639
2018-01-03 10:08



À partir de git v1.7.2, cherry pick peut accepter une gamme de commits:

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


116
2017-09-08 03:57



Êtes-vous sûr de ne pas vouloir fusionner les branches? Si la branche de travail ne dispose pas de validations récentes, vous pouvez simplement créer une nouvelle branche avec un HEAD au point souhaité.

Maintenant, si vous voulez vraiment choisir une gamme de commits, quelle que soit la raison, une manière élégante de le faire est de simplement appliquer un patch 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 fait git-rebase, mais sans avoir à jouer à des jeux. Vous pouvez ajouter --3way à git-am si vous avez besoin de fusionner. Assurez-vous qu'il n'y a pas d'autres fichiers * .patch déjà dans le répertoire où vous faites cela, si vous suivez les instructions textuellement ...


24
2018-01-04 09:32



J'ai enveloppé Le code de VonC dans un court script bash, git-multi-cherry-pick, pour un fonctionnement facile:

#!/bin/bash

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

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

Je l'utilise actuellement pour reconstituer l'historique d'un projet comportant à la fois du code tiers et des personnalisations mélangés dans le même tronc svn. Je sépare maintenant le code tiers de base, les modules 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 car j'ai deux arborescences dans le même référentiel, mais sans ancêtre partagé.


6
2018-03-31 14:20



Supposons que vous avez 2 branches,

"branchA": inclut les commits que vous souhaitez copier (de "commitA" à "commitB")

"brancheB": la branche dans laquelle vous voulez que les commits soient transférées de "brancheA"

1)

 git checkout <branchA>

2) obtenir les identifiants de "commitA" et "commitB"

3)

git checkout <branchB>

4)

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

5) Au cas où vous avez un conflit, résolvez-le et tapez

git cherry-pick --continue

continuer le processus de sélection des cerises.


6
2017-08-01 14:29



Toutes les options ci-dessus vous inviteront à résoudre les conflits de fusion. Si vous fusionnez des modifications validées pour une équipe, il est difficile de résoudre les conflits de fusion des développeurs et de continuer. Cependant, "git merge" fera la fusion en une seule fois, mais vous ne pourrez pas passer une série de révisions en argument. nous devons utiliser les commandes "git diff" et "git apply" pour faire la plage de fusion des tours. J'ai remarqué que "git apply" échouera si le fichier de correctif a diff pour trop de fichiers, nous devons donc créer un correctif par fichier et ensuite l'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 ces fichiers de la branche cible. Le statut de sortie de "git apply" n'est pas nul s'il n'est pas capable d'appliquer le patch, cependant si vous utilisez l'option -3way, il retournera à la fusion 3 voies et vous n'aurez pas à vous soucier de cet échec.

Voici 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=$1
    END=$2

    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
2017-09-07 06:48



Une autre option pourrait être de fusionner la stratégie avec la validation avant la plage, puis une fusion "normale" avec la dernière validation de cette plage (ou branche quand il s'agit de la dernière). Supposons donc que seuls les commits 2345 et 3456 du maître soient fusionnés dans la branche de fonctions:

maîtriser:
1234
2345
3456
4567

dans la branche de fonctionnalité:

git fusionner -s nôtre 4567
git fusion 2345

0
2017-08-16 12:47