Pregunta ¿Cuándo usas git rebase en lugar de git merge?


Cuándo se recomienda usar git rebase vs. git merge?

¿Todavía necesito fusionarme después de una rebase exitosa?


1246
2018-04-29 20:26


origen


Respuestas:


Version corta

  • Merge toma todos los cambios en una rama y los fusiona en otra rama en una confirmación.
  • Rebase dice que quiero que el punto en el que me bifurqué para pasar a un nuevo punto de partida

Entonces, ¿cuándo usas cualquiera de los dos?

Unir

  • Digamos que ha creado una rama con el propósito de desarrollar una característica única. Cuando quieras llevar esos cambios a la maestría, probablemente quieras unir (no te importa mantener todas las confirmaciones provisionales).

Rebase

  • Un segundo escenario sería si comenzó a hacer algún desarrollo y luego otro desarrollador hizo un cambio no relacionado. Probablemente quieras tirar y luego rebase para basar sus cambios de la versión actual del repositorio.

973
2018-04-29 20:38



Es simple, con rebase dices usar otra rama como la nueva base para tu trabajo.

Si tiene, por ejemplo, una sucursal master y creas una rama para implementar una nueva función, digamos que lo nombras cool-feature, por supuesto, la rama principal es la base de su nueva función.

Ahora, en cierto punto, desea agregar la nueva característica que implementó en el master rama. Podrías cambiar a master y fusionar el cool-feature rama:

$git checkout master
$git merge cool-feature

pero de esta manera se agrega una nueva confirmación ficticia, si desea evitar la historia de spaghetti, puede rebase:

$git checkout cool-feature
$git rebase master

y luego fusionarlo en master:

$git checkout master
$git merge cool-feature

Esta vez, dado que la rama temática tiene los mismos commits de master más los commits con la nueva característica, la fusión será solo un avance rápido.


288
2018-02-05 06:28



Para complementar mi propia respuesta mencionado por TSamper,

  • una rebase es una buena idea para hacer antes de una fusión, porque la idea es que se integre en su rama Y el trabajo de la rama B sobre el cual te fusionarás.
    Pero, nuevamente, antes de fusionarse, resuelve cualquier conflicto en tu rama (es decir, "rebase", como en "reproducir mi trabajo en mi rama a partir de un punto reciente de la rama" B)
    Si se hace correctamente, la fusión posterior de su sucursal a sucursal B puede ser rápido.

  • una fusión afecta directamente a la sucursal de destino B, lo que significa que las fusiones serán triviales, de lo contrario esa rama B puede ser largo para volver a un estado estable (tiempo para resolver todos los conflictos)


el punto de fusionarse después de una rebase?

En el caso que describo, rebase B en mi sucursal, solo para tener la oportunidad de reproducir mi trabajo desde un punto más reciente de B, pero mientras permaneces en mi rama.
En este caso, todavía se necesita una fusión para llevar a cabo mi trabajo "reproducido" B.

El otro escenario (descrito en Git Ready por ejemplo), es traer su trabajo directamente en B a través de una rebase (que conserva todos tus buenos commits, o incluso te da la oportunidad de volver a ordenarlos a través de una rebase interactiva).
En ese caso (donde rebase mientras está en la rama B), tiene razón: no se necesita fusionar más:

Un árbol git por defecto cuando no nos hemos fusionado ni re-basado

rebase1 

obtenemos por rebase:

rebase3

Ese segundo escenario se trata de: cómo recuperar la función nueva en el maestro.

Lo que quiero decir, al describir el primer escenario de rebase, es recordarles a todos que una rebase también se puede usar como un paso preliminar para eso (que es "obtener una nueva función en el maestro").
Puede usar rebase para llevar primero al maestro "en" la nueva rama de características: la rebase reproducirá confirmaciones de funciones nuevas de la HEAD master, pero aún en la rama de nueva característica, moviendo efectivamente el punto de inicio de su sucursal desde un antiguo compromiso maestro a HEAD-master.
Eso le permite resolver cualquier conflicto en tu branch (es decir, de forma aislada, mientras permite que el maestro continúe evolucionando en paralelo si su etapa de resolución de conflictos lleva demasiado tiempo).
Luego puedes cambiar a maestro y fusionar new-feature (o rebase) new-feature sobre master si desea conservar las confirmaciones hechas en su new-feature rama).

Asi que:

  • "rebase vs. merge" se puede ver como dos formas de importar un trabajo, por ejemplo, master.
  • Pero "rebase luego fusionar" puede ser un flujo de trabajo válido para resolver el conflicto por primera vez de forma aislada, y luego recuperar su trabajo.

253
2018-04-29 20:44



Aquí muchas respuestas dicen que fusionar convierte todos tus commits en uno, y por lo tanto sugiere usar rebase para preservar tus commits. Esto es incorrecto. Y una mala idea si ya has empujado tus commits.

Merge hace no borra tus compromisos. ¡Merge preserva la historia! (solo mira gitk) Rebase reescribe la historia, que es una cosa mala después de que has empujado eso.

Usar fusión - no rebase cuando ya has empujado.

Aquí está Linus '(autor de git) asumirlo. Es una muy buena lectura. O puede leer mi propia versión de la misma idea a continuación.

Rebasando una rama en el maestro:

  • proporciona una idea incorrecta de cómo se crearon los commits
  • contamina maestro con un montón de compromisos intermedios que pueden no haber sido bien probados
  • en realidad podría introducir rupturas de compilación en estas confirmaciones intermedias debido a los cambios que se realizaron al maestro entre el momento en que se creó la rama de tema original y el momento en que se reescribió.
  • hace difícil encontrar buenos lugares en el maestro para pagar.
  • Hace que las marcas de tiempo en confirmaciones no se alineen con su orden cronológico en el árbol. Entonces vería que el commit A precede al commit B en el master, pero el commit B fue el primero en escribir. (¡¿Qué?!)
  • Produce más conflictos porque los compromisos individuales en la rama temática pueden implicar conflictos de fusión que se deben resolver individualmente (Más información sobre lo que sucedió en cada compromiso).
  • es una reescritura de la historia. Si la rama que se está reubicando se ha desplazado a cualquier parte (compartida con cualquier persona que no sea usted), habrá arruinado a todos los que posean esa rama, ya que ha reescrito el historial.

En contraste, fusionando una rama de tema en maestro:

  • conserva el historial de dónde se crearon las ramas de tema, incluidas las fusiones desde el maestro a la rama de tema para ayudar a mantenerlo actualizado. Realmente tiene una idea precisa de con qué código estaba trabajando el desarrollador cuando estaban construyendo.
  • master es una rama compuesta principalmente de fusiones, y cada una de esas confusiones de fusión suelen ser "buenos puntos" en la historia que es seguro revisar porque allí es donde la rama temática estaba lista para integrarse.
  • se conservan todas las confirmaciones individuales de la rama de tema, incluido el hecho de que se encontraban en una rama de tema, por lo que aislar esos cambios es natural y puede explorar donde sea necesario.
  • los conflictos de fusión solo tienen que resolverse una vez (en el punto de fusión), por lo que los cambios de compromiso intermedios realizados en la rama de tema no tienen que resolverse de forma independiente.
  • se puede hacer varias veces sin problemas. Si integra su rama de temas para dominar periódicamente, la gente puede seguir trabajando en la rama de temas y puede seguir fusionándose de forma independiente.

151
2018-02-03 22:17



TL; DR

Si tiene alguna duda, use merge.

Respuesta corta

Las únicas diferencias entre una rebase y una fusión son:

  • La estructura de árbol resultante del historial (generalmente solo perceptible cuando se mira un gráfico de compromiso) es diferente (una tendrá ramas, la otra no).
  • Merge generalmente creará una confirmación adicional (por ejemplo, nodo en el árbol).
  • Merge y rebase manejarán los conflictos de manera diferente. Rebase presentará conflictos de un compromiso a la vez donde la fusión los presentará todos a la vez.

Entonces la respuesta corta es elige rebase o fusiona en función de cómo quieres que se vea tu historial.

Respuesta larga

Hay algunos factores que debe considerar al elegir qué operación usar.

¿La rama que está recibiendo cambios se comparte con otros desarrolladores externos a su equipo (por ejemplo, de código abierto, público)?

Si es así, no rebase. Rebase destruye la rama y esos desarrolladores tendrán repositorios rotos / inconsistentes a menos que usen git pull --rebase. Esta es una buena manera de molestar a otros desarrolladores rápidamente.

¿Cuán hábil es tu equipo de desarrollo?

Rebase es una operación destructiva. Eso significa que, si no lo aplica correctamente, podrías perder el trabajo comprometido y / o romper la consistencia de los repositorios de otros desarrolladores.

Trabajé en equipos en los que todos los desarrolladores venían de un momento en el que las empresas podían permitirse contratar personal dedicado para ocuparse de la bifurcación y la fusión. Esos desarrolladores no saben mucho sobre Git y no quieren saber mucho. En estos equipos no me arriesgaría a recomendar el rebasamiento por ningún motivo.

¿La rama en sí misma representa información útil?

Algunos equipos usan el modelo de rama por función en el que cada rama representa una función (o corrección de errores, o subcaracterística, etc.). En este modelo, la rama ayuda a identificar conjuntos de compromisos relacionados. Por ejemplo, uno puede revertir rápidamente una característica invirtiendo la fusión de esa rama (para ser justos, esta es una operación rara). O bien, difunde una característica comparando dos ramas (más común). Rebase destruiría la rama y esto no sería sencillo.

También trabajé en equipos que usaban el modelo de rama por desarrollador (todos estuvimos allí). En este caso, la rama en sí misma no transmite información adicional (la confirmación ya tiene el autor). No habría daño en rebasar.

¿Podría querer revertir la fusión por algún motivo?

Revertir (como deshacer) una rebase es considerablemente difícil y / o imposible (si la rebase tenía conflictos) en comparación con revertir una combinación. Si crees que hay una posibilidad de que quieras revertir, utiliza la fusión.

¿Trabajas en un equipo? Si es así, ¿estás dispuesto a adoptar un enfoque de todo o nada en esta rama?

Las operaciones de Rebase deben ser tiradas con un correspondiente git pull --rebase. Si trabaja solo, puede recordar cuál debe usar en el momento apropiado. Si trabajas en un equipo, será muy difícil coordinarlo. Esta es la razón por la cual la mayoría de los flujos de trabajo de rebase recomiendan usar rebase para todas las fusiones (y git pull --rebase para todos los tirones).

Mitos comunes

Merge destruye la historia (se compromete squash)

Suponiendo que tiene la siguiente fusión:

    B -- C
   /      \
  A--------D

Algunas personas afirman que la combinación "destruye" el historial de confirmaciones porque si observaras el registro de solo la rama principal (A - D), perderías los mensajes de confirmación importantes contenidos en B y C.

Si esto fuera cierto, no tendríamos preguntas como esta. Básicamente, verá B y C a menos que explícitamente solicite no verlos (utilizando --primer padre). Esto es muy fácil de probar por ti mismo.

Rebase permite fusiones más seguras / simples

Los dos enfoques se fusionan de forma diferente, pero no está claro que uno siempre sea mejor que el otro y puede depender del flujo de trabajo del desarrollador. Por ejemplo, si un desarrollador tiende a comprometerse regularmente (por ejemplo, tal vez se comprometan dos veces al día mientras hacen la transición del trabajo al hogar), entonces podría haber muchas confirmaciones para una rama determinada. Muchas de esas confirmaciones pueden no parecerse en nada al producto final (tiendo a refactorizar mi enfoque una o dos veces por función). Si alguien más estuviera trabajando en un área de código relacionada y trataran de volver a establecer mis cambios, podría ser una operación bastante tediosa.

Rebase es más fresco / más sexy / más profesional

Si te gusta alias rm a rm -rf para "ahorrar tiempo", entonces tal vez rebase es para ti.

Mis dos centavos

Siempre pienso que algún día me encontraré con un escenario en el que git rebase es la herramienta increíble que resuelve el problema. Al igual que creo que me encontraré con un escenario donde git reflog es una herramienta increíble que resuelve mi problema. He trabajado con git durante más de cinco años. No ha sucedido

Las historias desordenadas nunca han sido realmente un problema para mí. No acabo de leer mi historia de compromiso como una novela emocionante. La mayoría de las veces necesito un historial Voy a usar git blame o git bisect de todos modos. En ese caso, tener el compromiso de fusión es realmente útil para mí, porque si la fusión introdujo el problema que es información significativa para mí.

Actualización (4/2017)

Me siento obligado a mencionar que personalmente he suavizado el uso de rebase aunque mi consejo general sigue en pie. Recientemente he estado interactuando mucho con el Material angular 2 proyecto. Han usado rebase para mantener un historial de compromiso muy limpio. Esto me ha permitido ver muy fácilmente qué compromiso solucionó un defecto determinado y si ese compromiso se incluyó o no en un lanzamiento. Sirve como un gran ejemplo de uso de rebase correctamente.


114
2018-04-13 02:16



Fusionar significa: crear un único compromiso nuevo que combine mis cambios en el destino.

Rebase significa: crear una nueva serie de commits, usando mi conjunto actual de commits como pistas. En otras palabras, calcule cómo se verían mis cambios si hubiera empezado a hacerlos desde el punto en el que me estoy refinando. Después de la rebase, por lo tanto, es posible que deba volver a probar los cambios y durante la rebase, posiblemente tenga algunos conflictos.

Dado esto, ¿por qué rebase? Solo para mantener el historial de desarrollo claro. Supongamos que está trabajando en la característica X y, cuando termine, fusiona sus cambios. El destino ahora tendrá una confirmación única que diga algo similar a "Característica añadida X". Ahora, en lugar de fusionarse, si se volvió a configurar y se fusionó, el historial de desarrollo de destino contendría todas las confirmaciones individuales en una única progresión lógica. Esto hace que revisar los cambios más adelante sea mucho más fácil. Imagine lo difícil que le resultaría revisar el historial de desarrollo si 50 desarrolladores estuvieran fusionando varias funciones todo el tiempo.

Dicho eso, si ya has empujado la rama que estás trabajando en la cadena ascendente, no deberías volver a establecer la base, sino fusionarla. Para las ramas que no han sido empujadas en sentido ascendente, rebase, pruebe y fusione.

En otro momento es posible que desee volver a establecer la base cuando desea deshacerse de las confirmaciones de su rama antes de empujar hacia arriba. Por ejemplo: comete errores que introducen algún código de depuración desde el principio y otros se comprometen más allá de limpiar ese código. La única forma de hacerlo es realizando una rebase interactiva: git rebase -i <branch/commit/tag>

ACTUALIZACIÓN: También desea utilizar rebase cuando usa Git para interactuar con un sistema de control de versiones que no admite el historial no lineal (subversión, por ejemplo). Al usar el puente git-svn, es muy importante que los cambios que vuelva a fusionar en subversión sean una lista secuencial de cambios además de los cambios más recientes en el enlace troncal. Solo hay dos formas de hacerlo: (1) Recrear manualmente los cambios y (2) Usar el comando rebase, que es mucho más rápido.

ACTUALIZACIÓN2: una forma adicional de pensar en una rebase es que habilita un tipo de mapeo desde su estilo de desarrollo al estilo aceptado en el repositorio al que se compromete. Digamos que te gusta cometer pequeños trozos. Usted tiene un compromiso para corregir un error tipográfico, uno se compromete a deshacerse del código no utilizado, y así sucesivamente. Cuando hayas terminado lo que tienes que hacer, tendrás una larga serie de compromisos. Ahora supongamos que el repositorio al que se compromete fomenta los compromisos grandes, por lo que para el trabajo que está realizando, uno esperaría uno o quizás dos compromisos. ¿Cómo llevas tu cadena de compromisos y los comprimes a lo que se espera? Utilizarías una base de datos interactiva y reduciría tus pequeños compromisos en trozos más grandes. Lo mismo es cierto si se necesita el reverso, si su estilo fue de algunos compromisos grandes, pero el repositorio exigió series largas de compromisos pequeños. También usarías una rebase para hacer eso. Si se fusionó, ahora ha injertado su estilo de confirmación en el repositorio principal. Si hay muchos desarrolladores, puede imaginar lo difícil que sería seguir un historial con varios estilos de confirmación diferentes después de un tiempo.

ACTUALIZACIÓN3: Does one still need to merge after a successful rebase? Si tu puedes. La razón es que una rebase implica esencialmente un "cambio" de commits. Como he dicho anteriormente, estos commits se calculan, pero si tienes 14 commits desde el punto de bifurcación, entonces suponiendo que nada va mal con tu rebase, estarás 14 commits adelante (del punto en el que estás rebase) después la rebase está lista. Tuviste una rama antes de una rebase. Tendrás una rama de la misma longitud después. Aún debe fusionarse antes de publicar sus cambios. En otras palabras, rebase todas las veces que quiera (de nuevo, solo si no ha presionado sus cambios en sentido ascendente). Fusionar solo después de volver a establecer la base.


65
2018-02-05 06:47



antes de fusionar / rebase:

A <- B <- C    [master]
^
 \
  D <- E       [branch]

después git merge master:

A <- B <- C
^         ^
 \         \
  D <- E <- F

después git rebase master:

A <- B <- C <- D' <- E'

(A, B, C, D, E y F son commits)

este ejemplo y mucha más información bien ilustrada sobre git se pueden encontrar aquí: http://excess.org/article/2008/07/ogre-git-tutorial/


54
2018-06-07 06:19



Esta oración lo consigue:

En general, la forma de obtener lo mejor de ambos mundos es volver a establecer la base local   cambios que ha realizado pero que aún no ha compartido antes de insertarlos   para limpiar su historia, pero nunca rebase nada que haya empujado   algun lado.

Fuente: http://www.git-scm.com/book/en/v2/Git-Branching-Rebasing#Rebase-vs.-Merge


25
2018-01-05 13:50



Si bien la fusión es definitivamente la forma más fácil y común de integrar cambios, no es la única: Rebase es un medio alternativo de integración.

Comprender fusionar un poco mejor

Cuando Git realiza una combinación, busca tres compromisos:

  • (1) Compromiso de ancestro común Si sigue el historial de dos ramas en un proyecto, siempre tienen al menos un compromiso en común: en este punto en el tiempo, ambas ramas tenían el mismo contenido y luego evolucionaron de manera diferente.
  • (2) + (3) Puntos finales de cada rama El objetivo de una integración es combinar los estados actuales de dos ramas. Por lo tanto, sus respectivas últimas revisiones son de especial interés. La combinación de estos tres compromisos dará como resultado la integración que buscamos.

Fast-Forward o Merge Commit

En casos muy simples, una de las dos ramas no tiene ningún compromiso nuevo desde que se produjo la bifurcación: su último compromiso sigue siendo el ancestro común.

enter image description here

En este caso, realizar la integración es completamente simple: Git solo puede agregar todas las confirmaciones de la otra rama sobre la confirmación del antepasado común. En Git, esta forma de integración más simple se denomina fusión de "avance rápido". Ambas ramas comparten la misma historia.

enter image description here

En muchos casos, sin embargo, ambas ramas avanzaron individualmente. enter image description here

Para hacer una integración, Git tendrá que crear una nueva confirmación que contenga las diferencias entre ellos: la fusión de compromiso.

enter image description here

Compromisos humanos y compromisos de fusión

Normalmente, un compromiso es cuidadosamente creado por un ser humano. Es una unidad significativa que solo incluye cambios relacionados y los anota con un comentario.

Un commit de fusión es un poco diferente: en lugar de ser creado por un desarrollador, Git lo crea automáticamente. Y en lugar de envolver un conjunto de cambios relacionados, su propósito es conectar dos ramas, como un nudo. Si desea comprender una operación de fusión más adelante, debe echar un vistazo al historial de ambas ramas y el gráfico de confirmación correspondiente.

Integrando con Rebase

Algunas personas prefieren ir sin tales compromisos automáticos de fusión. En cambio, quieren que la historia del proyecto se vea como si hubiera evolucionado en una sola línea recta. No hay indicaciones de que se haya dividido en varias ramas en algún momento.

enter image description here

Veamos paso a paso una operación de rebase. El escenario es el mismo que en los ejemplos anteriores: queremos integrar los cambios de la rama B en la rama A, pero ahora usando rebase.

enter image description here

Haremos esto en tres pasos

  1. git rebase branch-A // syncs the history with branch-A
  2. git checkout branch-A // change the current branch to branch-A
  3. git merge branch-B // merge/take the changes from branch-B to branch-A 

Primero, Git "deshace" todos los commits en la rama A que ocurrieron después de que las líneas comenzaron a ramificarse (después de que el antepasado común se haya comprometido). Sin embargo, por supuesto, no los descartará: en su lugar, puede pensar en esos compromisos como "guardados temporalmente".

enter image description here

A continuación, aplica las confirmaciones de la rama B que queremos integrar. En este punto, ambas ramas se ven exactamente iguales.

enter image description here

En el paso final, las nuevas confirmaciones en la rama A ahora se vuelven a aplicar, pero en una nueva posición, además de las confirmaciones integradas de la sucursal B (se basan nuevamente). El resultado parece que el desarrollo sucedió en línea recta. En lugar de una confirmación de fusión que contiene todos los cambios combinados, se conservó la estructura de confirmación original.

enter image description here

Finalmente obtienes una rama limpia rama-A sin compromisos no deseados y generados automáticamente.

Nota: Tomado de lo impresionante enviar por git-tower. los desventajas de rebase también es una buena lectura en la misma publicación.


23
2017-10-12 11:52



El libro de gitano como una muy buena explicación sobre página de rebase.

Básicamente, una fusión llevará 2 commits y los combinará.

Una rebase irá al ancestro común en el 2 y aplicará incrementalmente los cambios uno encima del otro. Esto hace una historia más 'limpia' y más lineal.

Pero cuando rebase, abandona las confirmaciones anteriores y crea otras nuevas. Por lo tanto, nunca debe volver a establecer una base de datos de un repositorio público. Las otras personas que trabajan en el repositorio te odiarán.

Por esa razón solo me fusiono casi exclusivamente. El 99% de las veces mis ramas no difieren mucho, por lo que si hay conflictos, solo se encuentran en uno o dos lugares.


15
2017-12-20 21:41



Esta respuesta está ampliamente orientada en torno a Git Flow. Las tablas se han generado con el agradable Generador de tablas ASCII, y los árboles de historia con este maravilloso comando (aliased como git lg)

git log --graph --abbrev-commit --decorate --date=format:'%Y-%m-%d %H:%M:%S' --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%ad%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n''          %C(white)%s%C(reset) %C(dim white)- %an%C(reset)'

Las tablas están en orden cronológico inverso para ser más consistentes con los árboles de historia. Ver también la diferencia entre git merge y git merge --no-ff primero (generalmente quiere usar git merge --no-ff ya que hace que su historia se vea más cercana a la realidad):

git merge

Comandos:

Time          Branch "develop"             Branch "features/foo"
------- ------------------------------ -------------------------------
15:04   git merge features/foo
15:03                                  git commit -m "Third commit"
15:02                                  git commit -m "Second commit"
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

Resultado:

* 142a74a - YYYY-MM-DD 15:03:00 (XX minutes ago) (HEAD -> develop, features/foo)
|           Third commit - Christophe
* 00d848c - YYYY-MM-DD 15:02:00 (XX minutes ago)
|           Second commit - Christophe
* 298e9c5 - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git merge --no-ff

Comandos:

Time           Branch "develop"              Branch "features/foo"
------- -------------------------------- -------------------------------
15:04   git merge --no-ff features/foo
15:03                                    git commit -m "Third commit"
15:02                                    git commit -m "Second commit"
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

Resultado:

*   1140d8c - YYYY-MM-DD 15:04:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/foo' - Christophe
| * 69f4a7a - YYYY-MM-DD 15:03:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * 2973183 - YYYY-MM-DD 15:02:00 (XX minutes ago)
|/            Second commit - Christophe
* c173472 - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git merge vs git rebase

Primer punto: siempre combine las características en el desarrollo, nunca rebase el desarrollo de características. Esto es una consecuencia del Regla de Oro de Rebasar:

La regla de oro de git rebase es nunca usarlo en públicoramas

En otras palabras:

Nunca rebase nada que hayas empujado a alguna parte.

Yo personalmente agregaría: a menos que sea una rama de características Y usted y su equipo estén al tanto de las consecuencias.

Entonces la pregunta de git merge vs git rebase se aplica casi solo a las ramas de características (en los siguientes ejemplos, --no-ff siempre se ha usado al fusionar). Tenga en cuenta que ya que no estoy seguro de que haya una mejor solución (existe un debate), Solo proporcionaré cómo se comportan ambos comandos. En mi caso, prefiero usar git rebase ya que produce un árbol de historia más agradable :)

Entre ramas de características

git merge

Comandos:

Time           Branch "develop"              Branch "features/foo"           Branch "features/bar"
------- -------------------------------- ------------------------------- --------------------------------
15:10   git merge --no-ff features/bar
15:09   git merge --no-ff features/foo
15:08                                                                    git commit -m "Sixth commit"
15:07                                                                    git merge --no-ff features/foo
15:06                                                                    git commit -m "Fifth commit"
15:05                                                                    git commit -m "Fourth commit"
15:04                                    git commit -m "Third commit"
15:03                                    git commit -m "Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

Resultado:

*   c0a3b89 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 37e933e - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| *   eb5e657 - YYYY-MM-DD 15:07:00 (XX minutes ago)
| |\            Merge branch 'features/foo' into features/bar - Christophe
| * | 2e4086f - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | |           Fifth commit - Christophe
| * | 31e3a60 - YYYY-MM-DD 15:05:00 (XX minutes ago)
| | |           Fourth commit - Christophe
* | |   98b439f - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \ \            Merge branch 'features/foo' - Christophe
| |/ /
|/| /
| |/
| * 6579c9c - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * 3f41d96 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/            Second commit - Christophe
* 14edc68 - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git rebase

Comandos:

Time           Branch "develop"              Branch "features/foo"           Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10   git merge --no-ff features/bar
15:09   git merge --no-ff features/foo
15:08                                                                    git commit -m "Sixth commit"
15:07                                                                    git rebase features/foo
15:06                                                                    git commit -m "Fifth commit"
15:05                                                                    git commit -m "Fourth commit"
15:04                                    git commit -m "Third commit"
15:03                                    git commit -m "Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

Resultado:

*   7a99663 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 708347a - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| * 949ae73 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| |           Fifth commit - Christophe
| * 108b4c7 - YYYY-MM-DD 15:05:00 (XX minutes ago)
| |           Fourth commit - Christophe
* |   189de99 - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \            Merge branch 'features/foo' - Christophe
| |/
| * 26835a0 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * a61dd08 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/            Second commit - Christophe
* ae6f5fc - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

De develop a una rama de características

git merge

Comandos:

Time           Branch “develop"              Branch "features/foo"           Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10   git merge --no-ff features/bar
15:09                                                                    git commit -m “Sixth commit"
15:08                                                                    git merge --no-ff development
15:07   git merge --no-ff features/foo
15:06                                                                    git commit -m “Fifth commit"
15:05                                                                    git commit -m “Fourth commit"
15:04                                    git commit -m “Third commit"
15:03                                    git commit -m “Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m “First commit"

Resultado:

*   9e6311a - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 3ce9128 - YYYY-MM-DD 15:09:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| *   d0cd244 - YYYY-MM-DD 15:08:00 (XX minutes ago)
| |\            Merge branch 'develop' into features/bar - Christophe
| |/
|/|
* |   5bd5f70 - YYYY-MM-DD 15:07:00 (XX minutes ago)
|\ \            Merge branch 'features/foo' - Christophe
| * | 4ef3853 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | |           Third commit - Christophe
| * | 3227253 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ /            Second commit - Christophe
| * b5543a2 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| |           Fifth commit - Christophe
| * 5e84b79 - YYYY-MM-DD 15:05:00 (XX minutes ago)
|/            Fourth commit - Christophe
* 2da6d8d - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git rebase

Comandos:

Time           Branch “develop"              Branch "features/foo"           Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10   git merge --no-ff features/bar
15:09                                                                    git commit -m “Sixth commit"
15:08                                                                    git rebase development
15:07   git merge --no-ff features/foo
15:06                                                                    git commit -m “Fifth commit"
15:05                                                                    git commit -m “Fourth commit"
15:04                                    git commit -m “Third commit"
15:03                                    git commit -m “Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m “First commit"

Resultado:

*   b0f6752 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 621ad5b - YYYY-MM-DD 15:09:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| * 9cb1a16 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| |           Fifth commit - Christophe
| * b8ddd19 - YYYY-MM-DD 15:05:00 (XX minutes ago)
|/            Fourth commit - Christophe
*   856433e - YYYY-MM-DD 15:07:00 (XX minutes ago)
|\            Merge branch 'features/foo' - Christophe
| * 694ac81 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * 5fd94d3 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/            Second commit - Christophe
* d01d589 - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

Notas laterales

git cherry-pick

Cuando solo necesitas una confirmación específica, git cherry-pick es una buena solución (el -x la opción agrega una línea que dice "(Cherry escogido de commit ...)"al cuerpo del mensaje de confirmación original, por lo que generalmente es una buena idea usarlo, git log <commit_sha1> para verlo):

Comandos:

Time           Branch “develop"              Branch "features/foo"                Branch "features/bar"           
------- -------------------------------- ------------------------------- -----------------------------------------
15:10   git merge --no-ff features/bar                                                                            
15:09   git merge --no-ff features/foo                                                                            
15:08                                                                    git commit -m “Sixth commit"             
15:07                                                                    git cherry-pick -x <second_commit_sha1>  
15:06                                                                    git commit -m “Fifth commit"             
15:05                                                                    git commit -m “Fourth commit"            
15:04                                    git commit -m “Third commit"                                             
15:03                                    git commit -m “Second commit"                                            
15:02   git checkout -b features/bar                                                                              
15:01   git checkout -b features/foo                                                                              
15:00   git commit -m “First commit"                                                                              

Resultado:

*   50839cd - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 0cda99f - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| * f7d6c47 - YYYY-MM-DD 15:03:00 (XX minutes ago)
| |           Second commit - Christophe
| * dd7d05a - YYYY-MM-DD 15:06:00 (XX minutes ago)
| |           Fifth commit - Christophe
| * d0d759b - YYYY-MM-DD 15:05:00 (XX minutes ago)
| |           Fourth commit - Christophe
* |   1a397c5 - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \            Merge branch 'features/foo' - Christophe
| |/
|/|
| * 0600a72 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * f4c127a - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/            Second commit - Christophe
* 0cf894c - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git pull --rebase

No estoy seguro de poder explicarlo mejor que Derek Gourlay... Básicamente, usa git pull --rebase en lugar de git pull :) Lo que falta en el artículo, sin embargo, es que puedes habilitarlo por defecto:

git config --global pull.rebase true

git rerere

Nuevamente, muy bien explicado aquí. Pero ponga simple, si lo habilita, ya no tendrá que resolver el mismo conflicto varias veces.


14
2018-02-10 17:26