¿Cuándo usas Git rebase en lugar de Git merge?


1549

¿Cuándo se recomienda usar Git rebase vs. Git merge?

¿Todavía necesito fusionarme después de un rebase exitoso?




66
Un problema con las personas a las que les gusta usar rebase es que les impide empujar su código regularmente. Por lo tanto, querer un historial limpio les impide compartir su código, lo que creo que es más importante.
static_rtti

99
@static_rtti: Eso simplemente no es cierto. Está utilizando un flujo basado en rebase incorrecto si le impide impulsar sus cambios regularmente.
juzzlin

55
Es una verdadera lástima que la respuesta de Andrew Arnott y la respuesta de Pace no se hayan publicado antes, ya que responden esta pregunta de manera más completa que las respuestas anteriores que ya habían acumulado muchos votos.
Mark Booth

Respuestas:


1136

Version corta

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

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

Unir

  • Supongamos que ha creado una rama con el fin de desarrollar una característica única. Cuando desee devolver esos cambios a master, probablemente desee fusionar (no le importa mantener todos los commits provisionales).

Rebase

  • Un segundo escenario sería si comenzaras a desarrollar algo y luego otro desarrollador realizara un cambio no relacionado. Probablemente desee extraer y luego volver a crear una base para basar sus cambios desde la versión actual desde el repositorio.

105
@Rob mencionó el mantenimiento de confirmaciones provisionales al fusionarse. Creo que, por defecto, la fusión de la rama B (una rama de características en la que ha estado trabajando) en la rama M (la rama maestra) creará una confirmación en M para cada confirmación que se realizó en B ya que las dos divergieron. Pero si se fusiona utilizando la opción --squash, todas las confirmaciones realizadas en la rama B se "agruparán" y se fusionarán como una sola confirmación en la rama M, manteniendo el registro en su rama maestra agradable y limpio. El aplastamiento es probablemente lo que desea si tiene numerosos desarrolladores que trabajan de forma independiente y se fusionan nuevamente en master.
spaaarky21

19
Creo que la suposición de @ spaaarky21 sobre la fusión no es correcta. Si combina una rama B en la M maestra, solo habrá una única confirmación en M (incluso si B tiene varias confirmaciones), independientemente de si utiliza una combinación simple o --squash. Lo que hará --quash es eliminar la referencia a B como padre. Una buena visualización está aquí: syntevo.com/smartgithg/howtos.html?page=workflows.merge
jpeskin

14
@jpeskin Eso no es lo que estoy viendo. Acabo de hacer una prueba rápida para verificar. Cree un directorio con un archivo de texto, initun nuevo repositorio, addel archivo y commit. Verificación de una nueva rama de características ( checkout -b feature.) Cambie el archivo de texto, confirme y repita para que haya dos nuevas confirmaciones en la rama de características. Entonces checkout mastery merge feature. En log, veo mi commit inicial en master, seguido de los dos que se fusionaron de la función. Si usted merge --squash feature, la función se fusiona en master pero no se confirma, por lo que el único commit nuevo en master será el que usted mismo haga.
spaaarky21

21
@ spaaarky21 Parece que ambos tenemos la mitad de razón. Cuando es posible una fusión de avance rápido (como en su ejemplo), git incluirá de manera predeterminada todas las confirmaciones en la rama de características B (o, como sugiere, puede usar --squash para combinar en una única confirmación). Pero en el caso de que haya dos ramas divergentes M y B que está fusionando, git no incluirá todas las confirmaciones individuales de la rama B si se fusionan en M (use o no --squash).
jpeskin

66
¿Por qué es que el "(no te importa mantener todos los compromisos provisionales)" aparte en esta respuesta? No tenía sentido en el '09 y no tiene sentido ahora. Además, seguramente solo querrá volver a crear una nueva base si otro desarrollador realizó los cambios relacionados que usted necesitaba; si hicieron cambios no relacionados, su rama de características debería fusionarse fácilmente sin conflictos de todos modos, y su historial se mantendría.
Mark Booth

372

Es simple. Con rebase usted dice que use otra rama como la nueva base para su trabajo.

Si tiene, por ejemplo, una rama master, crea una rama para implementar una nueva característica y dice que la nombra cool-feature, por supuesto, la rama maestra es la base de su nueva característica.

Ahora, en cierto punto, desea agregar la nueva característica que implementó en la masterrama. Podrías cambiar mastery fusionar la cool-featurerama:

$ git checkout master
$ git merge cool-feature

Pero de esta manera se agrega una nueva confirmación ficticia. Si desea evitar la historia de espagueti, puede volver a redactar :

$ 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 de tema tiene las mismas confirmaciones de master más las confirmaciones con la nueva característica, la fusión será solo un avance rápido.


31
but this way a new dummy commit is added, if you want to avoid spaghetti-history- como es malo?
ア レ ッ ク ス

66
Además, la bandera de fusión --no-ff es muy muy útil.
Aldo 'xoen' Giambelluca

3
@ ア レ ッ ク ス como el usuario lo Sean Schofieldpone en un comentario: "Rebase también es bueno porque una vez que finalmente fusionas tus cosas de nuevo en master (que es trivial como ya se describió) lo tienes en la" parte superior "de tu historial de commit. proyectos donde las características pueden escribirse pero fusionarse varias semanas después, no desea fusionarlas en el maestro porque se "rellenan" en el maestro en la historia. Personalmente, me gusta poder hacer git log y ver esa característica reciente justo en la "parte superior". Tenga en cuenta que las fechas de confirmación se conservan: la modificación no cambia esa información ".
Adrien Be

44
Creo que vale la pena repetir aquí - recuerde que todos estos términos ( merge, rebase, fast-forward, etc.) se refieren a las manipulaciones específicas de un grafo acíclico dirigido. Se vuelven más fáciles de razonar con ese modelo mental en mente.
Roy Tinker

10
@Aldo No hay nada "limpio" o "ordenado" sobre una historia modificada. En general es inmundo y en mi humilde opinión porque no tienes idea de lo que realmente sucedió. La historia de Git "más limpia" es la que realmente ocurrió. :)
Marnen Laibow-Koser

269

Para complementar mi propia respuesta mencionada por TSamper ,

  • a menudo es una buena idea hacer una nueva versión antes de una fusión, porque la idea es que integre en su rama Yel trabajo de la rama Bsobre la que se fusionará.
    Pero nuevamente, antes de fusionar, resuelve cualquier conflicto en su rama (es decir, "rebase", como en "reproducir mi trabajo en mi rama comenzando desde un punto reciente de la rama B).
    Si se hace correctamente, la fusión posterior de su rama a la rama Bpuede avanzar rápidamente.

  • una fusión afecta directamente a la rama de destino B, lo que significa que es mejor que las fusiones sean triviales, de lo contrario, esa rama Bpuede ser larga para volver a un estado estable (tiempo para resolver todos los conflictos)


¿El punto de fusión después de un rebase?

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

El otro escenario ( descrito en Git Ready, por ejemplo), es llevar su trabajo directamente a Btravés de un rebase (que conserva todas sus buenas confirmaciones, o incluso le da la oportunidad de reordenarlas a través de un rebase interactivo).
En ese caso (cuando reescribe mientras está en la rama B), tiene razón: no se necesita más fusión:

Un árbol Git por defecto cuando no nos hemos fusionado ni rebajado

rebase1

obtenemos rebasando:

rebase3

El segundo escenario tiene que ver con: ¿cómo vuelvo a incorporar las nuevas funciones en master?

Mi punto, 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 "volver a poner la nueva característica en master").
Puede usar rebase para primero traer el maestro "a" la rama de nuevas características: la rebase reproducirá confirmaciones de nuevas características desde HEAD master, pero aún en la rama de nuevas características, moviendo efectivamente el punto de inicio de la rama desde una antigua confirmación maestra a HEAD-master.
Eso le permite resolver cualquier conflicto en su rama (es decir, de forma aislada, mientras permite que el maestro continúe evolucionando en paralelo si su etapa de resolución de conflictos toma demasiado tiempo).
Luego puede cambiar a master y fusionar new-feature(o volver new-featurea crear una base mastersi desea conservar los commits realizados en sunew-feature rama).

Entonces:

  • "rebase vs. fusión" se puede ver como dos formas de importar una obra en, por ejemplo, master.
  • Pero "rebase luego fusionar" puede ser un flujo de trabajo válido para resolver primero el conflicto de forma aislada y luego recuperar su trabajo.

17
fusionar después de rebase es un avance rápido trivial sin tener que resolver conflictos.
obecalp

44
@obelcap: De hecho, esta es una idea: tomas todos los conflictos de problemas en tu entorno (rebase master dentro de tu rama de nuevas características), y luego co master, fusionas new-feature: 1 pico-second (fast- adelante) si el maestro no tuvo evoluciones
VonC

27
Rebase también es bueno porque una vez que finalmente fusionas tus cosas nuevamente en master (lo cual es trivial como ya se describió) lo tienes en la "parte superior" de tu historial de commit. En proyectos más grandes donde las características pueden escribirse pero fusionarse varias semanas después, no desea fusionarlas en el maestro porque se "rellenan" en el maestro en la historia. Personalmente, me gusta poder hacer git log y ver esa característica reciente en la "parte superior". Tenga en cuenta que las fechas de confirmación se conservan: el rebase no cambia esa información.
Sean Schofield

3
@ Joe: mentalmente, estás diciendo "reproducir cualquiera de mis cambios (hecho de forma aislada en mi rama privada) encima de esa otra rama, pero déjame en mi rama privada una vez que haya terminado el rebase". Esa es una buena oportunidad para limpiar el historial local, evitando "confirmaciones de puntos de control", bisectos rotos y resultados de culpa incorrectos. Consulte "Flujo de trabajo de Git": sandofsky.com/blog/git-workflow.html
VonC

44
@scoarescoare la clave es ver cómo los cambios locales son compatibles además de la última rama ascendente. Si uno de sus commits introduce un conflicto, lo verá de inmediato. Una fusión introduce solo una confirmación (fusionada), que podría desencadenar muchos conflictos sin una manera fácil de ver cuál, entre sus propias confirmaciones locales, agregó dicho conflicto. Entonces, además de un historial más limpio, obtienes una vista más precisa de los cambios que introduces, commit by commit (reproducido por el rebase), a diferencia de todos los cambios introducidos por la rama ascendente (volcado en una sola fusión).
VonC

229

TL; DR

Si tiene alguna duda, use merge.

Respuesta corta

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

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

Entonces, la respuesta corta es elegir rebase o fusionar en función de cómo desea que se vea su historial .

Respuesta larga

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

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

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

¿Qué tan hábil es su equipo de desarrollo?

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

He trabajado en equipos en los que todos los desarrolladores proceden de una época en que las empresas podían permitirse personal dedicado para ocuparse de la ramificació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 un rebase por ningún motivo.

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

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

También he trabajado en equipos que usaron el modelo de sucursal por desarrollador (todos hemos estado allí). En este caso, la rama en sí no transmite ninguna información adicional (el commit ya tiene el autor). No habría daño en el rebase.

¿Podría querer revertir la fusión por alguna razón?

Revertir (como al deshacer) un rebase es considerablemente difícil y / o imposible (si el rebase tuvo conflictos) en comparación con revertir una fusión. Si crees que existe la posibilidad de que quieras revertir, usa merge.

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

Las operaciones de rebase deben extraerse con un correspondiente git pull --rebase. Si está trabajando solo, puede recordar cuál debe usar en el momento adecuado. Si está trabajando en un equipo, será muy difícil de coordinar. 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 --rebasepara todos los pulls).

Mitos comunes

La fusión destruye la historia (aplasta las confirmaciones)

Suponiendo que tiene la siguiente fusión:

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

Algunas personas afirmarán que la fusión "destruye" el historial de confirmación porque si mirara el registro de solo la rama maestra (A - D), perdería los mensajes importantes de confirmación 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 (usando --first-parent). Esto es muy fácil de probar por ti mismo.

Rebase permite fusiones más seguras / simples

Los dos enfoques se fusionan de manera diferente, pero no está claro que uno sea siempre 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 comprometen dos veces al día mientras hacen la transición del trabajo al hogar), entonces podría haber muchos compromisos para una rama determinada. Es posible que muchas de esas confirmaciones no se parezcan en nada al producto final (tiendo a refactorizar mi enfoque una o dos veces por función). Si alguien más estaba trabajando en un área de código relacionada e intentaban modificar mis cambios, podría ser una operación bastante tediosa.

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

Si le gusta usar un alias rmpara rm -rf"ahorrar tiempo", entonces tal vez sea necesario un rebase.

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, me encontraré con un escenario en el que el reflog de Git es una herramienta increíble que resuelve mi problema. He trabajado con Git por más de cinco años. No ha sucedido

Las historias desordenadas nunca han sido realmente un problema para mí. No solo leo mi historia de compromiso como una novela emocionante. La mayoría de las veces necesito un historial, voy a usar Git culpar o Git bisecar de todos modos. En ese caso, tener la confirmación de fusión es realmente útil para mí, porque si la fusión introdujo el problema, esa es información significativa para mí.

Actualización (4/2017)

Me siento obligado a mencionar que personalmente me he suavizado con el uso de rebase, aunque mi consejo general sigue vigente. Recientemente he estado interactuando mucho con el proyecto Angular 2 Material . Han utilizado rebase para mantener un historial de confirmación muy limpio. Esto me ha permitido ver muy fácilmente qué confirmación corrigió un defecto dado y si esa confirmación se incluyó o no en una versión. Sirve como un gran ejemplo de uso de rebase correctamente.


55
Debería ser la respuesta validada.
Mik378

Esta es ciertamente la mejor respuesta. Especialmente con el comentario aclarado en la última actualización. Ayuda a mantener el historial de git limpio y claro, pero úselo de manera segura.
zquintana

55
Sobre todo me encanta esta respuesta. Pero: Rebase no hace un historial "limpio". Hace una historia más lineal, pero eso no es lo mismo en absoluto, ya que quién sabe ahora qué "suciedad" esconde cada commit. La historia de Git más limpia y clara es la que mantiene la ramificación y la integridad.
Marnen Laibow-Koser

3
"Mito común, ves los compromisos B y C": ¡No necesariamente! En realidad, solo verá B y C si la fusión fue una combinación de avance rápido y eso solo es posible si no hubo conflictos. Si hay conflictos, ¡obtienes una única confirmación! Sin embargo: puede fusionar el maestro en la función primero y resolver conflictos allí y si luego combina la función en el maestro, obtiene los compromisos B y C, y una sola confirmación X de la (primera) fusión del maestro en la función en su historial.
Jeremy Benks

Muy buena explicación! ¡Debe votar más!
atenúa el

185

Muchas respuestas aquí dicen que la fusión convierte todas sus confirmaciones en una sola y, por lo tanto, sugiere utilizar rebase para preservar sus confirmaciones. Esto es incorrecto. Y una mala idea si ya has empujado tus commits .

La fusión no borra tus commits. ¡La fusión preserva la historia! (solo mira gitk) Rebase reescribe el historial, lo cual es una mala cosa después de haberlo empujado .

Use merge - no rebase cuando ya haya presionado.

Aquí está la versión de Linus (autor de Git) (ahora alojada en mi propio blog, recuperada por Wayback Machine ). Es una muy buena lectura.

O puede leer mi propia versión de la misma idea a continuación.

Rebasar una rama en master:

  • proporciona una idea incorrecta de cómo se crearon los commits
  • contamina al maestro con un montón de confirmaciones intermedias que pueden no haber sido bien probadas
  • en realidad podría introducir saltos de compilación en estas confirmaciones intermedias debido a los cambios que se realizaron para dominar entre el momento en que se creó la rama del tema original y el momento en que se modificó.
  • hace que sea difícil encontrar buenos lugares en master para pagar
  • Hace que las marcas de tiempo en las confirmaciones no se alineen con su orden cronológico en el árbol. Entonces vería que commit A precede a commit B en master, pero commit B fue creado primero. (¡¿Qué?!)
  • Produce más conflictos, porque los compromisos individuales en la rama del tema pueden involucrar conflictos de fusión que deben resolverse individualmente (mentir en la historia sobre lo que sucedió en cada compromiso).
  • Es una reescritura de la historia. Si la rama que se está rebautizando ha sido empujada a cualquier lugar (compartida con alguien que no sea usted), entonces ha arruinado a todos los demás que tienen esa rama desde que reescribió el historial.

Por el contrario, fusionar una rama de tema en maestro:

  • conserva el historial de dónde se crearon las ramas de temas, incluidas las fusiones del maestro a la rama de temas para ayudar a mantenerlo actualizado. Realmente tienes una idea precisa de con qué código trabajaba el desarrollador cuando estaban construyendo.
  • master es una rama compuesta principalmente de fusiones, y cada una de esas confirmaciones de fusión son típicamente 'buenos puntos' en la historia que son seguros de verificar, porque ahí 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 estaban en una rama de tema, por lo que aislar esos cambios es natural y puede profundizar cuando 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 confirmación intermedios realizados en la rama del tema no tienen que resolverse de forma independiente.
  • Se puede hacer varias veces sin problemas. Si integra su rama de tema para dominar periódicamente, la gente puede seguir construyendo sobre la rama de tema, y ​​puede seguir fusionándose de forma independiente.

3
Además, git merge tiene la opción "--no-ff" (sin avance rápido) que le permite revertir todos los cambios introducidos por una determinada fusión con mucha facilidad.
Tiago

3
Solo déjalo más claro: te refieres a la situación "cuando ya has presionado", esto debería ser audaz. El enlace a la publicación de Linus es genial, por cierto, lo aclara.
honzajde

2
pero, ¿no es la mejor práctica "actualizar" del maestro a la rama de su tema, antes de fusionar la rama del tema en el maestro a través de relaciones públicas (para resolver conflictos en su rama, no en el maestro)? Lo estamos haciendo así, así que la mayoría de las ramas de temas tienen como último compromiso "fusionar maestro de rama en tema -...", pero aquí aparece como una "característica" de rebase y nadie lo menciona por fusión ...?
ProblemsOfSumit

2
@AndrewArnott "La mayoría de las ramas temáticas deberían poder fusionarse sin conflictos en sus ramas objetivo" ¿Cómo debería ser posible cuando 20 desarrolladores trabajan en 30 ramas? Habrá fusiones mientras trabajas en las tuyas, por lo que, por supuesto, debes actualizar tu rama de tema desde el objetivo antes de crear un RP ... ¿no?
ProblemsOfSumit

3
Generalmente no, @Sumit. Git puede fusionar cualquier dirección muy bien a pesar de que se han realizado cambios en una o ambas ramas. Solo cuando las mismas líneas de código (o muy cercanas) se modifiquen en dos ramas, obtendrá conflictos. Si eso sucede con frecuencia en cualquier equipo, el equipo debe repensar cómo distribuyen el trabajo, ya que resolver conflictos es un impuesto y los ralentiza.
Andrew Arnott

76

TLDR: depende de lo más importante: una historia ordenada o una representación real de la secuencia de desarrollo

Si un historial ordenado es lo más importante, primero debe volver a crear una base y luego combinar los cambios, para que quede claro exactamente cuál es el nuevo código. Si ya ha empujado su rama, no rebase a menos que pueda lidiar con las consecuencias.

Si la representación verdadera de la secuencia es lo más importante, usted se fusionaría sin rebasar.

Fusionar significa: crear una nueva confirmación única que combine mis cambios en el destino. Nota: Esta nueva confirmación tendrá dos padres: la última confirmación de su cadena de confirmaciones y la última confirmación de la otra rama que está fusionando.

Rebase significa: Crear una serie completamente nueva de confirmaciones, utilizando mi conjunto actual de confirmaciones como pistas. En otras palabras, calcule cómo se habrían visto mis cambios si hubiera comenzado a hacerlos desde el punto en el que estoy haciendo un rebase. Después de la nueva versión, por lo tanto, es posible que deba volver a probar sus cambios y durante la nueva versión, posiblemente tenga algunos conflictos.

Dado esto, ¿por qué rebajas? Solo para mantener claro el historial de desarrollo. Supongamos que está trabajando en la función X y cuando haya terminado, combine sus cambios. El destino ahora tendrá una única confirmación que dirá algo similar a "Función X añadida". Ahora, en lugar de fusionar, si reorganiza y luego fusiona, el historial de desarrollo de destino contendría todas las confirmaciones individuales en una sola progresión lógica. Esto hace que revisar los cambios más adelante sea mucho más fácil. Imagine lo difícil que sería revisar el historial de desarrollo si 50 desarrolladores fusionaran varias funciones todo el tiempo.

Dicho esto, si ya ha empujado la rama en la que está trabajando en sentido ascendente, no debe volver a redactar, sino fusionar. Para las sucursales que no han sido empujadas aguas arriba, rebase, pruebe y fusione.

Otro momento en el que es posible que desee cambiar la base es cuando desea deshacerse de los commits de su rama antes de avanzar. Por ejemplo: los commits que introducen algún código de depuración desde el principio y otros commits más adelante que limpian ese código. La única forma de hacer esto es realizar un rebase interactivo:git rebase -i <branch/commit/tag>

ACTUALIZACIÓN: también desea utilizar rebase cuando use Git para interactuar con un sistema de control de versiones que no admite historial no lineal ( Subversion, por ejemplo). Cuando se usa el puente git-svn, es muy importante que los cambios que fusiones de nuevo en Subversion sean una lista secuencial de cambios además de los cambios más recientes en troncal. Solo hay dos formas de hacerlo: (1) Vuelva a crear manualmente los cambios y (2) Usando el comando rebase, que es mucho más rápido.

ACTUALIZACIÓN 2: Una forma adicional de pensar en un rebase es que permite una especie de mapeo desde su estilo de desarrollo al estilo aceptado en el repositorio con el que se está comprometiendo. Digamos que te gusta cometer en trozos pequeños y pequeños. Tiene una confirmación para corregir un error tipográfico, una confirmación para deshacerse del código no utilizado, etc. Cuando haya terminado lo que necesita hacer, tiene una larga serie de confirmaciones. Ahora, digamos que el repositorio al que se compromete fomenta grandes confirmaciones, por lo que para el trabajo que está haciendo, uno esperaría una o quizás dos confirmaciones. ¿Cómo tomas tu cadena de commits y los comprimes a lo que se espera? Usaría un rebase interactivo y aplastaría sus pequeños commits en menos trozos más grandes. Lo mismo es cierto si se necesitaba lo contrario: si su estilo consistía en algunas confirmaciones grandes, pero el repositorio exigía largas cadenas de pequeños commits. También usarías un rebase para hacer eso. Si se fusionó, ahora ha injertado su estilo de confirmación en el repositorio principal. Si hay muchos desarrolladores, puedes imaginar lo difícil que sería seguir un historial con varios estilos de confirmación diferentes después de un tiempo.

ACTUALIZACIÓN 3: Does one still need to merge after a successful rebase?Sí, lo haces. La razón es que un rebase implica esencialmente un "cambio" de commits. Como he dicho anteriormente, estas confirmaciones se calculan, pero si tuvo 14 confirmaciones desde el punto de bifurcación, suponiendo que nada salga mal con su rebase, tendrá 14 confirmaciones por delante (del punto en el que rebase) después El rebase está hecho. Tenías una rama antes de un rebase. Tendrás una rama de la misma longitud después. Aún necesita fusionarse antes de publicar sus cambios. En otras palabras, rebase tantas veces como desee (nuevamente, solo si no ha empujado sus cambios en sentido ascendente). Fusionarse solo después de rebase.


1
Una fusión con master podría resultar en un avance rápido. En una rama de características puede haber algunas confirmaciones, que tienen errores menores o ni siquiera se compilan. Si solo realiza pruebas unitarias en una rama de características, algunos errores en la integración pueden pasar. Antes de fusionarse con master, se requieren pruebas de integración que pueden mostrar algunos errores. Si se solucionan, la característica podría integrarse. Como no desea comprometer el código con errores para dominar, parece necesario un cambio de base para evitar un avance rápido de todos los compromisos.
mbx

1
@mbx git mergeadmite la --no-ffopción que lo obliga a realizar una confirmación de fusión.
Gavin S. Yancey

63

Si bien la fusión es definitivamente la forma más fácil y más 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 fusión, busca tres confirmaciones:

  • (1) Cometer ancestro común. Si sigue la historia de dos ramas en un proyecto, siempre tienen al menos un compromiso en común: en este momento, 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 últimas revisiones respectivas son de especial interés. La combinación de estos tres commits dará como resultado la integración que buscamos.

Avance rápido o confirmación de fusión

En casos muy simples, una de las dos ramas no tiene nuevas confirmaciones desde que ocurrió la ramificación: su última confirmación sigue siendo el antepasado común.

Ingrese la descripción de la imagen aquí

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

Ingrese la descripción de la imagen aquí

Sin embargo, en muchos casos, ambas ramas avanzaron individualmente.

Ingrese la descripción de la imagen aquí

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

Ingrese la descripción de la imagen aquí

Compromisos humanos y compromisos de fusión

Normalmente, un compromiso es creado cuidadosamente por un ser humano. Es una unidad significativa que envuelve solo los 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 de fusión automática. En cambio, quieren que la historia del proyecto se vea como si hubiera evolucionado en una sola línea recta. No hay indicios de que se haya dividido en varias ramas en algún momento.

Ingrese la descripción de la imagen aquí

Pasemos por una operación de rebase paso a paso. 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.

Ingrese la descripción de la imagen aquí

Haremos esto en tres pasos.

  1. git rebase branch-A // Synchronises 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 "deshacerá" todas las confirmaciones en la rama A que sucedió después de que las líneas comenzaron a ramificarse (después de la confirmación del ancestro común). Sin embargo, por supuesto, no los descartará: en su lugar, puede pensar en esas confirmaciones como "guardadas temporalmente".

Ingrese la descripción de la imagen aquí

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

Ingrese la descripción de la imagen aquí

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 rama B (se vuelven a basar).

El resultado parece que el desarrollo había sucedido en línea recta. En lugar de una confirmación de fusión que contiene todos los cambios combinados, se mantuvo la estructura de confirmación original.

Ingrese la descripción de la imagen aquí

Finalmente, obtienes una rama limpia branch -A sin commits no deseados y autogenerados.

Nota: Tomado de la impresionante publicación de git-tower. Las desventajas de rebasetambién es una buena lectura en la misma publicación.


+1 para diagramas muy geniales. Siempre quise poder ilustrar un ejemplo de flujo de git de la misma manera sin suerte.
Mikayil Abdullayev

60

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 confirmaciones)

Este ejemplo y mucha más información bien ilustrada sobre Git se puede encontrar en Git The Basics Tutorial .


30

Esta oración lo entiende:

En general, la forma de obtener lo mejor de ambos mundos es modificar los cambios locales que ha realizado, pero que aún no ha compartido, antes de presionarlos para limpiar su historia, pero nunca rebase nada que haya empujado a alguna parte .

Fuente: 3.6 Git Branching - Rebasing, Rebase vs. Merge


25

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 ( alias 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. Vea también la diferencia entre git mergey git merge --no-ffprimero (generalmente desea usarlo git merge --no-ffya que hace que su historial se vea más cerca de 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 características en desarrollo, nunca vuelva a desarrollar el desarrollo a partir de características . Esta es una consecuencia de la Regla de Oro de Rebasar :

La regla de oro git rebasees nunca usarlo en las ramas públicas .

En otras palabras :

Nunca rebajes 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 sean conscientes de las consecuencias .

Por lo tanto, la cuestión de git mergevs se git rebaseaplica casi solo a las ramas de características (en los siguientes ejemplos, --no-ffsiempre se ha utilizado al fusionar). Tenga en cuenta que, dado que no estoy seguro de que haya una solución mejor ( existe un debate ), solo proporcionaré cómo se comportan ambos comandos. En mi caso, prefiero usarlo git rebaseya 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 developa una rama característica

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 develop
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 develop
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 al margen

git cherry-pick

Cuando solo necesita una confirmación específica, git cherry-pickes una buena solución (la -xopción agrega una línea que dice " (recogido de la confirmación ...) " al cuerpo del mensaje de confirmación original, por lo que generalmente es una buena idea usarlo, git log <commit_sha1>para ver eso):

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, use en git pull --rebaselugar de git pull:) Sin embargo, lo que falta en el artículo es que puede habilitarlo de manera predeterminada :

git config --global pull.rebase true

git rerere

De nuevo, bien explicado aquí . Pero simplemente, si lo habilita, ya no tendrá que resolver el mismo conflicto varias veces.


15

El libro Pro Git tiene una muy buena explicación en la página de rebase .

Básicamente, una fusión tomará dos commits y los combinará.

Un rebase irá al antepasado común en los dos y aplicará los cambios de forma incremental uno encima del otro. Esto lo convierte en un historial más "limpio" y más lineal.

Pero cuando rebasas, abandonas las confirmaciones anteriores y creas nuevas. Por lo tanto, nunca debe volver a crear un repositorio que sea público. Las otras personas que trabajan en el repositorio te odiarán.

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


1
Las fusiones no combinan confirmaciones, eso sería reescribir el historial. Rebase hace eso.
kellyfj

4

Git rebase se utiliza para hacer que las rutas de ramificación en el historial sean más limpias y la estructura del repositorio sea lineal.

También se usa para mantener las ramas creadas por usted de manera privada, ya que después de volver a modificar y enviar los cambios al servidor, si elimina su rama, no habrá evidencia de la rama en la que ha trabajado. Entonces su sucursal es ahora su preocupación local.

Después de hacer rebase, también nos deshacemos de un commit adicional que solíamos ver si hacemos una fusión normal.

Y sí, uno aún necesita fusionarse después de un rebase exitoso ya que el comando rebase solo coloca su trabajo en la parte superior de la rama que mencionó durante el rebase, diga master, y realiza el primer commit de su rama como descendiente directo de la rama master . Esto significa que ahora podemos hacer una combinación de avance rápido para traer cambios de esta rama a la rama maestra.


4

Si solo es un desarrollador, puede usar rebase en lugar de fusionar para tener un historial claro

ingrese la descripción de la imagen aquí


3

Algunos ejemplos prácticos, algo conectados con el desarrollo a gran escala donde Gerrit se utiliza para la revisión y la integración de entrega:

Me fusiono cuando elevo mi rama de características a un nuevo maestro remoto. Esto proporciona un trabajo de elevación mínimo y es fácil seguir la historia del desarrollo de características en, por ejemplo, gitk .

git fetch
git checkout origin/my_feature
git merge origin/master
git commit
git push origin HEAD:refs/for/my_feature

Me fusiono cuando preparo un compromiso de entrega.

git fetch
git checkout origin/master
git merge --squash origin/my_feature
git commit
git push origin HEAD:refs/for/master

Reescribo cuando mi confirmación de entrega falla la integración por cualquier razón, y necesito actualizarlo hacia un nuevo maestro remoto.

git fetch
git fetch <gerrit link>
git checkout FETCH_HEAD
git rebase origin/master
git push origin HEAD:refs/for/master

3

Se explicó muchas veces qué rebase y qué fusión es, pero ¿cuándo debería usar qué?

¿Cuándo deberías usar rebase?

  • cuando no ha empujado la rama / nadie más está trabajando en ella
  • quieres la historia completa
  • desea evitar todos los mensajes de confirmación "combinados ..." generados automáticamente

A medida que Git rebase cambia la historia. Por lo tanto, no debe usarlo cuando alguien más esté trabajando en la misma rama / si lo ha presionado. Pero si tiene una sucursal local, puede hacer una fusión de rebase master antes de fusionar su sucursal nuevamente en master para mantener un historial más limpio. Al hacer esto, después de fusionarse con la rama maestra, no será visible que usó una rama en la rama maestra: el historial es "más limpio" ya que no ha generado automáticamente "fusionado ..", pero aún tiene el historial completo en su rama maestra sin haber confirmado "fusionado .." autogenerado.

Sin embargo, asegúrese de usar git merge feature-branch --ff-onlypara asegurarse de que no haya conflictos al crear una sola confirmación al fusionar su función con main. Esto es interesante si está utilizando ramas de características para cada tarea en la que trabaja a medida que obtiene el historial de la rama de características, pero no una confirmación "combinada ..."

Un segundo escenario sería, si se bifurca desde una rama y quiere saber qué ha cambiado en la rama principal. Rebase le brinda la información, ya que incluye cada confirmación individual.

¿Cuándo deberías usar merge?

  • cuando ha empujado la rama / otros también están trabajando en ella
  • no necesitas la historia completa
  • simplemente fusionarse es lo suficientemente bueno para ti

Cuando no necesita o quiere tener todo el historial de una rama de características en su rama maestra o si otros están trabajando en la misma rama / la ha presionado. Si aún desea tener el historial, solo combine master en la rama de características antes de fusionar la rama de características en master. Esto dará como resultado una fusión de avance rápido donde tiene el historial de la rama de características en su maestro (incluida la confirmación de fusión que estaba en su rama de características porque fusionó el maestro en ella).


-4

¿Cuándo lo uso git rebase? Casi nunca, porque reescribe la historia. git mergees casi siempre la opción preferible, porque respeta lo que realmente sucedió en su proyecto.


1
@benjaminhull ¡Gracias! Excepto que espero que mi respuesta esté basada en hechos. La opinión de la OMI no tiene mucho lugar en este tipo de cosas: es un hecho que perder su historia real hace que la vida sea más difícil más adelante.
Marnen Laibow-Koser

1
De acuerdo. La fusión nunca conducirá a un historial corrupto, etc. (cuando reescribas tus commits empujados)
surfrider
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.