¿Cómo copiar confirmaciones de una rama a otra?

728

Tengo dos ramas de mi maestro:

  • v2.1 : (versión 2) He estado trabajando durante varios meses.
  • wss : que creé ayer para agregar una característica específica a mi maestro (en producción)

¿Hay alguna manera de copiar los commits de ayer de wss a v2.1?

Bob Walsh
fuente
Para copiar simplemente los commits (o un rango de commits) de una rama a otra, esta respuesta me ayudó mejor: stackoverflow.com/questions/1994463/…
caramba
Compromisos

Respuestas:

566

Realmente debería tener un flujo de trabajo que le permita hacer todo esto fusionando:

- x - x - x (v2) - x - x - x (v2.1)
           \
            x - x - x (wss)

Entonces todo lo que tienes que hacer es git checkout v2.1y git merge wss. Si por alguna razón realmente no puede hacer esto, y no puede usar git rebase para mover su rama wss al lugar correcto, el comando para tomar un solo commit desde algún lugar y aplicarlo en otro lugar es git cherry-pick . Simplemente revise la rama en la que desea aplicarlo y ejecútelo git cherry-pick <SHA of commit to cherry-pick>.

Algunas de las formas en que rebase pueden salvarte:

Si su historial se ve así:

- x - x - x (v2) - x - x - x (v2.1)
           \
            x - x - x (v2-only) - x - x - x (wss)

Puede usar git rebase --onto v2 v2-only wsspara mover wss directamente a v2:

- x - x - x (v2) - x - x - x (v2.1)
          |\
          |  x - x - x (v2-only)
           \
             x - x - x (wss)

¡Entonces puedes unirte! Si realmente, realmente, realmente no puede llegar al punto en el que pueda fusionarse, aún puede usar rebase para hacer efectivamente varias selecciones de cereza a la vez:

# wss-starting-point is the SHA1/branch immediately before the first commit to rebase
git branch wss-to-rebase wss
git rebase --onto v2.1 wss-starting-point wss-to-rebase
git checkout v2.1
git merge wss-to-rebase

Nota: la razón por la que se necesita un poco de trabajo adicional para hacer esto es porque está creando confirmaciones duplicadas en su repositorio. Esto no es realmente algo bueno: el objetivo de una fácil ramificación y fusión es poder hacer todo haciendo commit (s) en un lugar y fusionándolos en donde sea necesario. Las confirmaciones duplicadas significan una intención de nunca fusionar esas dos ramas (si decides que quieres hacerlo más adelante, obtendrás conflictos).

Cascabel
fuente
1
No podría estar más de acuerdo con esta respuesta. +1. Vea también mi respuesta anterior para ilustrar las consecuencias de la selección de cerezas: stackoverflow.com/questions/881092/…
VonC
18
Excelente respuesta sobre cómo hacer esto de la manera adecuada . Desearía poder votar dos veces por el esfuerzo de crear diagramas ASCII también.
Gotgenes
@VonC: Gracias por el apoyo y la información adicional sobre por qué no elegir, sé que me escabullí un poco allí. @gotgenes: ¡Gracias! Creo que vale la pena el esfuerzo, solo mira la página de manual de git-rebase. No hay mejor manera de explicarlo.
Cascabel
En cuanto a por qué es posible que no pueda fusionarse: la fusión de Git no funciona bien con git-svn. Para copiar una serie de confirmaciones de una rama SVN a otra, terminé seleccionándolas y luego realizando una nueva versión / rebase interactiva para eliminar las git-svn-idreferencias incorrectas antes dcommitde volver a comenzar . Aunque probablemente podría haber omitido el paso de selección de cereza y simplemente haber usado un rebase por sí mismo.
Bob
1
Aquí está mi caso de uso: las correcciones de errores críticos se comprometieron con la rama de características. Lo necesito en master para entrar en producción ahora. Esto salvará mi trasero.
Capitán Hipertexto
910

Utilizar

git cherry-pick <commit>

para aplicar <commit>a su sucursal actual .

Yo mismo probablemente haría una verificación cruzada de los commits que selecciono gitky los selecciono con un clic derecho en la entrada de commit allí.


Si desea ir más automático (con todos sus peligros) y asumir todos los commits desde que sucedió ayer en wss, puede generar la lista de commits usando git log(con la --prettysugerencia de Jefromi)

git log --reverse --since=yesterday --pretty=%H

así que todo junto asumiendo que usas bash

for commit in $(git log --reverse --since=yesterday --pretty=%H);
do
    git cherry-pick $commit
done

Si algo sale mal aquí (hay un gran potencial) estás en problemas ya que esto funciona en el pago en vivo, así que haz selecciones manuales o usa rebase como lo sugiere Jefromi.

Benjamin Bannier
fuente
Todos los marcadores de posición para la opción --pretty están en la página de manual de git-log. Puede obtener el formato que desee, especialmente útil para obtener los campos que desea para un script en una forma fácilmente analizable.
Cascabel
También me gustaría señalar que, suponiendo que realmente desee crear confirmaciones duplicadas, el método que se utiliza git rebaseen mi respuesta es más robusto. En particular, usando un bucle for como este, si una de las selecciones de cereza falla, aún intentará hacer el resto. Esto es ... muy muy malo, digamos.
Cascabel
2
Convenido. Es por eso que nunca lo uso, sino que lo hago manualmente. Pero cherry-pick sigue siendo la respuesta, al menos al título de la pregunta. Modifiqué la respuesta.
Benjamin Bannier
1
Alguien se comprometió con una rama antigua / incorrecta, y cherry-pick me permitió poner esa confirmación en la rama correcta (sin dejar de mantenerla como el confirmador). Perfecto.
Patrick
8
Una vista rara, una gitrespuesta que es simple y directa a la solución, en lugar de serpentear a través de las complejidades de git para demostrar cuán bien lo sabe el respondedor.
Przemek D
74

git cherry-pick : Aplique los cambios introducidos por algunos commits existentes

Supongamos que tenemos una rama A con confirmaciones (X, Y, Z). Tenemos que añadir estos compromete a la rama B . Vamos a usar las cherry-pickoperaciones.

Cuando usamos cherry-pick, hay que añadir compromete en la rama B en el mismo orden cronológico que las confirmaciones aparecen en la rama Una .

cherry-pick admite una variedad de commits, pero si tiene commits de fusión en ese rango, se vuelve realmente complicado

git checkout B
git cherry-pick SHA-COMMIT-X
git cherry-pick SHA-COMMIT-Y
git cherry-pick SHA-COMMIT-Z

Ejemplo de flujo de trabajo:

ingrese la descripción de la imagen aquí

Podemos usar cherry-pickcon opciones

-e o --edit : con esta opción, git cherry-pick le permitirá editar el mensaje de confirmación antes de confirmar.

-n o --no-commit : por lo general, el comando crea automáticamente una secuencia de confirmaciones. Este indicador aplica los cambios necesarios para seleccionar cada confirmación nombrada en su árbol de trabajo y el índice, sin realizar ninguna confirmación. Además, cuando se utiliza esta opción, su índice no tiene que coincidir con la confirmación HEAD. La selección de cereza se realiza contra el estado inicial de su índice.

Aquí un artículo interesante sobre cherry-pick.

LYES - CHIOUKH
fuente
19

Puede crear un parche a partir de las confirmaciones que desea copiar y aplicar el parche a la rama de destino.

Charles Ma
fuente
16
Incluso si, por alguna razón, realmente desea utilizar parches en lugar de cherry-pick (s) / rebase, la forma más sencilla de hacerlo es con git format-patch <revision range>y git am *.patch.
Cascabel
Requiere checkouta otra rama.
CoolMind
12

O si eres un poco menos del lado del evangelista, puedes hacer una forma fea que estoy usando. En deploy_template hay confirmaciones que quiero copiar en mi maestro como implementación de sucursal

git branch deploy deploy_template
git checkout deploy
git rebase master

Esto creará una nueva implementación de sucursal (uso -f para sobrescribir la rama de implementación existente) en deploy_template, luego volverá a crear esta nueva rama en la maestra, dejando intacta deploy_template.

Petr Sykora
fuente
1

Para el caso simple de copiar el último commit de la rama wss a v2.1, simplemente puede tomar el commit id ( git log --oneline | head -n 1) y hacer:

git checkout v2.1
git merge <commit>
zeroimpl
fuente
Esto requiere verificar en otra sucursal.
CoolMind
1

El comando cherry-pick puede leer la lista de confirmaciones de la entrada estándar.

El siguiente comando cherry-picks se compromete escrito por el usuario John que existe en la rama "desarrollo" pero no en la rama "lanzamiento", y lo hace en orden cronológico.

git log develop --not release --format=%H --reverse --author John | git cherry-pick --stdin
Gebb
fuente