743 votos

git flujo de trabajo y de reajuste vs combinación de preguntas

He estado usando git ahora por un par de meses en un proyecto con uno de los desarrolladores de otros. Tengo varios años de experiencia con svn, así que supongo que traerá una gran cantidad de equipaje a la relación.

He oído que git es excelente para la ramificación y fusión, y de momento, yo no lo veo. Seguro, la ramificación es muy sencillo, pero cuando trato de fusionar, todo va todo al infierno. Ahora, estoy acostumbrado a que desde svn, pero a mí me parece que acabo de negociado un mediocre sistema de control de versiones para el otro.

Mi pareja me dice que mis problemas se derivan de mi deseo de fusionar queramos o no, y que yo debería ser el uso de reajuste en lugar de combinar en muchas situaciones. Por ejemplo, aquí es el flujo de trabajo que ha establecido:

clonar el repo remoto
git checkout-b my_new_feature
..trabajo y compromiso de algunas cosas
git rebase maestro
..trabajo y compromiso de algunas cosas
git rebase maestro
..terminar la función
git checkout master
git merge my_new_feature

Esencialmente, crear una rama, SIEMPRE reajuste de maestro a la rama, y la combinación de la rama de nuevo al maestro. Importante a tener en cuenta es que la rama permanece siempre local.

Aquí es el flujo de trabajo que empecé con

clon remoto repo
crear my_new_feature sucursal en la repo remoto
git checkout-b --pista my_new_feature origen/my_new_feature
..trabajo, commit, push to origen/my_new_feature
git merge master (para obtener algunos de los cambios que mi pareja añadido)
..trabajo, commit, push to origen/my_new_feature
git merge maestro
..acabado my_new_feature, de inserción a origen/my_new_feature
git checkout master
git merge my_new_feature
eliminar de la rama remota
borrar sucursal local

Hay 2 diferencias esenciales (creo): yo uso la combinación de siempre en lugar de reajuste, y yo empuje mi rama de la característica (y mi rama de la característica confirma) para el control remoto de repos.

Mi razonamiento para la rama remota es que yo quiero que mi trabajado copia de seguridad como en el que estoy trabajando. Nuestra repo se copia automáticamente y puede ser restaurada si algo va mal. Mi portátil no está, o no tan a fondo. Por lo tanto, no me gusta tener el código en mi laptop que no es reflejado en alguna otra parte.

Mi razonamiento para la combinación en lugar de rebase es que la combinación parece ser la norma y de reajuste parece ser una característica avanzada. Mi sensación es que lo que estoy tratando de hacer no es una configuración avanzada, por lo que rebase debería ser innecesario. Incluso he examinado la nueva Pragmática libro de Programación en git, y se cubren de mezcla ampliamente y apenas mencionan reajuste.

De todos modos, yo estaba siguiendo a mi flujo de trabajo en una reciente rama, y cuando traté de combinar de nuevo a maestro, todo se fue al infierno. Había toneladas de conflictos con cosas que no debería haber importado. Los conflictos sólo tenía ningún sentido para mí. Me tomó un día para ordenar todo, y, finalmente, culminó en un obligó a empujar hacia el maestro a distancia, ya que mi maestro local tiene todos los conflictos resueltos, pero el control remoto de uno todavía no era feliz.

¿Cuál es la "correcta" de flujo de trabajo para algo como esto? Git se supone que para hacer ramificación y fusión de super-fácil, y no estoy viendo.

Actualización 2011-04-15

Esta parece ser una pregunta muy popular, así que pensé en actualizar con mis 2 años de experiencia desde que me preguntó por primera vez.

Resulta que el flujo de trabajo original es correcta, al menos en nuestro caso. En otras palabras, esto es lo que queremos hacer y funciona:

clonar el repo remoto
git checkout-b my_new_feature
..trabajo y compromiso de algunas cosas
git rebase maestro
..trabajo y compromiso de algunas cosas
git rebase maestro
..terminar la función
git checkout master
git merge my_new_feature

De hecho, nuestro flujo de trabajo es un poco diferente, como tendemos a hacer la calabaza se funde en lugar de raw se funde. Esto nos permite convertir nuestras toda la rama de la funcionalidad en un único commit en el maestro. Luego borre de nuestra rama. Esto nos permite, lógicamente, la estructura de nuestro compromete en el maestro, incluso si son un poco desordenado en nuestras sucursales. Así que, esto es lo que hacemos:

clonar el repo remoto
git checkout-b my_new_feature
..trabajo y compromiso de algunas cosas
git rebase maestro
..trabajo y compromiso de algunas cosas
git rebase maestro
..terminar la función
git checkout master
git merge --squash my_new_feature
git commit-m", agregó my_new_feature"
git branch-D my_new_feature

Yo he llegado a amar git y nunca quiero volver a SVN. Si usted está luchando, a seguir con él y, finalmente, verá la luz al final del túnel.

295voto

nilbus Puntos 5476

TL;DR

Un git rebase de flujo de trabajo no protege de la gente que está mal en la resolución de conflictos o las personas que están acostumbrados a un SVN flujo de trabajo, como se sugiere en Evitar Git Desastres: Una Historia Sangrienta. Sólo lo hace la resolución de conflictos más tedioso para ellos y hace que sea más difícil recuperarse de la mala resolución de conflictos. En su lugar, utilice diff3, de modo que no es tan difícil en el primer lugar.


Reajuste de flujo de trabajo no es mejor para la resolución de conflictos!

Yo soy muy pro-rebase para la limpieza de la historia. Sin embargo, si alguna vez me pegó un conflicto, inmediatamente me abortar el reajuste y hacer una mezcla lugar! Lo que realmente me mata que la gente está recomendando un reajuste de flujo de trabajo como una alternativa mejor a una combinación de flujo de trabajo para la resolución de conflictos (que es exactamente lo que esta pregunta fue acerca de).

Si se va "a todos al infierno" durante una combinación de correspondencia, se va a ir "todos al infierno" durante un rebase, y potencialmente mucho más infierno! He aquí por qué:

Razón #1: Resolver los conflictos de una vez, en lugar de una vez para cada commit

Cuando se rebase en lugar de combinación, usted tendrá que llevar a cabo la resolución de conflictos tantas veces como haya compromete a reajuste, por el mismo conflicto!

Real escenario

Me rama de maestro a refactorizar un método complicado en una rama. Mi refactorización de trabajo se compone de 15 comete total que yo trabajo para refactorizar y obtener revisiones de código. Parte de mi refactorización consiste en la fijación de la mezcla de tabulaciones y espacios que estaban presentes en el master antes. Esto es necesario, pero por desgracia, se entra en conflicto con cualquier cambio realizado después de este método en el master. Efectivamente, mientras que yo estoy trabajando en este método, alguien que hace una simple y legítimos de cambio para el mismo método que en la rama principal que debe ser combinado con mis cambios.

Cuando es el momento de combinar mi rama de nuevo con el maestro, tengo dos opciones:

git merge: Puedo obtener un conflicto. Veo el cambio que hicieron para dominar y combinar con (el producto final) de mi rama. Hecho.

git rebase: Tengo un conflicto con mi primer commit. I resolver el conflicto y continuar el reajuste. Tengo un conflicto con mi segundo cometer. I resolver el conflicto y continuar el reajuste. Tengo un conflicto con mi tercer cometer. I resolver el conflicto y continuar el reajuste. Tengo un conflicto con mi cuarto cometer. I resolver el conflicto y continuar el reajuste. Tengo un conflicto con mi quinto cometer. I resolver el conflicto y continuar el reajuste. Tengo un conflicto con mi sexto cometer. I resolver el conflicto y continuar el reajuste. Tengo un conflicto con mi séptimo cometer. I resolver el conflicto y continuar el reajuste. Tengo un conflicto con mi octavo cometer. I resolver el conflicto y continuar el reajuste. Tengo un conflicto con mi noveno cometer. I resolver el conflicto y continuar el reajuste. Tengo un conflicto con mi décima de comprometerse. I resolver el conflicto y continuar el reajuste. Tengo un conflicto con mi undécima cometer. I resolver el conflicto y continuar el reajuste. Tengo un conflicto con mi xii cometer. I resolver el conflicto y continuar el reajuste. Tengo un conflicto con mi xiii cometer. I resolver el conflicto y continuar el reajuste. Tengo un conflicto con mi xiv cometer. I resolver el conflicto y continuar el reajuste. Tengo un conflicto con mi xv cometer. I resolver el conflicto y continuar el reajuste.

Tienes que estar bromeando si este es tu flujo de trabajo preferido. Todo lo que necesita es un espacio en blanco revisión que entra en conflicto con un cambio en el maestro, y en cada commit estará en conflicto y debe ser resuelto. Y este es un simple escenario en el que sólo un espacio en blanco conflicto. Dios no lo quiera, usted tiene un conflicto real participación de los principales cambios en el código a través de archivos y tiene que resolver que en múltiples ocasiones.

Con todos los extra de la resolución de conflictos que tiene que hacer, que sólo aumenta la posibilidad de que usted va a cometer un error. Pero los errores están bien en git ya que se puede deshacer, ¿verdad? Excepto, por supuesto,...

Razón #2: Con reajuste, no se puede deshacer!

Yo creo que todos estamos de acuerdo en que la resolución de conflictos puede ser difícil, y también que algunas personas son muy malos. Puede ser muy propenso a errores, que por qué es tan grande que git hace que sea fácil de deshacer!

Cuando la combinación de una rama, git crea un merge commit que puede ser desechado o modificado si la resolución de conflictos va mal. Incluso si usted ya ha empujado a la mala combinación de comprometerse con el público/autorizado repo, puede utilizar git revert para deshacer los cambios introducidos por la mezcla y vuelva a realizar la mezcla correctamente en una nueva combinación de cometer.

Cuando se rebase una rama, en el probable caso de que la resolución de conflictos se hace mal, estás jodido. Cada commit contiene ahora la mala combinación, y no sólo puede rehacer el reajuste*. En el mejor, tiene que volver atrás y modificar cada uno de los afectados se compromete. No es divertido.

Después de un reajuste, es imposible determinar lo que era originalmente parte de la cometa y lo que se presentó como consecuencia de una mala resolución de conflictos.

*Es posible deshacer un reajuste si se puede cavar la edad refs de git interna de los registros, o si se crea una tercera rama que apunta al último commit antes de reajuste. Usted, por supuesto, tiene que mantener esa rama hasta que estuvieron seguros de que los conflictos se resuelven correctamente, sin introducir errores. Pero aviso que nadie había que como parte de su reajuste del flujo de trabajo...

Tome el infierno fuera de resolución de conflictos: el uso de diff3

Tome este conflicto, por ejemplo:

<<<<<<< HEAD
TextMessage.send(:include_timestamp => true)
=======
EmailMessage.send(:include_timestamp => false)
>>>>>>> feature-branch

Mirar el conflicto, es imposible saber lo que cada rama cambiado o lo que su intención era. Esta es la principal razón, en mi opinión, por qué la resolución de conflictos es confusa y difícil.

diff3 al rescate!

git config --global merge.conflictstyle diff3

Cuando se utiliza el diff3, cada nuevo conflicto tendrá una sección 3ª, la fusión de un ancestro común.

<<<<<<< HEAD
TextMessage.send(:include_timestamp => true)
||||||| merged common ancestor
EmailMessage.send(:include_timestamp => true)
=======
EmailMessage.send(:include_timestamp => false)
>>>>>>> feature-branch

En primer lugar examinar la fusión de un ancestro común. Comparar cada lado para determinar cada rama de la intención. Se puede ver que la HEAD cambiado EmailMessage a TextMessage. Su intención es cambiar la clase que se usa para TextMessage, pasando los mismos parámetros. También se puede ver que cuentan con rama-la intención es pasar false en vez de true para el :include_timestamp opción. Para combinar estos cambios, combinar la intención de ambas:

TextMessage.send(:include_timestamp => false)

En general:

  • Comparar el antepasado común con cada rama, y determinar qué rama tiene el cambio más simple
  • Aplicar ese simple cambio en la otra rama de la versión de el código, por lo que contiene tanto el más simple y el más complejo de cambio
  • Quitar todas las secciones de conflicto código distinto del que se acaba de fusionar el conjunto de cambios en

278voto

VonC Puntos 414372

"Conflictos" significa "evoluciones paralelas de un mismo contenido". Así que si se va "a todos al infierno" durante una combinación, significa que tienen grandes evoluciones en el mismo conjunto de archivos.

La razón por la que un rebase entonces es mejor que una fusión es que:

  • reescribir su local de confirmación historia con la del maestro (y, a continuación, volver a su trabajo, a la resolución de cualquier conflicto, a continuación,)
  • la combinación final sin duda será un "avance rápido", porque tendrá todo el commit de la historia de la maestra, además de que sólo los cambios a aplicar.

Confirmo que el flujo de trabajo correcto en ese caso (evoluciones en conjunto común de archivos) es el reajuste de la primera, y luego fusionar.

Sin embargo, esto significa que, si usted empuja su sucursal local (para la copia de seguridad de razón), que la rama no se debe tirar (o al menos usada) por otra persona (ya que la confirmación de la historia será reescrita por los sucesivos rebase).


Sobre ese tema (de reajuste, a continuación, combinar flujo de trabajo), barraponto menciona en los comentarios de los dos blogs interesantes, tanto desde randyfay.com:

El uso de esta técnica, su trabajo siempre va en la parte superior del poder público como un parche que es hasta la fecha actual HEAD.

(una técnica similar existe para bazar)

25voto

Alex Gontmakher Puntos 714

En mi flujo de trabajo, me rebase tanto como sea posible (y yo trato de hacerlo a menudo. No dejar que las discrepancias se acumulan reduce drásticamente la cantidad y la gravedad de las colisiones entre las ramas).

Sin embargo, incluso en la mayoría de reajuste basado en el flujo de trabajo, hay un lugar para las combinaciones.

Recordemos que mezcla realidad crea un nodo que tiene dos padres. Ahora considere la siguiente situación: tengo dos independientes función de brances a y B, y ahora quieren desarrollar cosas en función de la rama de C que depende de a y de B, mientras que a y B están recibiendo revisado.

¿Qué debo hacer entonces, es la siguiente:

  1. Crear (y de pago) rama de C en la parte superior de A.
  2. Fusionarla con la B

Ahora ramal C incluye los cambios de a y de B, y puedo continuar con el desarrollo. Si he de hacer cualquier cambio a Una, luego me reconstruir la gráfica de las ramas de la siguiente manera:

  1. crear la rama de T en la nueva top de Una
  2. combinación de T con B
  3. reajuste de la C a T
  4. borrar rama T

De esta forma, se puede mantener grafos arbitrarios de las ramas, pero de hacer algo más complejo que la situación descrita anteriormente es ya demasiado complejo, dado que no hay ninguna herramienta automática para hacer el reajuste cuando el padre cambios.

19voto

Scott Brown Puntos 191

NO use git push origin --mirror BAJO CASI CUALQUIER CIRCUNSTANCIA.

No pregunte si estás seguro de que quieres hacer esto, y es mejor estar seguro, porque va a borrar todas sus sucursales remotas que no están en el cuadro local.

http://twitter.com/dysinger/status/1273652486

11voto

Pat Notz Puntos 46841

En tu situación yo creo que tu pareja es la correcta. Lo bueno de reajuste es que a los de afuera los cambios parece que todo sucedió en un lugar limpio secuencia por sí mismos. Esto significa que

  • los cambios son muy fáciles de revisión
  • usted puede seguir para hacer un bonito, pequeño cometa y, sin embargo, usted puede hacer conjuntos de los comete público (mediante la fusión en master) todos a la vez
  • cuando usted mira al público, la rama principal verás diferentes de la serie de confirmaciones para funciones diferentes por diferentes desarrolladores, pero que no todos ellos se entremezclan

Usted todavía puede continuar para empujar su desarrollo privado rama del repositorio remoto para el bien de la copia de seguridad, pero los demás no debe de tratar como a un "público" de la rama ya que vas a ser de reajuste. Por CIERTO, un sencillo comando para hacer esto es git push --mirror origin .

El artículo de Empaquetado de software usando Git hace un trabajo bastante bueno explicando las compensaciones de la fusión frente a reajuste. Es un poco diferente contexto, pero los principales son el mismo, que básicamente se reduce a si sus ramas son públicos o privados y cómo se va a integrar en la línea principal.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X