you - ¿Cómo se hace git bisect para ignorar las ramas fusionadas?
git-blame (9)
Es posible que pueda usar git bisect start --no-checkout
para evitar tener que pagar realmente la confirmación en el árbol de trabajo. Entonces sospecho que puede hacer que git checkout BISECT_HEAD
para confirmaciones que realmente desea probar (es decir, solo las confirmaciones de primer padre en la rama principal). No lo he intentado pero espero que funcione.
Soy consciente de que git bisect es consciente de las ramas por diseño, de modo que si entre una buena confirmación, G y un compromiso malo, B, se fusionó en una rama, también debe tener en cuenta esos cambios, ya que el error puede estar contenido en la rama.
En mi caso, tengo una dependencia como una rama secundaria y me uno a cambios en mi proyecto principal de vez en cuando. La dependencia se puede considerar una biblioteca que tiene una forma diferente de ejecución, diferentes sistemas de compilación, etc. de mi proyecto principal, pero aún quiero cambios recientes a través de fusiones a la rama principal.
El problema es que, mientras se bisecta en este escenario, terminas en commits no compilables en los commits de la dependencia.
Realmente solo quiero considerar cada fusión de rama como una única confirmación mientras hago la bisección.
Una solución que he encontrado hasta ahora es hacer una lista de confirmaciones válidas G ... B con git log --first-parent, y luego mientras bisecta, do git bisect skip si la confirmación actual no está en esa lista. Sin embargo, lleva mucho tiempo (muchos archivos para pagar / cambiar para cada salto).
Entonces, la pregunta es: ¿Hay alguna forma de hacerlo? ¿Padres primerizos con git bisect o proporcionar una lista de compromisos que considero válidos para evitar el control de sucursales que ya sé que no son compilables? ¿Cómo solo verificamos las confirmaciones marcadas con o en el diagrama?
G---o---o---o---o---o---o---B main project branch / / / x---x---x---x---x dependency / / x'' dependency project taskbranch
Editar : diagrama agregado para mayor claridad
La respuesta de Björn Steinbrink funciona muy bien, pero recientemente comenzó a imprimir esto:
git bisect skip $(comm -23 <(git rev-list G | sort) <(git rev-list --first-parent G | sort))
Aquí hay una versión más moderna de su solución que usa "git replace" en lugar de injertos:
hint: Support for /info/grafts is deprecated hint: and will be removed in a future Git version. hint: hint: Please use "git replace --convert-graft-file" hint: to convert the grafts into replace refs. hint: hint: Turn this message off by running hint: "git config advice.graftFileDeprecated false"
Desafortunadamente, es mucho más lento para grandes repositorios (alrededor de 3 minutos para 150k confirmaciones); git replace
aún no parece tener un modo bulk. Es posible que desee restringir la lista de revistas a solo las confirmaciones en el alcance de su bisectriz.
Para eliminar los reemplazos cuando haya terminado, puede rm .git/refs/replace/*
.
Pensé en una posible solución, pero todavía estoy esperando encontrar algo más elegante:
Marcar todos los segundos padres de todas las fusiones en la rama principal como bueno
Marcar todos los padres remotos de cada fusión como buenos considerará que todos los commits que les preceden son buenos (y, como tales, omitidos por bisect). Esta solución también debe ser lo suficientemente genérica como para manejar fusiones múltiples desde múltiples ramas, dejando solo las confirmaciones en la rama principal.
git rev-list --first-parent --merges --parents GOOD..BAD /
| sed ''s/^[^ ]/+ [^ ]/+ //'' /
| xargs git bisect good
(Reemplazar BIEN y MALO con las confirmaciones relevantes)
La expresión regular en sed elimina los primeros dos commits de cada línea; la fusión se compromete, y el primer padre, dejando al resto de los padres (generalmente solo el segundo).
Dado el historial establecido en la pregunta, ejecutar el oneliner le daría:
G---o---o---o---o---o---o---B main project branch / / / G---x---G---x---G dependency / / x'' dependency project taskbranch
Esto haría que la bisección atravesara solo las confirmaciones en la rama principal:
o---o---o---o---o---o
Si alguna de las ramas fusionadas son indirectamente la causa del problema, se descubrirá cuando pruebe la fusión de compromiso a través de bisección, lo que podría ser motivo para investigar más a fondo sobre esa rama.
Por lo tanto, la suposición de que el primer padre de una combinación de fusión siempre es la misma rama no siempre es correcta. Por ejemplo, si está desactivado en una rama de tema y fusiona el máster para actualizarlo (por lo tanto, para esta combinación de commit, el primer elemento primario es la rama de tema) y luego vuelve al tema maestro y fusiona el tema, obtiene una fusión de avance rápido, que solo mueve el maestro a la combinación de fusión que tuvo el primer padre como su rama de tema. Esto puede parecer artificial, pero en realidad es un flujo de trabajo bastante normal: siempre fusiono master en mi branch para que mi fusión de nuevo a master sea una combinación trivial (es decir, de capacidad de reenvío rápido) (Sorry James, siempre olvida volver a establecer la base) .
Hay una manera que he encontrado para ayudar a descubrir qué padre es su sucursal: la fusión compromete el comentario. De forma predeterminada, git compone un comentario de confirmación de fusión que indica qué rama se fusionó y usted puede usar esto para deducir qué padre es la rama que le interesa, siempre que la persona que realiza la combinación no sobrescriba este comentario de confirmación de fusión.
Así que probé esto y parece funcionar para mí. Escribí un script de Python para ayudar a hacer esto en github . Si ejecuta este script, intentará rastrear hacia atrás y seguir su bifurcación y emitir una lista de identificadores de commit que son las puntas de las ramas que se fusionan en su bifurcación. Con esta lista, puede darles a "giselar bien" y bisectar omitirá todas las confirmaciones en las ramas fusionadas de su bisección, logrando el resultado deseado.
Puede indicar a git-bisect que solo revise los primeros padres de las asignaciones de fusión ejecutando el siguiente comando:
git rev-list --first-parent --merges --parents HEAD | / while read COMMIT PARENT1 PARENT2; do git replace --graft $COMMIT $PARENT1; done
Puedes hacer que git trate tu historial como lineal usando injertos. Para linealizar todo el primer historial principal que puede usar:
git rev-list --first-parent --merges --parents HEAD | cut -d'' '' -f1,2 > .git/info/grafts
Solo deja caer el archivo de injertos cuando hayas terminado con la bisección.
Si el historial se ve así:
A - B - C - H - I - J - K - L / / D - E - F - G
donde L es malo, B es bueno, y desea ignorar la rama DEFG, y luego ejecutar
$ git bisect start $ git bisect skip $( git rev-list G ^C ) $ git bisect bad L $ git bisect good B
donde B, C, G y L son los respectivos shas, parece hacer lo que usted quiere.
Sin embargo, no veo un método de un solo paso, basado en su solución actual: git bisect skip puede tomar una lista de confirmaciones para omitir. git log branchname enumerará commits en branch branchname. Así que esto debería permitirle especificar la lista de confirmaciones.
Si su dependencia y su código principal viven en diferentes espacios del sistema de archivos, puede especificar las rutas para incluir con git bisect start. Dependiendo del diseño de tu código, esa puede ser la mejor opción. (¡Casi seguro es si tienes una lista de archivos que pueden contener el error!)
La página man tiene detalles; el ver también hay una lectura interesante, también.
He estado buscando algo como esto también. Hasta donde tengo es que git rev-list --bisect --first-parent
parece hacer lo que quieres, y los documentos para rev-list implican que la opción --bisect
es lo que bisect usa internamente-- pero git bisect
para agregar esa bandera a sus llamadas a rev-list parece menos trivial:
El comando bisect es implementado por un script de shell git-bisect, que a su vez usa un comando integrado bisect--helper
para hacer realmente la parte interesante ("computación, visualización y pago" dice el comentario ...), aparentemente basado en un montón de archivos de estado mágico en .git /. Y parece ser el comando rev-list que reutiliza el código de bisect - helper en lugar de revertirlo como es de esperar.
Por lo tanto, tendrías que extender el filtro de commit de bisect - helper para hacerlo, creo.
Como solución alternativa, algo como esto podría funcionar: después de que bisect verifique algo por usted, reinicie a uno diferente usando git rev-list --bisect --first-parent
, pruebe eso y git rev-list --bisect --first-parent
como bueno / malo / omitir y continúe desde ahí.