Como cereza recoger una serie de confirmaciones y se funden en otra rama?
-
22-09-2019 - |
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!
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 queB
.
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 ramaworking
)
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 ramaintegration
en la ramatmp
)
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 elB
gama travésD
que seríaB^..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 ejemplocherry-pick A..B
ycherry-pick --stdin
), también lo hizogit revert
; éstos no son compatibles con larebase [-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