Pregunta

Tengo el siguiente esquema de repositorio:

  • rama principal (de producción)
  • integración
  • trabajar

Lo que quiero lograr es la cereza recoger una serie de confirmaciones de la rama de trabajo y se funden en la rama de integración. Me bastante nuevo en Git y no puedo encontrar la manera de hacer exactamente esto (el cherry picking de las gamas de comprometerse en una operación de la fusión no) sin estropear el repositorio de arriba. Cualquier indicador o pensamientos sobre esto? Gracias!

¿Fue útil?

Solución

Cuando se trata de una serie de confirmaciones, cherry-picking es era no es práctico.

Como se menciona a continuación por Keith Kim , Git 1.7.2+ introdujo la posibilidad de cereza recoger una serie de confirmaciones (pero que todavía tienen que ser conscientes de la consecuencia de cherry picking para una futura fusión )

  

cherry-pick git" aprendió a recoger una serie de confirmaciones
  (Por ejemplo "cherry-pick A..B" y "cherry-pick --stdin"), también lo hizo "git revert"; éstos no son compatibles con el control de secuencia más agradable "rebase [-i]" tiene, sin embargo.

Damian comentarios y nos advierte:

  

En la forma "cherry-pick A..B", A debe ser mayor que B .
   Si son el orden equivocado el comando fallará sin .

Si usted quiere recoger el B gama través D (inclusive) que sería B^..D .
Consulte " Git crear rama de la gama de confirmaciones anteriores? " como una ilustración.

Jubobs menciona en los comentarios :

  

Esto supone que B no es una raíz cometer; obtendrá un error "unknown revision" en caso contrario.

Nota: a partir de Git 2.9.x / 2,10 (Q3 2016), se pueden seleccionar los diversos comprometerse directamente en una rama huérfano (cabeza vacía): véase " Como hacer rama existente huérfano en git ".


Respuesta original (enero de 2010)

A rebase --onto sería mejor, en el que reproducir la gama dada de comprometerse en la parte superior de la rama de la integración, como Charles Bailey describe aquí .
(También, busque "Aquí es cómo le trasplantar una rama tema sobre la base de una rama a otra" en el git rebase página del manual , para ver un ejemplo práctico de git rebase --onto)

Si su rama actual es la integración:

# 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

Esto se volverá a reproducir todo lo que entre:

  • después de que el padre de first_SHA-1_of_working_branch_range (de ahí el ~1): la primera se comprometen desea volver a reproducir
  • hasta "integration" (que apunta al último comprometen desea volver a reproducir, de la rama working)

a "tmp" (que apunta a donde integration estaba apuntando antes)

Si existe algún conflicto cuando una de esas confirmaciones se repite:

  • o bien resolverlo y ejecutar "git rebase --continue".
  • o saltarse este parche, y en lugar de correr "git rebase --skip"
  • o cancelar el todas las cosas con un "git rebase --abort" (y volver a poner la rama integration en la rama tmp)

Después de eso rebase --onto, integration estará de nuevo en la última confirmación de la rama de integración (que es "tmp" rama + todas las confirmaciones repite)

Con cherry-picking o rebase --onto, no se olvide que tiene consecuencias en las siguientes fusiones, como describe aquí .


Una solución pura "cherry-pick" es discuten aquí , e implicaría algo como:

  

Si desea utilizar un enfoque de parches a continuación. "Git formato de parche | am git" y "git cereza" son sus opciones
  Actualmente, git cherry-pick acepta un solo cometió, pero si usted quiere recoger el B gama través D que sería B^..D en la jerga de Git, por lo

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

Pero de todos modos, cuando se necesita "repetición" una serie de confirmaciones, la palabra "repetición" debe empujar a utilizar la función de "rebase" de Git.

Otros consejos

Como recogida de cereza v1.7.2 git puede aceptar una serie de confirmaciones:

  

git cherry-pick aprendió a recoger una serie de confirmaciones (por ejemplo cherry-pick A..B y cherry-pick --stdin), también lo hizo git revert; éstos no son compatibles con la rebase [-i] control de secuencia más bonito tiene, sin embargo.

Suponga que tiene 2 ramas,

"branchA": incluye confirmaciones que desea copiar (desde "commitA" a "commitB"

"branchB": la rama desea que los compromete a ser transferidos de "branchA"

1)

 git checkout <branchA>

2) obtener los identificadores de "commitA" y "commitB"

3)

git checkout <branchB>

4)

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

5) En caso de que tenga un conflicto, resolverlo y escriba

git cherry-pick --continue

para continuar con el proceso de cereza-Pick.

¿Está seguro de que no desea combinar en realidad las ramas? Si la rama de trabajo tiene algunos commits recientes que no desea, puede simplemente crear una nueva rama con una cabeza en el punto que desee.

Ahora, si realmente quiere cereza recoger una serie de confirmaciones, por cualquier razón, una manera elegante de hacer esto es simplemente tirar de un conjunto de parches y aplicarlo a su nueva rama de la integración:

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

Esto es esencialmente lo git-rebase está haciendo de todos modos, pero sin la necesidad de jugar juegos. Se pueden añadir a --3way git-am si necesita fusión. Asegúrese de que no hay otra * .patch ya los archivos en el directorio donde se hace esto, si se siguen las instrucciones pie de la letra ...

I envuelto código de VonC en una escritura del golpe corto, git-multi-cherry-pick, para facilitar la ejecución:

#!/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 

Actualmente estoy usando esto como reconstruyo la historia de un proyecto que tenía tanto el código 3 ª parte y personalizaciones mezclados juntos en el mismo tronco SVN. Ahora estoy división de código aparte núcleo tercera parte, los módulos de 3 ª parte, y las personalizaciones en sus propias ramas git para una mejor comprensión de las personalizaciones en el futuro. git-cherry-pick es útil en esta situación ya que tengo dos árboles en el mismo repositorio, pero sin un ancestro común.

Todas las opciones anteriores le pedirá a conflictos de fusión resolución. Si está fusionando cambios confirmados para un equipo, es difícil conseguir resolver los conflictos de fusión de los desarrolladores y proceder. Sin embargo, "git merge" va a hacer la fusión en una sola toma, pero que no puede pasar una serie de revisiones como argumento. tenemos que utilizar "git diff" y "Git aplicar" comandos para hacer el rango de fusión de revoluciones. He observado que "Git aplicar" fallará si el archivo de revisión tiene diferencias para demasiados archivos, por lo que tenemos para crear un parche por archivo y luego aplicar. Tenga en cuenta que el guión no será capaz de eliminar los archivos que se eliminan en la bifurcación de origen. Este es un caso raro, puede eliminar manualmente estos archivos de bifurcación de destino. El estado de salida de "Git aplicar" no es cero si no es capaz de aplicar el parche, sin embargo si se utiliza la opción -3way va a caer de nuevo a 3 vías de combinación y no tiene que preocuparse por este fracaso.

A continuación se muestra la secuencia de comandos.

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"

Otra opción podría ser la fusión con nuestra estrategia para el envío de datos antes de que el rango de fusión y luego un 'normal' con la última confirmación de ese rango (o rama cuando es el último). Así que supongamos que sólo 2.345 y 3.456 confirmaciones de maestro que se fusionaron en rama de la característica:

master:
1234
2345
3456
4567

en la rama de la característica:

git merge -s ours 4567
git merge 2345
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top