tutorial español comandos git git-merge git-cherry-pick

git - español - ¿Cómo elegir una serie de compromisos y fusionarlos en otra rama?



git push (7)

¿Estás seguro de que no quieres fusionar las ramas? Si la rama de trabajo tiene algunas confirmaciones recientes que no desea, puede crear una nueva rama con una CABEZA en el punto que desee.

Ahora, si realmente desea elegir una serie de compromisos, por cualquier razón, una forma elegante de hacerlo es simplemente tirar de un conjunto de parches y aplicarlo a su nueva rama de integración:

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

Esto es esencialmente lo que está haciendo git-rebase de todos modos, pero sin la necesidad de jugar juegos. Puede agregar --3way a git-am si necesita fusionar. Asegúrese de que no haya otros archivos * .patch en el directorio donde hace esto, si sigue las instrucciones literalmente ...

Tengo el siguiente diseño de repositorio:

  • rama maestra (producción)
  • integración
  • trabajando

Lo que quiero lograr es elegir una serie de confirmaciones de la rama de trabajo y fusionarla en la rama de integración. Soy bastante nuevo en git y no puedo encontrar la manera exacta de hacer esto (la selección exacta de los rangos de confirmación en una operación, no la fusión) sin desordenar el repositorio. ¿Alguna sugerencia o pensamiento sobre esto? ¡Gracias!


A partir de git v1.7.2, cherry pick puede aceptar un rango de confirmaciones:

git cherry-pick aprendió a elegir un rango de confirmaciones (por ejemplo, cherry-pick A..B y cherry-pick --stdin ), así también git revert ; Sin embargo, estos no admiten el mejor control de secuenciación que ha rebase [-i] .


Cuando se trata de una gama de compromisos, la selección de cereza es no era practico

Como mencionó Keith Kim a continuación , Git 1.7.2+ introdujo la capacidad de seleccionar una serie de confirmaciones (pero aún debe ser consciente de las consecuencias de la selección de cerebros para una combinación futura )

git cherry-pick "aprendió a elegir una serie de compromisos
(por ejemplo, " cherry-pick A..B " y " cherry-pick --stdin "), también lo hizo " git revert "; Sin embargo, estos no admiten el mejor control de secuenciación que tiene " rebase [-i] ".

damian comments y nos advierte:

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

Si desea seleccionar el rango de B a D (inclusive) , sería B^..D
Consulte " Git crear rama del rango de confirmaciones anteriores? " Como ilustración.

Como Jubobs menciona en los comentarios :

Esto supone que B no es una confirmación de raíz; obtendrá un error de " unknown revision " de lo contrario.

Nota: a partir de Git 2.9.x / 2.10 (Q3 2016), puede seleccionar un rango de confirmación directamente en una rama huérfana (cabeza vacía): consulte " Cómo hacer que una rama existente sea huérfana en git ".

Respuesta original (enero 2010)

Una rebase --onto sería mejor, donde rebase --onto el rango dado de confirmación en la parte superior de su rama de integración, como Charles Bailey describió aquí .
(También, busque "Aquí está cómo trasplantar una rama temática de una rama a otra" en la página de manual de git rebase , para ver un ejemplo práctico de git rebase --onto )

Si su rama actual es 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

Eso lo volverá a reproducir todo entre:

  • después del padre de first_SHA-1_of_working_branch_range (de ahí el ~1 ): la primera confirmación que desea reproducir
  • hasta la " integration " (que apunta a la última confirmación que desea reproducir, desde la rama de working )

a " tmp " (que apunta a donde apuntaba la integration anteriormente)

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

  • git rebase --continue y ejecuta " git rebase --continue ".
  • o salta este parche, y ejecuta " git rebase --skip "
  • o cancele todo con un " git rebase --abort " (y vuelva a colocar la rama de integration en la rama tmp )

Después de esa rebase --onto , la integration volverá a la última confirmación de la rama de integración (es decir, la rama " tmp " + todas las confirmaciones repetidas)

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

Una solución pura de " cherry-pick " se discute aquí , e involucraría algo como:

Si desea utilizar un enfoque de parche, "git format-patch | git am" y "git cherry" son sus opciones.
Actualmente, git cherry-pick solo acepta un solo compromiso, pero si desea seleccionar el rango B a D sería B^..D en git lingo, entonces

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

Pero de todos modos, cuando necesite "repetir" un rango de confirmaciones, la palabra "repetición" debería empujarlo a usar la función " rebase " de Git.


Otra opción podría ser fusionarse con la estrategia nuestra para el compromiso antes del rango y luego una combinación ''normal'' con el último compromiso de ese rango (o rama cuando sea el último). Así que supongamos que solo 2345 y 3456 confirmaciones del maestro se fusionen en la rama de características:

master: 1234 2345 3456 4567

en la rama característica:

git merge -s ours 4567 git merge 2345


Supongamos que tienes 2 ramas,

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

"branchB": la sucursal a la que desea que se transfieran las confirmaciones desde "branchA"

1)

git checkout <branchA>

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

3)

git checkout <branchB>

4)

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

5) En caso de que tenga un conflicto, resuélvalo y escriba

git cherry-pick --continue

para continuar con el proceso de selección de cerezas.


Todas las opciones anteriores le pedirán que resuelva los conflictos de combinación. Si está fusionando los cambios confirmados para un equipo, es difícil resolver los conflictos de combinación de los desarrolladores y continuar. Sin embargo, "git merge" hará la fusión en un solo disparo, pero no puede pasar un rango de revisiones como argumento. tenemos que usar los comandos "git diff" y "git apply" para hacer el rango de combinación de revoluciones. He observado que "git apply" fallará si el archivo de parche tiene diff para demasiados archivos, así que tenemos que crear un parche por archivo y luego aplicar. Tenga en cuenta que la secuencia de comandos no podrá eliminar los archivos que se eliminan en la rama de origen. Este es un caso raro, puede eliminar manualmente dichos archivos de la rama de destino. El estado de salida de "git apply" no es cero si no puede aplicar el parche, sin embargo, si usa la opción -3way, volverá a la combinación de 3 vías y no tendrá que preocuparse por este fallo.

A continuación se muestra el guión.

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"


Envolví el código de VonC en un breve script de bash, 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 mientras reconstruyo el historial de un proyecto que tenía tanto el código de terceros como las personalizaciones combinadas en el mismo tronco svn. Ahora estoy dividiendo el código principal de terceros, los módulos de terceros y las personalizaciones en sus propias sucursales de 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 antepasado compartido.