Question

J'ai la disposition du référentiel suivant:

  • branche principale (production)
  • intégration
  • travail

Ce que je veux atteindre est de cerise choisir une gamme de commits de la branche de travail et la fusion dans la branche d'intégration. Je assez nouveau pour connard et je ne peux pas comprendre comment faire exactement cela (le picorage commit des gammes en une seule opération pas la fusion) sans déconner vers le haut du dépôt. Tous les pointeurs ou réflexions sur ce sujet? Merci!

Était-ce utile?

La solution

En ce qui concerne une gamme de commits, picorage est n'a pas pratique.

mentionné ci-dessous par conséquence de picorage pour la future fusion )

  

écrémer git » appris à choisir une gamme de commits
  (Par exemple "cherry-pick A..B" et "cherry-pick --stdin"), tout comme "git revert"; ceux-ci ne prennent pas en charge la plus belle contrôle de séquençage « rebase [-i] » a, cependant.

commentaires et nous met en garde contre:

  

Dans la forme de "cherry-pick A..B", A devrait être plus que B .
   Si elles sont le mauvais ordre la commande échouer en mode silencieux .

Si vous voulez choisir la gamme B par D (inclus) qui serait B^..D .
Voir " Git création d'une branche de la gamme des précédentes commits? " à titre d'illustration.

Jubobs mentionne dans les commentaires :

  

Cela suppose que B n'est pas un engagement racine; vous obtiendrez une erreur « unknown revision » autrement.

Note: Depuis Git 2.9.x / 2.10 (Q3 2016), vous pouvez écrémer une gamme de commettre directement sur une branche orpheline (tête vide): voir " Comment faire une branche existante orphelin git ".


Réponse originale (Janvier 2010)

rebase --onto serait mieux, où vous rejouez la plage donnée de s'engager au-dessus de votre branche d'intégration, comme Charles Bailey décrit ici .
(Aussi, recherchez « Voici comment vous transplanter une branche thématique basée sur une branche à l'autre » dans la git rebase page de manuel, pour voir un exemple concret de git rebase --onto)

Si votre branche courante 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 rejouer tout entre:

  • après le parent de first_SHA-1_of_working_branch_range (d'où le ~1): la première vous commettras voulez rejouer
  • jusqu'à « integration » (qui pointe vers le dernier que vous commettez voulez rejouer, de la branche working)

à "tmp" (qui pointe à l'endroit où integration pointait avant)

En cas de conflit lorsque l'un de ces commits est rejoué:

  • soit le résoudre et exécuter « git rebase --continue ».
  • ou sauter ce patch, et au lieu de courir "git rebase --skip"
  • ou annuler la toute chose 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 validation de la branche d'intégration (qui est la branche « tmp » + tous les commits rejoués)

Avec picorage ou rebase --onto, ne pas oublier qu'elle a des conséquences sur les fusions successives, comme décrit ici .


Une solution pure "de cherry-pick" est discuté ici et impliquerait quelque chose comme:

  

Si vous souhaitez utiliser une approche patch puis "le format-patch git | git am" et "cerise git" sont vos options
.   À l'heure actuelle, git cherry-pick accepte un seul commit, mais si vous voulez choisir la gamme B par D qui serait B^..D dans 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 fonctionnalité « rejouer » une gamme de commits, le mot « rejouer » devrait vous pousser à utiliser le « rebase » de Git.

Autres conseils

Au choix git cerise v1.7.2 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), donc a fait git revert; ceux-ci ne prennent pas en charge a, bien que le rebase [-i] plus agréable de contrôle de séquençage.

Supposons que vous avez 2 branches,

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

"branchB": la branche que vous voulez que les commits à transférer de "branchA"

1)

 git checkout <branchA>

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

3)

git checkout <branchB>

4)

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

5) Si vous avez un conflit, le résoudre et le type

git cherry-pick --continue

pour continuer le processus écrémer.

Êtes-vous sûr que vous ne voulez pas fusionner réellement les branches? Si la branche de travail a des commits récents vous ne voulez pas, vous pouvez simplement créer une nouvelle branche avec une tête au point que vous voulez.

Maintenant, si vous voulez vraiment cerise choisir une gamme de commits, pour une raison quelconque, d'une manière élégante de faire est de simplement tirer d'un patchset et l'appliquer à votre nouvelle branche d'intégration:

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

Ceci est essentiellement ce que git-rebase fait de toute façon, mais sans avoir besoin de 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 verbatim ...

J'enroulai 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 

J'utilise actuellement ce que je reconstruis l'histoire d'un projet qui avait à la fois le code 3e parti et personnalisations mélangées dans le même tronc svn. Je vais partager maintenant à part le code 3ème partie noyau, modules 3ème partie, et personnalisations sur leurs propres branches git pour une meilleure compréhension des personnalisations à l'avenir. git-cherry-pick est utile dans cette situation depuis que j'ai deux arbres dans le même référentiel, mais sans ancêtre commun.

Toutes les options ci-dessus vous invite à résoudre les conflits de fusion. Si vous fusionnez des changements engagés pour une équipe, il est difficile de se résoudre les conflits de fusion des développeurs et continuer. Cependant, « git merge » fera la fusion en un seul coup, mais vous ne pouvez pas passer une série de révisions en argument. nous devons utiliser « git diff » et « git appliquer » les commandes pour faire la gamme de fusion de régime moteur. Je l'ai observé que « git appliquer » échouera si le fichier patch a diff pour le fichier trop grand nombre, donc nous devons créer un patch par fichier, puis appliquer. Notez que le script ne sera pas en mesure de supprimer les fichiers qui sont supprimés dans la branche source. Ceci est un cas rare, vous pouvez supprimer manuellement ces fichiers de branche cible. L'état de la sortie de « git appliquer » n'est pas nul si elle ne peut pas appliquer le patch, si vous utilisez l'option -3way il retombera à 3 fusion de façon et vous n'avez pas à vous soucier de cet échec.

Ci-dessous 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"

Une autre option pourrait être de fusionner avec la nôtre de stratégie à la validation avant la plage, puis une fusion « normale » avec la dernière livraison de cette plage (ou branche quand il est le dernier). Ainsi, supposons que 2345 et 3456 commits de maître à fusionner dans la branche de fonction:

master:
1234
2345
3456
4567

dans la branche de fonction:

git merge -s ours 4567
git merge 2345
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top