git encuentra todas las asignaciones no fusionadas en el maestro agrupadas por las twigs en las que se crearon

Tengo que crear una revisión del código de las twigs no fusionadas.

Nota al margen: al encontrar soluciones, no vayamos al problema del context de la sucursal local, ya que esto se ejecutará en un server, solo habrá un origen remoto, siempre ejecutaré un command de origen de búsqueda de git antes de otros commands y cuando hablemos sobre twigs, nos referiremos al origen / nombre-twig .
Nota al margen 2: Tengo buen conocimiento de cómo funciona git tanto en porcelana como en fontanería.

Si la configuration fuera simple y cada twig que se originó desde el maestro continuaría en su propio path, podríamos simplemente ejecutar:

git rev-list origin/branch-name --not origin/master --no-merges 

para cada twig no fusionada y agregue las confirmaciones resultantes a cada revisión por twig.

El problema surge cuando hay una fusión entre 2-3 twigs y el trabajo continuo en algunas de ellas. Como dije, para cada sucursal quiero crear revisiones programáticas programáticas y no quiero include una confirmación en múltiples revisiones.
Principalmente los problemas se networkingucen al encontrar la twig original para cada compromiso.
O para simplificar … encontrar todas las asignaciones no fusionadas agrupadas por la twig en la que probablemente fueron creadas.

Centrémonos en un simple ejemplo:

  - * b4 - branch2's head * | a4 - branch1's head | * b3 * | merge branch2 into branch1 * |\ | m3 - master's head | * \| a3 | | | | | * b2 | * | merge master into branch1 * /| | m2 |/ | * merge branch1 into branch2 | * /| a2 | |/ | | | * b1 | | / | |/ | /| |/ | | * a1 * / m1 |/ | * start - 

y lo que quiero get es:

  • branch1: a1, a2, a3, a4
  • branch2: b1, b2, b3, b4

La mejor solución que he encontrado hasta ahora es ejecutar:

 git show-branch --topo-order --topics origin/master origin/branch1 origin/branch2 

y analizar el resultado:

 * [master] m3 ! [branch1] a4 ! [branch2] b4 --- + [branch2] b4 + [branch2^] b3 + [branch1] a4 ++ [branch2~2] b2 -- [branch2~3] Merge branch 'branch1' into branch2 ++ [branch2~4] b1 + [branch1~2] a3 + [branch1~4] a2 ++ [branch1~5] a1 *++ [branch2~5] m1 

La interpretación de salida es así:

  1. Las primeras n líneas son las n twigs analizadas
  2. una línea con —-
  3. una línea para cada commit con un más (o less en caso de commit de fusión) en el n-ésimo carácter de sangría si ese commit está en la n-ésima sucursal.
  4. la última línea es la base de combinación para todas las twigs analizadas

Para el punto 3. la resolución del nombre de confirmación comienza con un nombre de twig y, a partir de lo que veo, esta twig corresponde a la confirmación de la twig en la que se creó, probablemente al promover la ruta que llega al primer padre.
Como no estoy interesado en fusionar compromisos, los ignoraré.
Luego analizaré cada branch-path-commit para get su hash con rev-parse.

¿Alguien tiene alguna idea programática mejor para resolver esto?

El repository se puede clonar con --mirror que crea un repository vacío que se puede usar como un espejo del repository original y se puede actualizar con git remote update --prune después de lo cual todas las tags se deben eliminar para esta function.

Lo implemento de esta manera:
1. get una list de twigs no fusionadas en el maestro

 git branch --no-merged master 

2. para cada twig, obtenga una list de revisiones en esa twig y no en la twig principal

 git rev-list branch1 --not master --no-merges 

Si la list está vacía, elimine la twig de la list de twigs
3. Para cada revisión, determine la twig original con

 git name-rev --name-only revisionHash1 

y coincide con la expresión regular para ^([^\~\^]*)([\~\^].*)?$ . El primer patrón es el nombre de la twig, el segundo es la ruta relativa a la twig.
Si el nombre de la twig encontrada no es igual a la twig inicial, elimine la revisión de la list.

Al final obtuve una list de twigs y para cada una de ellas una list de confirmaciones.


Después de investigar un poco más, se puede hacer todo en una sola línea con:

 git rev-list --all --not master --no-merges | xargs -L1 git name-rev | grep -oE '[0-9a-f]{40}\s[^\~\^]*' 

El resultado es un resultado en forma

 hash branch 

que se puede leer, analizar, orderar, agrupar o lo que sea.

Si capto su espacio problemático, creo que puede usar –sha1-name

git show-branch –topo-order –topics –sha1-name origen / master origin / branch1 origin / branch2

para enumerar lo que le interesa, luego ejecute los commits a través de git-what-branch

git-what-branch : Descubre en qué twig está una confirmación, o cómo llegó a una twig con nombre. Este es un script Perl de Seth Robertson

y formatee el informe según sus necesidades?

No hay una respuesta correcta a esta pregunta porque está poco especificada.

La historia de Git es simplemente un gráfico acíclico dirigido (DAG), y en general es imposible determinar las relaciones semánticas entre dos nodos arbitrarios en un DAG a less que los nodos estén suficientemente labeldos. A less que pueda garantizar que los posts de confirmación en su gráfico de ejemplo siguen un patrón confiable, que puede analizarse por máquina, las confirmaciones no están suficientemente labeldas; es imposible identificar automáticamente las confirmaciones que le interesan sin context adicional (por ejemplo, garantías que sus desarrolladores siguen ciertas mejores prácticas).

Aquí hay un ejemplo de lo que quiero decir. Usted dice que commit a1 está asociado con branch1 , pero esto no puede determinarse con certeza simplemente mirando los nodos de su gráfico de ejemplo. Es posible que alguna vez tu historial de repositorys de ejemplo fuera así:

  * merge branch1 into branch2 - branch2's head |\ _|/ / * b1 | | | | _|_/ / | | * a1 * / m1 |/ | * start - master's head 

Tenga en count que branch1 ni siquiera existe en el gráfico anterior. El gráfico anterior podría haber surgido de la siguiente secuencia de events:

  1. branch2 se crea al start en el repository compartido
  2. el usuario # 1 crea a1 en su twig branch2 local
  3. Mientras tanto, el usuario # 2 crea m1 y b1 en su twig branch2 local
  4. el usuario # 1 presiona su twig branch2 local en el repository compartido, lo que hace que la reference de branch2 en el repository compartido apunte a a1
  5. el usuario n. ° 2 intenta enviar su sucursal branch2 local al repository compartido, pero esto falla con un error de avance rápido ( branch2 actualmente apunta a a1 y no se puede reenviar rápidamente a b1 )
  6. el usuario # 2 ejecuta git pull , fusionando a1 en b1
  7. usuario # 2 ejecuta git commit --amend -m "merge branch1 into branch2" por alguna razón inexplicable
  8. el usuario # 2 presiona, y el historial del repository compartido termina pareciéndose al DAG anterior

Algún time después, el usuario n. ° 1 crea branch1 fuera de a1 y crea a2 , mientras que el usuario n. ° 2 de avance rápido fusiona m1 en master , lo que da como resultado el siguiente historial de confirmaciones:

  * merge a1 into b1 - branch2's head * |\ a2 - branch1's head | _|/ |/ * b1 | | | | _|_/ / | | * a1 * / m1 - master's head |/ | * start 

Dado que esta secuencia de events es técnicamente posible (aunque poco probable), ¿cómo puede un humano dejar que Git le diga cuál se compromete a "pertenecer" a qué twig?

Analizar los posts de Commit Merge

Si puede garantizar que los usuarios no cambien los posts de confirmación de fusión (siempre aceptan el valor pnetworkingeterminado de Git), y que Git nunca y nunca cambiará el formatting de post de confirmación de combinación pnetworkingeterminada, entonces el post de confirmación de la fusión se puede usar como pista que a1 comenzó en branch1 . Tendrá que escribir una secuencia de commands para analizar los posts de confirmación; no hay simples lineamientos de Git para hacer esto por usted.

Si las fusiones son siempre intencionales

Alternativamente, si tus desarrolladores siguen las mejores prácticas (cada fusión es intencional y está destinada a include una twig de nombre diferente, lo que da como resultado un repository sin esas estúpidas confusiones de fusión creadas por git pull ), y no estás interesado en las confirmaciones de un sucursal hija completa, entonces las confirmaciones que le interesan están en la ruta del primer padre. Si sabe qué sucursal es el padre de la sucursal que está parsing, puede hacer lo siguiente:

 git rev-list --first-parent --no-merges parent-branch-ref..branch-ref 

Este command enumera los identificadores SHA1 para las confirmaciones a las que se puede acceder desde branch-ref excluyendo las confirmaciones accesibles desde parent-branch-ref y las confirmaciones que se combinaron desde las twigs secundarias.

En el gráfico de ejemplo anterior, suponiendo que el order principal está determinado por sus annotations y no por el order de las líneas que entran en un compromiso de fusión, git rev-list --first-parent --no-merges master..branch1 imprimiría el SHA1 identificadores para commits a4, a3, a2 y a1 (en ese order; use --reverse si quiere el order opuesto), y git rev-list --first-parent --no-merges master..branch2 imprimiría el Identificadores SHA1 para confirmaciones b4, b3, b2 y b1 (nuevamente, en ese order).

Si las sucursales tienen claras relaciones entre padres e hijos

Si tus desarrolladores no siguen las mejores prácticas y tus sucursales están llenas de esas estúpidas fusiones creadas por git pull (u otra operación equivalente), pero tienes claras las relaciones entre padres e hijos, entonces escribir un script para ejecutar el siguiente algorithm puede funcionar para tú:

  1. Encuentre todas las confirmaciones accesibles desde la twig de interés, excluyendo todas las confirmaciones de su sucursal principal, la sucursal principal de sus padres, la sucursal principal de sus padres, etc., y guarde los resultados. Por ejemplo:

     git rev-list master..branch1 >commit-list 
  2. Haga lo mismo para todas las twigs de niños, nietos, etc. de la twig de interés. Por ejemplo, suponiendo que branch2 se considera hijo de branch1 :

     git rev-list ^master ^branch1 branch2 >commits-to-filter-out 
  3. Filtra los resultados del paso # 2 de los resultados del paso # 1. Por ejemplo:

     grep -Fv -f commits-to-filter-out commit-list 

El problema con este enfoque es que una vez que una sucursal hija se fusiona con su principal, se considera que esas confirmaciones son parte del padre, incluso si el desarrollo en la sucursal de hijo continúa. Aunque esto tiene sentido semánticamente, no produce el resultado que usted dice que quiere.

Algunas mejores prácticas

Estas son algunas de las mejores prácticas para hacer que este problema en particular sea más fácil de resolver en el futuro. La mayoría, si no todos, se pueden aplicar a través del uso inteligente de los ganchos en el repository compartido.

  1. Solo una tarea por twig. Múltiples tareas están prohibidas.
  2. NUNCA permita que el desarrollo continúe en una sucursal secundaria una vez que se haya fusionado con su padre. La fusión implica que se realiza una tarea, final de la historia. Respuestas a preguntas anticipadas:
    • P: ¿Qué sucede si descubro un error en la twig hija? R: Comience una nueva twig fuera del padre. NO continúe con el desarrollo en la twig hija.
    • P: ¿Qué pasa si la nueva característica aún no está list? A: ¿Entonces por qué fusionaste la sucursal? Quizás fusionaste una subtarea completa; si es así, las subtareas restantes deben ir en sus propias twigs fuera de la twig padre. NO continúe con el desarrollo en la twig hija.
  3. Prohibir el uso de git pull
  4. Una twig hija no debe fusionarse con su padre a less que todas sus twigs secundarias se hayan fusionado en ella.
  5. Si la twig no tiene twigs secundarias, considere volver a basarla en la twig padre antes de fusionarse con --no-ff . Si tiene twigs secundarias, aún puede volver a establecer la base, pero conserve las fusiones --no-ff de las twigs secundarias (esto es más complicado de lo que debería ser).
  6. Combine la twig principal en la twig secundaria con frecuencia para facilitar la resolución de los conflictos de combinación.
  7. Evite fusionar una sucursal de abuelos directamente en su sucursal de nieto: primero fusione al niño y luego combine al menor con el nieto.

Si todos tus desarrolladores siguen estas reglas, entonces un simple:

 git rev-list --first-parent --no-merges parent-branch..child-branch 

es todo lo que necesita para ver las confirmaciones que se realizaron en esa twig less los compromisos realizados en las twigs de sus hijos.

Sugeriría hacerlo de la manera en que lo describiste. Pero trabajaría en la salida de git log --format="%H:%P:%s" ^origin/master origin/branch1 origin/branch2 , por lo que puede hacer mejor andar en tree.

  1. Construya una estructura de tree adecuada a partir de la salida, marcando padres e hijos.
  2. Comience a caminar desde las cabezas (obtenga sus SHA de git rev-parse ). Marque cada compromiso con los nombres de la cabeza de donde vino y su distancia.
    • Para los pasos que no son del primer padre (la otra parte de la fusión), agregaría 100 a la distancia.
    • Si cumple un compromiso de fusión, verifique qué dice sobre qué twig se fusionó. Utilice esta información cuando siga los dos enlaces principales: si el nombre analizado de la twig que va a no coincide con su HEAD actual, agregue 10000 a la distancia.
    • Para ambos padres: ahora sabes su nombre. Agregue a todos sus hijos que son primogénitos a un dict: commit -> known-name .
  3. Tome su dict de commits de nombre conocido y comience a caminar por el tree (hacia los niños, no hacia los padres). Restar 10000 de la distancia de la twig fusionada. Al hacer esto, camine para no comprometerse a no ser el primer padre y detenerse tan pronto como llegue a un punto de ramificación (un compromiso que tiene dos hijos). También pare si golpea una de sus cabezas de twig.

Ahora, para cada una de sus confirmaciones, tendrá una list de valores de distancia (que podrían ser negativos) para las cabezas de sucursal. Para cada compromiso, la twig con la menor distancia es en la que probablemente se creó el compromiso.

Si tiene time, es posible que desee recorrer toda la historia y luego restar la historia de la maestría, que podría dar resultados ligeramente mejores si sus twigs se han fusionado en el maestro antes.


No pude resistir: hice un script de Python que hace lo que describí. Pero con un cambio: con cada paso normal, la distancia no aumenta, sino que disminuye. Esto tiene el efecto de que las twigs que vivieron más time después de un punto de fusión son preferidas, lo que personalmente me gusta más. Aquí está: https://gist.github.com/Chronial/5275577

Uso: simplemente ejecute git-annotate-log.py ^origin/master origin/branch1 origin/branch2 verifique la calidad de los resultados (generará un tree de logging git con annotations).