Desde el tiempo que git cherry-pick
aprendí para poder aplicar múltiples confirmaciones, la distinción se volvió algo discutible, pero esto es algo que se puede llamar evolución convergente ;-)
La verdadera distinción radica en la intención original de crear ambas herramientas:
git rebase
La tarea es reenviar una serie de cambios que un desarrollador tiene en su repositorio privado, creado contra la versión X de alguna rama ascendente, a la versión Y de esa misma rama (Y> X). Esto cambia efectivamente la base de esa serie de confirmaciones, por lo tanto, "rebase".
(También permite al desarrollador trasplantar una serie de confirmaciones a cualquier confirmación arbitraria, pero esto tiene un uso menos obvio).
git cherry-pick
es para llevar un compromiso interesante de una línea de desarrollo a otra. Un ejemplo clásico es el backporting de una corrección de seguridad realizada en una rama de desarrollo inestable a una rama estable (mantenimiento), donde merge
no tiene sentido, ya que traería muchos cambios no deseados.
Desde su primera aparición, git cherry-pick
ha podido elegir varias confirmaciones a la vez, una por una.
Por lo tanto, posiblemente la diferencia más llamativa entre estos dos comandos es cómo tratan la rama en la que trabajan: git cherry-pick
generalmente trae una confirmación de otro lugar y la aplica en la parte superior de su rama actual, registrando una nueva confirmación, mientras git rebase
toma su rama actual y reescribe una serie de su propia sugerencia se compromete de una forma u otra. Sí, esta es una descripción muy simplificada de lo que se git rebase
puede hacer, pero es intencional, para tratar de asimilar la idea general.
Actualice para explicar mejor un ejemplo de uso que se git rebase
está discutiendo.
Ante esta situación,
The Book afirma:
Sin embargo, hay otra forma: puede tomar el parche del cambio que se introdujo en C3 y volver a aplicarlo sobre C4. En Git, esto se llama rebase. Con el comando rebase, puede tomar todos los cambios que se confirmaron en una rama y aplicarlos en otra.
En este ejemplo, ejecutaría lo siguiente:
$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command
El "problema" aquí es que, en este ejemplo, la rama "experimento" (el tema de la reorganización) se bifurcó originalmente de la rama "maestra" y, por lo tanto, comparte las confirmaciones C0 a C2 con ella; de hecho, "experimento" es " master "hasta, e incluido, C2 más el compromiso C3 encima. (Este es el caso más simple posible; por supuesto, "experimento" podría contener varias docenas de confirmaciones además de su base original).
Ahora git rebase
se le dice que vuelva a basar "experimento" en la punta actual de "maestro", y git rebase
dice así:
- Se ejecuta
git merge-base
para ver cuál es la última confirmación compartida por el "experimento" y el "maestro" (en otras palabras, cuál es el punto de desviación). Este es C2.
- Guarda todas las confirmaciones realizadas desde el punto de desvío; en nuestro ejemplo de juguete, es solo C3.
- Rebobina HEAD (que apunta a la confirmación de punta de "experimento" antes de que la operación comience a ejecutarse) para apuntar a la punta de "maestro"; estamos reajustando sobre ella.
- Intenta aplicar cada una de las confirmaciones guardadas (como si fuera con
git apply
) en orden. En nuestro ejemplo de juguete es solo una confirmación, C3. Digamos que su aplicación producirá un commit C3 '.
- Si todo salió bien, la referencia del "experimento" se actualiza para señalar la confirmación resultante de aplicar la última confirmación guardada (C3 'en nuestro caso).
Ahora volvamos a tu pregunta. Como puede ver, aquí técnicamente de git rebase
hecho trasplanta una serie de confirmaciones de "experimento" a la punta de "maestro", por lo que puede decir con razón que hay "otra rama" en el proceso. Pero la esencia es que la confirmación de sugerencias de "experimento" terminó siendo la nueva confirmación de sugerencias en "experimento", simplemente cambió su base:
Una vez más, técnicamente se puede decir que git rebase
aquí se incorporaron ciertas confirmaciones del "maestro", y esto es absolutamente correcto.
Con cherry-pick, las confirmaciones / ramas originales se mantienen y se crean nuevas confirmaciones. Con rebase, toda la rama se mueve con la rama apuntando a las confirmaciones reproducidas.
Digamos que comenzó con:
Rebase:
Usted obtiene:
Selección de cereza:
Usted obtiene:
para obtener más información sobre git, este libro tiene la mayor parte (http://git-scm.com/book)
fuente
topic
basara en la parte superiormaster
, no contiene las confirmaciones omitidas, entonces, ¿de qué rama serán parte?git checkout topic
y luego degit reset --hard C'
la recolección de cerezas, entonces tiene el mismo resultado que después de rebase. Me salvé de muchos conflictos de fusión utilizando la selección selectiva sobre el rebase, porque el antepasado común estaba muy atrás.git
-guru pero estorebase
/cherry-pick
IS en la de todos los detalles congit
que tenía una comprensión del problema.git checkout -b
, que no tiene nada que ver congit cherry-pick
. Una mejor manera de explicar lo que está tratando de decir sería “corregit rebase
en latopic
rama y la pasamaster
; corresgit cherry-pick
en lamaster
rama y la pasas (se confirma desde)topic
".La selección selectiva funciona para confirmaciones individuales .
Cuando realizas un cambio de base, se aplican todas las confirmaciones del historial al HEAD de la rama que faltan allí.
fuente
git cherry-pick foo~3..foo
y obtener las confirmaciones superiores del árbol de "foo" elegidas una por una.git am
en él. Mientras que una selección selectiva aplica confirmación por confirmación (posiblemente creando un buzón de un solo mensaje para cada parche). Mi rebase estaba fallando porque el archivo de buzón que estaba creando se quedó sin espacio en la unidad, pero la selección con el mismo rango de revisión tuvo éxito (y parece ejecutarse más rápido).Una respuesta corta:
Las respuestas dadas anteriormente son buenas, solo quería dar un ejemplo en un intento de demostrar su interrelación.
No se recomienda reemplazar "git rebase" con esta secuencia de acciones, es solo "una prueba de concepto" que, espero, ayude a comprender cómo funcionan las cosas.
Dado el siguiente repositorio de juguetes:
Digamos, tenemos algunos cambios muy importantes (confirmaciones # 2 a # 5) en master que queremos incluir en nuestro test_branch_1. Por lo general, simplemente cambiamos a una rama y hacemos "git rebase master". Pero como pretendemos que solo estamos equipados con "git cherry-pick", lo hacemos:
Después de todas estas operaciones, nuestro gráfico de confirmación se verá así:
Como podemos ver, las confirmaciones # 6 y # 7 se aplicaron contra 7254931 (una confirmación de sugerencia del maestro). HEAD se movió y señala una confirmación que es, esencialmente, la punta de una rama rebasada. Ahora todo lo que tenemos que hacer es eliminar un puntero de rama antiguo y crear uno nuevo:
test_branch_1 ahora está enraizado desde la última posición maestra. ¡Hecho!
fuente
cherry-pick
es capaz de aplicar una variedad de confirmaciones, creo que sí. Aunque esta es una forma un poco extraña de hacer las cosas, nada le impide seleccionar todas las confirmaciones en su rama de características además demaster
, luego elimine la rama de características y vuelva a crearla de manera que apunte a la punta demaster
. Se puede pensar engit rebase
como una secuencia degit cherry-pick feature_branch
,git branch -d feature_branch
ygit branch feature_branch master
.Ambos son comandos para reescribir las confirmaciones de una rama encima de otra: la diferencia está en qué rama - "la tuya" (la actualmente verificada
HEAD
) o "suya" (la rama pasada como argumento al comando) - es la base de esta reescritura.git rebase
toma una confirmación inicial y reproduce tus confirmaciones como si fueran después de las suyas (la confirmación inicial).git cherry-pick
toma un conjunto de confirmaciones y reproduce sus confirmaciones como si fueran posteriores a las tuyas (tuHEAD
).En otras palabras, los dos comandos son, en su comportamiento núcleo (ignorando sus características de rendimiento divergentes, convenciones de llamada y opciones de mejora), simétrica : retirar la rama
bar
y en funcionamientogit rebase foo
conjuntos de labar
rama a la misma historia como el registro de salida ramafoo
y funcionandogit cherry-pick ..bar
fijaríafoo
a (los cambios defoo
, seguidos de los cambios debar
).En cuanto al nombre, la diferencia entre los dos comandos se puede recordar en que cada uno describe lo que hace con la rama actual :
rebase
hace que el otro encabece la nueva base para sus cambios, mientras quecherry-pick
selecciona los cambios de la otra rama y los coloca encima de tuHEAD
(como cerezas encima de un helado).fuente
Ambos hacen cosas muy similares; la principal diferencia conceptual es (en términos simplificados) que:
rebase mueve confirmaciones de la rama actual a otra rama .
Cherry-pick copia confirmaciones de otra rama a la rama actual .
Usando diagramas similares a la respuesta de @Kenny Ho :
Dado este estado inicial:
... y suponiendo que desea que las confirmaciones de la
topic
rama se reproduzcan en la parte superior de lamaster
rama actual , tiene dos opciones:Usando rebase: primero iría a
topic
haciendogit checkout topic
y luego movería la rama ejecutandogit rebase master
, produciendo:Resultado: su rama actual
topic
fue reorganizada (movida) amaster
.La
topic
sucursal se actualizó, mientras que lamaster
sucursal permaneció en su lugar.Usando cherry-pick : primero iría a
master
haciendogit checkout master
y luego copiaría la rama ejecutandogit cherry-pick topic~3..topic
(o, de manera equivalente,git cherry-pick B..G
), produciendo:Resultado: las confirmaciones de
topic
se copiaron enmaster
.La
master
sucursal se actualizó, mientras que latopic
sucursal permaneció en su lugar.Por supuesto, aquí tenía que decirle explícitamente a cherry-pick que eligiera una secuencia de confirmaciones , usando la notación de rango
foo..bar
. Si simplemente hubiera pasado el nombre de la rama, como engit cherry-pick topic
, habría recogido solo la confirmación en la punta de la rama, dando como resultado:fuente