tag remota rama example crear git merge workflow release cherry-pick

remota - git push example



¿Qué modelos de ramificación de Git funcionan para ti? (4)

Nuestra empresa actualmente utiliza un modelo de ramificación de troncal / versión / revisión simple y le gustaría recibir consejos sobre qué modelos de ramificación funcionan mejor para su compañía o proceso de desarrollo.

  1. Flujos de trabajo / modelos de ramificación

    A continuación se encuentran las tres descripciones principales de esto que he visto, pero se contradicen parcialmente entre sí o no van lo suficientemente lejos para resolver los problemas subsiguientes que hemos encontrado (como se describe a continuación). Por lo tanto, nuestro equipo hasta ahora no ofrece soluciones tan buenas. ¿Estás haciendo algo mejor?

  2. Fusionar vs rebasar (enredado vs historia secuencial)

    ¿Se debe pull --rebase o esperar con la fusión de nuevo a la línea principal hasta que su tarea haya finalizado? Personalmente me inclino hacia la fusión ya que esto conserva una ilustración visual de la base en la que se inició y finalizó una tarea, e incluso prefiero merge --no-ff para este propósito. Sin embargo, tiene otros inconvenientes. Además, muchos no se han dado cuenta de la útil propiedad de la fusión, que no es commutative (la fusión de una rama de tema en maestro no significa la combinación de maestro en la rama de tema).

  3. Estoy buscando un flujo de trabajo natural.

    Algunas veces los errores ocurren porque nuestros procedimientos no capturan una situación específica con reglas simples. Por ejemplo, una solución necesaria para versiones anteriores debería, por supuesto, basarse lo suficientemente en sentido descendente para que sea posible fusionar en sentido ascendente en todas las sucursales (¿es el uso de estos términos lo suficientemente claro?). Sin embargo, sucede que una solución llega al maestro antes de que el desarrollador se dé cuenta de que debería haber sido colocado más hacia abajo, y si eso ya está presionado (aún peor, fusionado o algo basado en él), la opción restante es la selección de cerebros, con Sus peligros asociados. ¿Qué simples reglas como estas usas? También en esto se incluye la incomodidad de una rama temática que excluye necesariamente otras ramas temáticas (asumiendo que están ramificadas de una línea base común). Los desarrolladores no quieren terminar una característica para iniciar otra con la sensación de que el código que acaban de escribir ya no existe

  4. ¿Cómo evitar la creación de conflictos de fusión (debido a cherry pick)?

    Lo que parece ser una forma segura de crear un conflicto de fusión es elegir entre las ramas, ¿no se pueden volver a fusionar? ¿Sería posible resolver esta situación aplicando la misma confirmación en reversa (cómo hacer esto?) En cualquiera de las sucursales? Esta es una de las razones por las que no me atrevo a presionar por un flujo de trabajo en gran parte basado en la fusión.

  5. ¿Cómo descomponerse en ramas tópicas?

    Nos damos cuenta de que sería asombroso ensamblar una integración completa de las ramas temáticas, pero a menudo el trabajo de nuestros desarrolladores no está claramente definido (a veces es tan simple como "hurgando") y si algún código ya ha entrado en un tema "misceláneo", ¿No se puede sacar de allí otra vez, de acuerdo con la pregunta anterior? ¿Cómo trabaja para definir / aprobar / graduar / liberar sus ramas temáticas?

  6. Los procedimientos adecuados, como la revisión del código y la graduación , por supuesto, serían hermosos.

    Pero simplemente no podemos mantener las cosas lo suficientemente desenredadas para manejar esto, ¿alguna sugerencia? Ramas de integración, ilustraciones?

A continuación hay una lista de preguntas relacionadas:

También revise lo que Plastic SCM escribe sobre el desarrollo impulsado por tareas , y si Plastic no es su elección, estudie el modelo de bifurcación de nvie y sus scripts de apoyo .


Creo, y podría estar equivocado, que una de las cosas que más se malinterpreta acerca de git es su naturaleza distribuida. Esto hace que sea muy diferente decir subversión en las formas en que puede trabajar, aunque puede imitar el comportamiento de SVN si lo desea. El problema es que prácticamente cualquier flujo de trabajo funcionará, lo cual es genial pero también engañoso.

Si entiendo bien el desarrollo del kernel (me enfocaré en eso), todos tienen su propio repositorio git para desarrollar el kernel. Hay un repositorio, linux-2.6.git, atendido por Torvalds, que actúa como repositorio de lanzamiento. La gente clona desde aquí si desea comenzar a desarrollar una función en contra de la rama de "lanzamiento".

Otros repositorios hacen algún desarrollo. La idea es clonar desde linux-2.6, ramificarse tantas veces como desee hasta el punto en el que tenga una función "nueva" en funcionamiento. Luego, cuando esto esté listo, puede ponerlo a disposición de alguien considerado de confianza, que extraerá esta rama de su repositorio en la de ellos y la combinará con la corriente principal. En el kernel de Linux, esto ocurre en varios niveles (tenientes de confianza) hasta que alcanza el linux-2.6.git, punto en el que se convierte en "el kernel".

Ahora aquí es donde se vuelve confuso. Los nombres de las sucursales no necesitan ser consistentes en todos los repositorios. Así que puedo git pull origin master:vanilla-code y obtener una rama del maestro de origin en una sucursal de mi repositorio llamada vanilla-code . A condición de que sepa lo que está pasando, realmente no importa, se distribuye en el sentido de que todos los repositorios son iguales entre sí y no solo se comparten en varias computadoras como SVN.

Entonces, con todo esto en mente:

  1. Creo que depende de cada programador cómo hacen su ramificación. Todo lo que necesita es un repositorio central para administrar las versiones, etc. Trunk podría ser la head . Los lanzamientos pueden ser etiquetas o sucursales y las revisiones son probablemente sucursales en sí mismas. De hecho, es probable que haga lanzamientos como sucursales para que puedas seguir parchándolos.
  2. Me uniría y no rebase. Si, por ejemplo, toma un repositorio, lo clona, ​​se ramifica y hace algo de desarrollo, luego extraiga de su origin , en su repositorio, probablemente yourbranch otra rama y fusione el último master en yourbranch para que otra persona pueda extraer sus cambios como poco esfuerzo como sea posible. En mi experiencia, muy raramente hay una necesidad de rebase de verdad.
  3. Creo que es un caso de entender cómo funciona Git y lo que puede hacer. Lleva un tiempo y mucha buena comunicación. Solo empecé a entender realmente lo que sucede cuando comencé a usar git con otros desarrolladores e incluso ahora, algunas cosas de las que no estoy seguro.
  4. Los conflictos de fusión son útiles. Lo sé, lo sé, quiere que todo funcione, pero el hecho es que el código cambia y usted necesita fusionar los resultados en algo que funcione. Los conflictos de fusión son, de hecho, sólo más programación. Nunca he encontrado una explicación fácil para qué hacer con ellos, así que aquí está: note los archivos que tienen conflictos de fusión, vaya y cámbielos a lo que deberían ser, git add . y luego git commit .
  5. Sin embargo se adapta. Como he dicho, cada repositorio de git de los usuarios es suyo para jugar y los nombres de las sucursales no tienen que ser los mismos . Si tuviera un repositorio de pruebas, por ejemplo, podría imponer un esquema de nombres, pero no es necesario para cada desarrollador, solo en el repositorio de lanzamiento.
  6. Esta es la etapa de fusión. Solo se fusiona con las sucursales de lanzamiento, etc. cuando considera que el código se revisa / pasa la prueba de calidad.

Espero que eso ayude. Me doy cuenta de que VonC acaba de publicar una explicación muy similar ... ¡No puedo escribir lo suficientemente rápido!

Edite algunos pensamientos adicionales sobre cómo usar git en un entorno comercial, ya que esto parece relevante para el OP de los comentarios:

  • El repositorio de versiones, lo llamaremos product.git , es accesible para una serie de programadores / técnicos superiores responsables de cuidar el producto en sí. Son análogos al papel de los mantenedores en OSS.
  • Estos programadores probablemente también lideran en parte el desarrollo de nuevas versiones, por lo que también pueden codificarse ellos mismos y mantener varios repositorios. Es posible que administren repositorios de prueba para características realmente nuevas y también pueden tener sus propios repositorios.
  • Debajo de ellos hay programadores responsables de desarrollar bits individuales. Por ejemplo, alguien podría ser responsable del trabajo de UI. Por lo tanto, gestionan el repositorio UI.git.
  • Debajo de ellos están los programadores que desarrollan las funciones como su trabajo diario.

¿Así que lo que sucede? Bueno, todos sacan al comienzo de cada día de la fuente "ascendente", es decir, el repositorio de lanzamiento (que probablemente también contendrá el último material del desarrollo de los días anteriores). Todo el mundo hace esto, directamente. Esto irá a una rama en su repositorio, probablemente llamado "maestro" o tal vez si me llaman "último". El programador entonces hará algún trabajo. Este trabajo puede ser algo de lo que no están seguros, así que hacen una rama, hacen el trabajo. Si no funciona, pueden eliminar la rama y volver. Si lo hace, tendrán que fusionarse con la rama principal en la que están trabajando actualmente. Diremos que este es un programador de IU que trabaja en la latest-ui usuario, por lo que realiza git checkout latest-ui seguido de git merge abc-ui-mywhizzynewfeature . Luego le dice a su jefe técnico (el líder de UI) hey, he completado una tarea de este tipo, tira de mí. Así que la ventaja de la interfaz de usuario hace que git pull user-repo lastest-ui:lastest-ui-suchafeature-abc . Luego, el líder de la interfaz de usuario lo mira en esa rama y dice: en realidad, eso es muy bueno, lo fusionaré ui-latest interfaz de usuario. Luego podría decirle a todos los que están debajo de él que se retiren de él en sus ui-latest ramas de la ui-latest o el nombre que les hayan dado, para que los desarrolladores los exploren. Si el equipo está contento, el líder de la interfaz de usuario podría pedirle al conductor de la prueba que lo extraiga y fusione los cambios. Esto se propaga a todas las personas (posteriores al cambio) que lo prueben y envíen informes de errores, etc. Finalmente, si la función pasa las pruebas, etc., uno de los principales conductores técnicos podría fusionarlo con la copia de trabajo actual del programa, en cuyo momento Todos los cambios se propagan de nuevo hacia abajo. Y así.

No es una forma de trabajo "tradicional" y está diseñada para ser "dirigida por pares" en lugar de "jerárquica" como SVN / CVS. En esencia, todos tienen acceso comprometido, pero solo localmente. Es el acceso al repositorio y el repositorio que usted designa como el repositorio de lanzamiento que le permite usar la jerarquía.


La característica más preocupante que los nuevos desarrolladores de DVCS deben tener en cuenta es el proceso de publicación :

  • puede importar (buscar / extraer) cualquier repositorio remoto que necesite
  • puedes publicar (push) en cualquier repo (simple) que quieras

A partir de eso, puede respetar algunas reglas para facilitar sus preguntas:

Ahora:

Flujos de trabajo / modelos de ramificación :

Cada flujo de trabajo está ahí para admitir un proceso de administración de la versión , y eso se adapta a cada proyecto.
Lo que puedo agregar al flujo de trabajo que menciona es: cada desarrollador no debe crear una rama de características, solo una rama "dev actual", porque la verdad es que el desarrollador a menudo no sabe qué producirá exactamente su rama: una característica, varias (porque terminó siendo una característica demasiado compleja), ninguna (porque no estaba lista para el lanzamiento), otra característica (porque la original se había "transformado"), ...

Solo un "integrador" debe establecer sucursales de características oficiales en un repositorio "central", que luego los desarrolladores pueden buscar para reajustar / fusionar la parte de su trabajo que se ajuste a esa característica.

Fusionar vs rebasar (enredado vs historia secuencial) :

Me gusta la respuesta que menciona (" Descripción del flujo de trabajo para el uso de git para el desarrollo interno ")

Estoy buscando un flujo de trabajo natural :

para las correcciones, puede ayudar a asociar cada corrección con un ticket de un seguimiento de errores, lo que ayuda al desarrollador a recordar dónde (es decir, en qué rama, es decir, una rama dedicada "para reparaciones") debe realizar dichas modificaciones.
Luego, los ganchos pueden ayudar a proteger un repositorio central contra los empujes de las correcciones de errores no validadas o de las ramas desde las que no se deben enviar. (No hay una solución específica aquí, todo esto debe adaptarse a su entorno)

¿Cómo evitar la creación de conflictos de fusión (debido a cherry pick)?

Como lo indicó Jakub Narębski en su respuesta , la selección de cerezas debe reservarse para situaciones raras donde se requiera.
Si su configuración implica un montón de selección de cerezas (es decir, "no es raro"), entonces algo está apagado.

¿Aplicaría el mismo commit en revertir (cómo hacer esto?)

git revert debería ocuparse de eso, pero eso no es lo ideal.

¿Cómo descomponerse en ramas tópicas?

Siempre que una rama aún no haya sido empujada en todas partes, un desarrollador debe reorganizar su historial de confirmaciones (una vez que finalmente vea que el desarrollo toma una forma más definitiva y estable) en:

  • varias ramas si es necesario (una por clara característica identificada)
  • un conjunto coherente de confirmaciones dentro de una rama (consulte Recorte de registros de Git )

¿Procedimientos adecuados como revisión de código y graduación?

El repositorio de ramas de integración (en una integración dedicada) puede ayudar al desarrollador a:

  • volver a basar su desarrollo en la parte superior de esa rama de integración remota (pull --rebase)
  • resolver localmente
  • empujar el desarrollo a ese repo
  • Consulte con el integrador que no resulte en un desastre;)

Personalmente, trato de mantener solo el código listo para publicación en la rama maestra.

Cuando trabajo en una nueva característica o corrección de errores, lo hago en una rama. También hago pruebas de unidad en la rama. Si todo funciona bien, solo entonces fusiono / rebase de nuevo en master.

También trato de usar las convenciones comunes de nombres de rama, como:

  • corrección de errores / recursive_loop
  • bugfix / sql_timeout
  • feature / new_layout
  • feature / enhanced_search

Un modelo que he usado con buenos resultados es el siguiente:

Un repo "bendito" que todos empujan y tiran hacia / desde, básicamente una topología cliente-servidor.

No hay una rama maestra, por lo que ningún desarrollador puede insertar ningún código en "línea principal".

Todos los desarrollos suceden en ramas temáticas. Tenemos nombres de espacios de nombre para detectar fácilmente quién es el responsable: jn / newFeature o jn / issue-1234

También hay una asignación casi 1 a 1 entre las sucursales y las tarjetas kanban / scrum en la pizarra.

Para liberar una rama se empuja al repositorio bendecido y la tarjeta kanban se mueve para que esté lista para su revisión.

Luego, si la sucursal acepta la sucursal, es un candidato para un lanzamiento.

Un lanzamiento ocurre cuando un conjunto de ramas aceptadas se combinan y se etiquetan con un número de versión.

Al presionar la nueva etiqueta al repositorio bendecido, existe una nueva base posible para las nuevas funciones.

Para evitar conflictos de combinación, se solicita a los desarrolladores que actualicen (fusionen) sus sucursales inéditas a la última etiqueta de lanzamiento.