Flexible vs ramificación estática (Git vs Clearcase / Accurev)

Mi pregunta es sobre la forma en que Git maneja las twigs: cada vez que se ramifica desde una confirmación, esta twig no recibirá cambios de la twig principal a less que la fuerce con una combinación.

Pero en otros sistemas como Clearcase o Accurev, puedes especificar cómo se completan las twigs con algún tipo de mecanismo de inheritance : quiero decir, con Clearcase, usando config_spec, puedes decir "get todos los files modificados en branch / main / issue001 y luego continúe con los que están en / main o con esta línea base específica ".

En Accurev también tiene un mecanismo similar que permite a las transmisiones recibir cambios desde las twigs superiores (transmite como los llaman) sin fusionar o crear una nueva confirmación en la twig.

¿No te pierdes esto mientras usas Git? ¿Puedes enumerar escenarios donde esta inheritance es imprescindible?

Gracias

Actualización Lea la respuesta de VonC a continuación para enfocar realmente mi pregunta. Una vez que aceptamos el "almacenamiento lineal" y los SCM basados ​​en DAG tienen capacidades diferentes, mi pregunta es: ¿ cuáles son los escenarios de la vida real (especialmente para las empresas más que OSS) donde el lineal puede hacer cosas que no son posibles para DAG? ¿Valen la pena?

Para entender por qué Git no ofrece ningún tipo de lo que se refiere como un "mecanismo de inheritance" (que no involucra un compromiso), primero debe comprender uno de los conceptos básicos de esos SCM (por ejemplo, Git vs. ClearCase)

  • ClearCase utiliza un almacenamiento de versión lineal : cada versión de un elemento (file o directory) está vinculada en una relación lineal directa con la versión anterior del mismo elemento.

  • Git utiliza un gráfico acíclico dirigido por DAG : cada "versión" de un file es en realidad parte de un set global de cambios en un tree que es en sí mismo parte de una confirmación. La versión anterior de eso se debe encontrar en una confirmación previa, accesible a través de una única ruta de gráfico acíclico dirigida.

En un sistema lineal, una especificación de configuration puede especificar varias reglas para lograr la "inheritance" que ve (para un file dado, primero select una determinada versión, y si no está presente, luego select otra versión, y si no está presente, select una tercero, y así sucesivamente).

La twig es una bifurcación en una historia lineal , una versión dada para una determinada regla de selección (todas las otras reglas de selección anteriores a esa todavía se aplican, de ahí el efecto de "inheritance")

En un DAG, un compromiso representa toda la "inheritance" que obtendrá alguna vez; no hay una selección "acumulativa" de versiones. Solo hay una ruta en este gráfico para seleccionar todos los files que verá en este punto exacto (commit).
Una twig es solo una nueva ruta en este gráfico.

Para aplicar, en Git, algunas otras versiones, debe hacer lo siguiente:

  • fusionar en su twig algún otro compromiso (como en el git pull "mencionado por la respuesta de stsquad ) o
  • rebase su twig (como Greg menciona )

Pero dado que Git es un SCM basado en DAG, siempre dará como resultado un nuevo compromiso.

Lo que estás "perdiendo" con Git es algún tipo de "composition" (cuando estás seleccionando diferentes versiones con diferentes reglas de selección sucesivas), pero eso no sería práctico en un D VCS (como en "Distribuido"): cuando estás hacer una sucursal con Git, necesita hacerlo con un punto de partida y un contenido claramente definido y fácilmente replicado en otros repositorys.

En un VCS puramente central, puede definir su espacio de trabajo (en ClearCase, su "vista", ya sea instantánea o dinámica) con las reglas que desee.


unknown-google agrega en el comentario (y en su pregunta anterior):

Entonces, una vez que vemos que los dos models pueden lograr cosas diferentes (lineal frente a DAG), mi pregunta es: ¿cuáles son los escenarios de la vida real (especialmente para las empresas más que OSS) donde lineal puede hacer cosas que no son posibles para DAG? ¿Lo valen?

Cuando se trata de un "escenario de la vida real" en términos de reglas de selección, lo que puede hacer en un model lineal es tener varias reglas de selección para el mismo set de files .

Considere esta "especificación de configuration" (es decir, "especificación de configuration" para las reglas de selección con ClearCase):

element /aPath/... aLabel3 -mkbranch myNewBranch element /aPath/... aLabel2 -mkbranch myNewBranch 

Selecciona todos los files labeldos como ' aLabel2 ' (y bifurcación desde allí), excepto aquellos labeldos como ' aLabel3 ' – y bifurcación desde allí – (porque esa regla precede a la que menciona ' aLabel2 ').

¿Vale la pena?

No.

En realidad, el sabor UCM de ClearCase (la metodología de " Administración de configuration unificada " incluida con el producto ClearCase y que representa todas las "mejores prácticas" deducidas del uso básico de ClearCase) no lo permite, por razones de simplificación . Un set de files se denomina "componente", y si desea realizar una bifurcación para una determinada label (conocida como "línea de base"), eso se traduciría de la siguiente manera:

 element /aPath/... .../myNewBranch element /aPath/... aLabel3 -mkbranch myNewBranch element /aPath/... /main/0 -mkbranch myNewBranch 

Debes elegir un punto de inicio (aquí, ' aLabel3 ') e ir desde allí. Si también desea los files de ' aLabel2 ', realizará una combinación de todos los files ' aLabel2 ' con los de 'myNewBranch'.

Esa es una "simplificación" que no tiene que hacer con un DAG, donde cada nodo del gráfico representa un "punto de partida" definido exclusivamente para una sucursal, cualquiera que sea el set de files involucrados.

Merge y rebase son suficientes para combinar ese punto de partida con otras versiones de un set determinado de files, para lograr la "composition" deseada, mientras se mantiene esa historia particular aislada en una twig.

El objective general es razonar en "operaciones de control de versiones coherentes aplicadas a un componente coherente ". Un set "coherente" de files es uno en un estado coherente bien definido:

  • si está labeldo, todos sus files están labeldos
  • si está ramificado, todos sus files se ramificarán desde el mismo punto de partida único

Eso se hace fácilmente en un sistema DAG; puede ser más difícil en un sistema lineal (especialmente con "Base ClearCase" donde la "especificación de configuration" puede ser complicada), pero se aplica con la metodología UCM de esa misma herramienta de base lineal.

En lugar de lograr esa "composition" a través de un "truco de regla de selección privada" (con ClearCase, alguna order de regla seleccionada), lo logras solo con operaciones de VCS (rebase o merge), que dejan un rastro claro para todos (en oposition a una configuration espec privada para un desarrollador, o compartida entre algunos, pero no todos los desarrolladores). Nuevamente, impone un sentido de coinheritance , en oposition a una "flexibilidad dinámica", que puede tener dificultades para reproducirse más adelante .

Eso le permite abandonar el ámbito de VCS (Sistema de control de versiones) e ingresar al ámbito de SCM (Software Configuration Management) , que se ocupa principalmente de la " reproducibilidad ". Y eso (características de SCM) se puede lograr con un VCS basado en lineal o en un DAG.

Parece que lo que estás buscando podría ser git rebase . Al volver a basar una twig, se separa conceptualmente de su punto de ramificación original y se vuelve a conectar en otro punto. (En realidad, la rebase se implementa aplicando cada parche de la bifurcación en secuencia al nuevo punto de bifurcación, creando un nuevo set de parches.) En su ejemplo, puede volver a establecer una bifurcación de una bifurcación en la punta actual de una bifurcación superior, que esencialmente "henetworkingará" todos los cambios realizados en la otra twig.

No estoy totalmente seguro de lo que estás pidiendo, pero parece que la semántica de seguimiento de git es lo que quieres. Cuando se ramifica desde un origen, puede hacer algo como:

git -t -b my_branch origen / master

Y luego el futuro "git pull" s fusionará automáticamente origen / master en su twig de trabajo. A continuación, puede usar "git cherry -v origin / master" para ver cuál es la diferencia. Puede usar "git rebase" antes de publicar los cambios para limpiar el historial, pero no debe usar rebase una vez que su historial sea público (es decir, que otras personas sigan esa twig).

En cuanto al esquema de inheritance utilizado por accurev: los usuarios de GIT probablemente "obtendrán" todo cuando analicen git-flow (ver también: http://github.com/nvie/gitflow y http://jeffkreeftmeijer.com/ 2010 / why-arent-you-using-git-flow / )

Este model de ramificación GIT lo hace más o less (manualmente / con la ayuda de la herramienta git-flow) lo que accurev hace de manera automática y con gran soporte de GUI.

Entonces parece que GIT puede hacer lo que Accurev hace. Como en realidad nunca utilicé git / git-flow día a día, no puedo decir cómo funciona pero parece prometedor. (Menos soporte de GUI apropiado 🙂

Intentaré responderte la pregunta. (Debo decir aquí que no he usado GIT, solo leí al respecto, así que si algo que menciono a continuación es incorrecto, por favor corrígeme)

"¿Puedes enumerar escenarios donde esta inheritance es imprescindible?"

No diré que es obligatorio, ya que puede resolver un problema con la herramienta que tiene, y podría ser una solución válida para su entorno. Supongo que es más una cuestión de processs que la herramienta en sí misma. Asegurarse de que su process sea coherente y también le permita retroceder en el time para reproducir cualquier paso / estado intermedio es el objective, y lo mejor de todo es que la herramienta le permite ejecutar su process y SCMP de la forma más sencilla posible.

El único escenario que puedo ver es útil para tener este comportamiento de 'inheritance' y usar el poder de la especificación de configuration, es cuando quieres que tu set de cambios esté " aislado " asignado a una tarea (devtask, CR, SR o lo que sea el propósito / scope de su set de cambios)

Usar esta composition le permite tener su twig de desarrollo limpia y aún usar una combinación diferente (usando composition) del rest del código, y todavía tener solo lo que es relevante para la tarea aislada en una twig durante todo el ciclo de vida de la tarea, solo hasta la fase de integración.

Siendo purista teniendo que comprometer / fusionar / rebase solo para tener un "punto de partida definido", supongo que " contaminaría " tu sucursal y terminarás con tus cambios y otros cambios en tu set de sucursal / cambio.

¿Cuándo / dónde este aislamiento es útil? Los puntos siguientes solo pueden tener sentido en el context de las empresas que persiguen CMM y algunas certificaciones ISO, y pueden no ser de interés para otro tipo de empresas o OSS.

  • Al ser muy quisquilloso, es posible que desee contar con precisión las líneas de código (agregado / modificado / eliminado) del set de cambios correspondiente a un único desarrollador, que luego se utilizará como una input para las estimaciones de código y esfuerzo.

  • Puede ser más fácil revisar el código en diferentes etapas, teniendo solo su código en una sola twig (no pegado con otros cambios)

En grandes proyectos con varios equipos y más de 500 desarrolladores trabajando simultáneamente en el mismo código base (donde los treees charts de versiones de elementos individuales se ven como una maraña ennetworkingada con varias líneas de carga, una para cada cliente grande o una para cada tecnología) grandes configuraciones las especificaciones que usan una composition de varios grados de profundidad hacen que esta cantidad de personas trabaje a la perfección para adaptar el mismo producto / sistema (código base) a diferentes propósitos. Al usar esta especificación de configuration, dá dinámicamente a cada equipo o subgrupo, una visión diferente de lo que necesitan y de dónde necesitan ramificarse, (en cascada en varios casos) sin la necesidad de crear twigs intermedias de integración, o fusionar y reescalonar constantemente todo los bits con los que necesitas comenzar El código de la misma tarea / propósito era ramificarse de diferentes tags, pero tenía sentido. (Puede argumentar aquí la 'línea de reference conocida' como un principio de la SCM, pero las tags simples contempladas en un plan SCM escrito hicieron el trabajo). Debe ser posible resolver esto con GIT (supongo que de una manera no dinámica) pero encuentro realmente difícil de imaginar sin este comportamiento de 'inheritance'. Supongo que el punto mencionado por VonC "si está ramificado, todos sus files se ramificarán desde el mismo punto de partida único" se rompió aquí, pero además estaba bien documentado en el SCMP, recuerdo que había una fuerte razón comercial para hacerlo de esa manera.

Sí, la creación de estas especificaciones de configuration que mencioné anteriormente no era gratuita, al principio había 4-5 personas bien pagadas detrás del SCM pero luego se networkingujeron mediante scripts automatizados que le preguntaron qué deseaba en términos de tags / twigs / características y escribe la CS por ti.

La reproducibilidad aquí se logró simplemente guardando la especificación de configuration junto con la tarea en el sistema devTask, por lo que cada tarea se correlacionó con los requisitos y se mapeó con una especificación de configuration y un set de cambios (files de código, documentos de layout, documentos de testing etc)

Así que hasta aquí una conclusión aquí podría ser, solo si su proyecto es lo suficientemente grande / complicado (y puede pagar SC Managers a lo largo de la vida del proyecto :)) entonces solo comenzará a pensar si necesita el comportamiento de 'inheritance' o herramienta realmente versátil; de lo contrario, irá directamente a una herramienta que es gratuita y que ya se encargará de la coinheritance de su SCM … pero podría haber otros factores en la herramienta SCM que podrían hacer que se apegue a uno u otro. .read en ..

Algunas notas al margen, que podrían estar fuera del tema, pero supongo que en algunos casos como el mío deben tenerse en count.

Debo agregar aquí que usamos el "CC bueno" y no el UCM. Totalmente de acuerdo con VonC sobre una buena metodología que permite "guiar" la flexibilidad hacia una configuration más coherente . Lo bueno es que CC es bastante flexible y puedes encontrar (no sin cierto esfuerzo) una buena forma de tener algo coherente mientras que en otro SCM puedes tenerlo gratis. Pero por ejemplo aquí (y otros lugares en los que he trabajado con CC) para proyectos C / C ++ no podemos permitirnos el precio de no tener la function winkin (reutilizando los objects Derive), que networkinguce varias veces X el time de compilation. Se puede argumentar que tener un mejor layout, un código más desacoplado y optimizar los Makefiles puede networkingucir la necesidad de comstackr todo, pero hay casos en los que necesita comstackr toda la bestia muchas veces al día, y compartir el DO ahorra Montones de time / dinero. Donde estoy ahora tratamos de usar tanta herramienta gratuita como podamos, y creo que nos desharemos de CC si podemos encontrar una herramienta más barata o gratuita que implemente la function winkin .

Terminaré con algo que mencionó Paul, las diferentes herramientas son mejores que otras para diferentes propósitos, pero agregaré que se puede alejar de alguna limitación de la herramienta al tener un process coherente y sin escarificar la reproducibilidad, puntos key del SCM. Al final, supongo que la respuesta vale? depende de su "problema", el SDLC que está ejecutando, sus processs de SCM y si hay alguna característica adicional (como winkin) que pueda ser útil en su entorno.

mis 2 centavos

Dejando a un lado la teoría, he aquí una especie de práctica práctica sobre esto, desde mi punto de vista usando AccuRev en un entorno de producción comercial durante varios años: el model de inheritance funciona muy bien siempre que los flujos secundarios no se hayan separado demasiado de los antepasados todavía en desarrollo. Se descompone cuando las transmisiones henetworkingadas son demasiado diferentes.

La inheritance (versiones posteriores como hijos de anteriores) permite que los cambios en las streams ancestrales estén activos en secuencias secundarias sin que nadie haga nada (a less que se requiera una fusión, en cuyo caso se muestra una superposition profunda, lo que es bueno para poder ver )

Eso suena genial, y en la práctica lo es, cuando todas las secuencias involucradas son relativamente similares. Usamos ese model para hotfix y flujos de nivel de package de service por debajo de una versión de producción determinada. (En realidad, es un poco más complicado que eso para nosotros, pero esa es la idea general).

Las versiones de producción están en paralelo, sin inheritance, con esos hijos de hotfix y service pack debajo de cada uno de ellos. Comenzar una nueva versión significa crear una nueva transmisión a nivel de versión y empujar manualmente todo desde la secuencia de mantenimiento más reciente para la versión anterior. Después de eso, los cambios en las versiones anteriores que se aplican a los posteriores deben insertse manualmente en cada uno de ellos, lo que requiere más trabajo, pero permite un control mucho mayor.

Originalmente usamos el model de inheritance en todos los lanzamientos, donde los posteriores eran hijos de anteriores. Eso funcionó bien por un time, pero se volvió inmanejable con el time. Las principales diferencias arquitectónicas entre lanzamientos henetworkingadas inevitablemente cambian una mala idea. Sí, puede colocar una instantánea en el medio para bloquear la inheritance, pero luego todos los cambios deben realizarse manualmente, y la única diferencia real entre parent-snapshot-child y las secuencias paralelas no henetworkingables es que toda la vista de flujo gráfica continuamente empuja hacia abajo y a la derecha, que es un PITA.

Una cosa realmente buena de AccuRev es que tienes esta opción, todo el time. No es una restricción inherente de la architecture de su progtwig SCM.

¿Has notado que también puedes download versiones específicas de files con GIT?

Solo usa esto:

 git checkout [< tree-ish >] [--] < paths > 

Al igual que las especificaciones de configuration, cualquier versión existente de un file (routes) puede cargarse en el tree de trabajo. Cita de los documentos de git-checkout:

La siguiente secuencia verifica la twig principal, revierte el Makefile a dos revisiones, elimina hello.c por error y lo recupera del índice:

 $ git checkout master $ git checkout master~2 Makefile $ rm -f hello.c $ git checkout hello.c 

ClearCase, sin MultiSite, es un repository único, pero se distribuye Git. ClearCase se compromete a nivel de file, pero Git se compromete a nivel de repository. (Esta última diferencia significa que la pregunta original se basa en un malentendido, como se señala en las otras publicaciones aquí).

Si estas son las diferencias de las que estamos hablando, entonces creo que "lineal" versus "DAG" es una manera confusa de distinguir estos sistemas SCM. En ClearCase, todas las versiones de un file se conocen como la versión del file "tree", pero en realidad es un gráfico acíclico dirigido. La verdadera diferencia para Git es que los DAG de ClearCase existen por file. Por lo tanto, creo que es engañoso referirse a ClearCase como no DAG y a Git como DAG.

(BTW ClearCase versiona sus directorys de forma similar a sus files, pero esa es otra historia).

No estoy seguro de si está preguntando algo, pero está demostrando que las transmisiones de Accurev son herramientas diferentes a las de Git (o SVN). (No sé Clearcase.)

Por ejemplo, con Accurev se le obliga , como usted dice, a usar ciertos flujos de trabajo, lo que le da un historial auditable de cambios que no son compatibles con Git. La inheritance de Accurev hace que ciertos flujos de trabajo sean más eficientes y otros imposibles.

Con Git puede tener una encoding exploratoria segregada en repos locales o en twigs de características, que Accurev no admitiría muy bien.

Diferentes herramientas son buenas para diferentes propósitos; es útil preguntar para qué sirve cada uno.

Intereting Posts