El flujo de trabajo de Git para auditar confirmaciones sin reescribir el historial

Estoy trabajando con un desarrollador que es nuevo en git, y me gustaría configurar un flujo de trabajo de git que me permita auditar las confirmaciones realizadas por este desarrollador (y posiblemente rechazarlas) sin forzarlo a rebase su trabajo (que es propenso a errores) para nuevos usuarios).

Aquí está el escenario:

  • la twig master contiene solo código auditado
  • devel twig devel se crea bifurcando twig master
  • un desarrollador está trabajando en la twig de devel e impulsar su código para que yo audite
  • Detecto algunos problemas con su código, así que le pido que haga más commits en devel branch para solucionar el problema
  • Una vez que estoy contento con el código, selecciono (o me fusiono con squash) los desarrolladores se comprometen en la twig master , agregan mis propios comentarios y marcan la confirmación según el autor.
  • El desarrollador fusiona la twig master en su twig de devel

Aquí hay una ilustración visual de este escenario:

Escenario visual

Después de esta secuencia, ¿cómo puedo estar 100% seguro de que los errores cometidos por el desarrollador durante la secuencia "cometer errores / rehacer" no volverán a aparecer cuando el desarrollador presione su twig de devel nuevamente después de otros commits?

La mejor solución sería pedir al desarrollador que vuelva a establecer la base de su twig de devel frente a la master , pero esta es una tarea difícil para los nuevos usuarios de git.

Si este flujo de trabajo es incorrecto de alguna manera, sugiéreme otro en el que pueda auditar las confirmaciones antes de fusionarlas en la twig principal.

EDITAR

Un amigo me sugirió una dirección que parece prometedora: la opción –fixup al hacer commit.

--fixup=<commit>

Construya un post de compromiso para usar con rebase --autosquash . El post de confirmación será la línea de asunto de la confirmación especificada con un prefijo de "corrección". Ver git-rebase para más detalles.

Esta opción podría ser utilizada por el desarrollador para marcar correctamente su segundo y tercer commit como una solución para su primera. Una buena solución para explorar …

Observación 1: Al intentar convertir las confirmaciones separadas en devel en una única confirmación en el master , está reescribiendo el historial. Veo el punto en tratar de mantener una historia limpia y lineal en el master , sin embargo, una historia less lineal con fusiones se integraría más fácilmente con los commands básicos de git.

Observación 2: si su flujo de trabajo incluye explícitamente a miembros que no están familiarizados con las herramientas básicas que utiliza para compartir el código, debe vivir con las consecuencias. En algún momento, creo que el desarrollador debería aprender git.

Aquí hay dos sugerencias:

  1. Coloque el historial lineal en el maestro y "valide" los cambios ejecutando, desde el maestro:

     git merge --no-ff devel 

    Esta es la forma más directa de informar a git que las modificaciones en el devel se tienen en count en el master .

  2. Haz la fusión con tu propio desarrollo y haz que tu desarrollador elimine las modificaciones de origin/devel .
    Si la única confirmación en el maestro realmente solo consiste en aplastar las confirmaciones en devel , esto no debería desencadenar ningún conflicto: la combinación de commit master -> devel debería introducir 0 modificaciones.
    Si realmente has modificado la confirmación aplastada, y el desarrollador puede tener modificaciones locales propias, tienes que enfrentar la posibilidad de desencadenar conflictos de su lado de todos modos …

Si vas a aplastar la twig de desarrollo en lugar de fusionarla normalmente, no es una buena idea fusionar ese compromiso aplastado en la twig de desarrollo, porque entonces tendrás un montón de conflictos confusos, porque git te cree Estamos aplicando un nuevo código, cuando en realidad es el mismo código.

Sería mejor simplemente hacer una simple combinación en master , luego una simple fusión de nuevo en devel , o bien descartar la twig de devel y hacer una nueva de la confirmación más reciente de master . Siempre que el código que se combina con el master sea ​​"bueno", según usted, entonces probablemente no obtendrá ninguna regresión.

Por otro lado, si vas con tu plan original de fusionar en commits aplastados de nuevo en devel , eso boostá tus posibilidades de que ocurra una regresión, debido a los confusos conflictos.

Actualizar

Borré partes de mi respuesta anterior porque en realidad solo probé haciendo squash commit en master y luego inmediatamente lo fundí de nuevo en devel , y no causó ningún conflicto, por lo que parte de mi respuesta fue incorrecta.

Convertí esto en una wiki de la comunidad porque todavía contiene mucha información sobre el problema en los comentarios.

Solo usa Gerrit. Con gerrit, tendrá el historial de sus comentarios, confirmaciones, etc. También puede abandonar el cambio. El flujo de trabajo que uso como desarrollador:

Preparar

Copie el enlace gerrit commit-message en su repo/.git/hooks . Asegúrese de que sea ejecutable y no contenga crlf.

Haga una revisión remota para presionar, o mejor alias de shell si trabaja con * nix.

Cree un alias para rebasar en ~ / .gitconfig (sobre el punto de horquilla )

 [alias] reb = !"git rebase -i $(git merge-base --fork-point origin/master HEAD)" 

Flujo de trabajo

 while unapproved do git commit -a --amend git push review # reviewers comment, reject, approve etc. # If rejected, I change commit as requinetworking, then end 

Aplastamiento

Al presionar a gerrit debería haber (probablemente) solo una confirmación.

Entonces squash se compromete en su twig en una sola:

 git reb 

El editor se abrirá. Cambia la pick a squash para cada línea, excepto la primera (commit más antiguo). Guardar y Salir. El editor se abrirá con posts de confirmación. Elimine todo excepto el post de confirmación más antiguo y la línea con Commit-ID (se necesita para gerrit).

Rebase

Si fusionar su twig falla en gerrit, puede volver a basarlo en origen / maestro

 git rebase origin/master 

Si hay muchos conflictos, puede evitar el dolor de resolver muchos de ellos simplemente usando cherry-pick

 git checkout -b topic2 origin/master git cherry-pick topic git branch -D topic git branch -m topic 

git review

También puedes usar git review para simplificar algunas operaciones cuando trabajas con gerrit.

Si se asegura de que su otro desarrollador siempre crea cambios desde una determinada twig, digamos desarrollar, puede tener la configuration de la twig principal que siempre existe, por ejemplo:

maestro, desarrollar

Si su desarrollador solo crea twigs de características desde la twig de desarrollo, puede crear commits todo lo que quiera. Luego, cuando piense que está listo, puede seleccionar / volver a clasificar según el tamaño y hacer lo suyo con él. La twig de características se elimina, asegurándose de que el historial reescrito desaparezca.

Todo lo que su desarrollador debe recordar es crear una sucursal desde la sucursal de desarrollo remoto cada vez que quiera iniciar una nueva function y no tocar su twig de características local cuando diga que va a fusionar algunas cosas en su desarrollo.

Luego, cuando esté listo, borrará su twig myfeature localmente y la eliminará remotamente cuando haya fusionado / reorientado / seleccionado sus buenos cambios en su desarrollo.

Solo los buenos compromisos entran en la twig de desarrollo. Tu desarrollador crea una nueva twig desde el desarrollo como antes.

Creo que algunas ramificaciones básicas son lo mínimo que tu desarrollador debería saber. Si no puede volver a clasificar / limpiar su sucursal / commits, creo que debe aceptar seguir cierto flujo de trabajo.

Tal vez no es perfecto, pero tal vez un posible flujo de trabajo, no obstante. Espero eso ayude.

La forma más fácil con la menor cantidad de alboroto sería fusionarse en los cambios de la twig de desarrollo en maestro. Solo necesita actualizar regularmente la twig con el maestro para que sus twigs no diverjan demasiado (dependiendo de qué funciones estén trabajando otras personas).

Si desea tener una sola confirmación para la modificación en el maestro. Puede volver a establecer la base de los commits de los desarrolladores en una sola confirmación y luego seleccionar de forma precisa esa confirmación en el maestro. Esto daría lugar a complicaciones ya que solo podría hacer git push -f para actualizar la twig de devel remoto y si su desarrollador no está familiarizado con git sería complicado actualizar su twig de devel . O requeriría que eliminen esa twig y luego usen una nueva twig para cualquier trabajo futuro.

Tendrá que decidir qué opción seguir dependiendo de si desea que todos los commits de su desarrollador aparezcan en el logging. La forma más fácil y less problemática es simplemente fusionar desarrollo y maestro.

Probaré el siguiente flujo de trabajo y le diré si las cosas van bien.

Requisitos previos

  • el desarrollador debe poder comprometerse desde la línea de command
  • el desarrollador siempre debe permanecer en la misma twig, de modo que no tenga que preocuparse por qué twig está actualmente desprotegida
  • desarrollador nunca debe tener que resolver conflictos que afectan el código que no tiene escrito
  • desarrollador nunca estará en una situación donde podría perder modificaciones locales a su tree de trabajo

Herramientas

git commit con la opción –fixup :

--fixup=<commit>

Construya un post de compromiso para usar con rebase --autosquash . El post de confirmación será la línea de asunto de la confirmación especificada con un prefijo de "corrección".

git rebase con –autosquash, –autostash y –interactive options

--interactive

Haga una list de los commits que están a punto de ser actualizados. Permita que el usuario edite esa list antes de volver a basarla. Este modo también se puede usar para dividir confirmaciones.

--autosquash

Cuando el post de logging de compromiso comienza con "squash! …" (o "fixup! …"), y hay un commit cuyo título comienza con el mismo …, modifica automáticamente la list de tareas de rebase -i para que la confirmación marcada para aplastar viene justo después del compromiso para ser modificado, y cambia la acción de la confirmación movida de pick a squash (o fixup ). Ignora la subsiguiente "corrección" o "¡aplastar!" Después de la primera, en caso de que hayas hecho reference a una corrección / squash anterior con git commit --fixup/--squash .

Esta opción solo es válida cuando se usa la opción interactiva .

Si la opción –autosquash está habilitada de forma pnetworkingeterminada utilizando la variable de configuration rebase.autosquash , esta opción se puede utilizar para anular y deshabilitar esta configuration.

--autostash

Cree automáticamente un alijo temporal antes de que comience la operación, y aplíquelo después de que finalice la operación. Esto significa que puede ejecutar rebase en un tree de trabajo sucio. Sin embargo, úselo con cuidado: la aplicación definitiva de ocultación después de una rebase exitosa puede resultar en conflictos no triviales.

Flujo de trabajo

  1. El desarrollador bifurca la twig master en una twig de devel . El punto de la horquilla está marcado con una label (por ejemplo, version_1.1 )
  2. El desarrollador trabaja y se compromete en la twig de devel . Cuando el trabajo está terminado, él empuja su twig en el repository remoto para que el auditor pueda verlo y validarlo.
  3. El auditor busca la twig de devel y mira el código. Si algo no es correcto, le pide al desarrollador que haga algunas modificaciones.
  4. Para cada modificación realizada por el desarrollador, se debe usar el siguiente command para confirmar la corrección: git commit --fixup <commit that was not OK> . Que la twig se empuja de nuevo.
  5. Una vez que el auditor esté contento con las modificaciones realizadas, el desarrollador debe volver a establecer una base en su sucursal para aplastar todas las confirmaciones de corrección en una confirmación hermosa y libre de errores (mientras tanto, podrían haberse comprometido otros trabajos no relacionados).

GIT_EDITOR=: git rebase tags/version_1.1 --interactive --autosquash --autostash .

El GIT_EDITOR=: está aquí para evitar mostrar el editor que presenta las lists de compromisos debido a la opción --interactive . Esta opción es necesaria para hacer que la fixup reordere automáticamente.

El último paso es empujar la twig de devel nuevamente (con la opción --force ) para que el auditor pueda fusionarla en la twig master . La base de rebase para la siguiente corrección de desarrollo podría ser la twig principal o una nueva label que el desarrollador puso en su twig de desarrollo después de fusionar la twig principal.

Aquí está el tree git resultante:

Ejemplo de gitk del flujo de trabajo de reparación

Bueno, si tiene un desarrollador principiante y usted es el único revisor, le sugiero este flujo de trabajo:

  1. el desarrollador crea una twig local desde el maestro para implementar alguna característica (nombre de la sucursal: i-123)
  2. el desarrollador agrega un código a la twig i-123
  3. el desarrollador crea la request de fusión para fusionar i-123 en la twig principal
  4. el revisor encuentra un error y notifica el problema al desarrollador
  5. el desarrollador agregar se compromete a resolver el problema y notifica al revisor para verificar el cambio de la twig i-123
  6. el revisor verifica el código fuente y acepta la request de combinación (fusionar i-123 en la twig principal ya que se destruyó el resultado i-123)
  7. el desarrollador sincroniza el repository local (como resultado: la twig principal contiene cambios relativos a i-123 y se destruyó i-123)
  8. el desarrollador puede continuar con el paso 1

Este enfoque permite que un desarrollador trabaje en una o varias características al mismo time, y elimina la complicada lógica sobre mantener actualizada la twig de desarrollo. Es un enfoque fácil para el desarrollador principiante.