¿Por qué todos los repositorios serios de Github que realizo solicitan quieren que reduzca mis confirmaciones en una única confirmación?
Pensé que el registro de git estaba allí para que pudieras inspeccionar todo tu historial y ver exactamente qué cambios ocurrieron dónde, pero aplastarlo lo saca del historial y lo agrupa todo en una confirmación. ¿Cual es el punto?
Esto también parece ir en contra del mantra "comprometerse temprano y comprometerse con frecuencia".
Respuestas:
Para que tenga un historial de git claro y conciso que documente clara y fácilmente los cambios realizados y los motivos.
Por ejemplo, un registro de git típico 'sin aplastar' para mí podría tener el siguiente aspecto:
¡Que desastre!
Mientras que un registro de git más cuidadosamente administrado y fusionado con un pequeño enfoque adicional en los mensajes para esto podría verse así:
Creo que puede ver el punto de aplastar los compromisos en general y el mismo principio se aplica a las solicitudes de extracción: legibilidad de la historia. También puede estar agregando a un registro de confirmación que ya tiene cientos o incluso miles de confirmaciones y esto ayudará a mantener la historia cada vez más breve y concisa.
Desea comprometerse temprano y con frecuencia. Es una mejor práctica por muchas razones. Encuentro que esto me lleva a tener compromisos frecuentes que son "wip" (trabajo en progreso) o "parte A hecho" o "error tipográfico, corrección menor" donde estoy usando git para ayudarme a trabajar y darme puntos de trabajo que Puedo volver a si el siguiente código no funciona a medida que progreso para que las cosas funcionen. Sin embargo, no necesito ni quiero ese historial como parte del historial final de git, por lo que puedo aplastar mis commits, pero vea las notas a continuación sobre lo que esto significa en una rama de desarrollo frente a master.
Si hay hitos importantes que representan distintas etapas de trabajo, todavía está bien tener más de una confirmación por función / tarea / error. Sin embargo, esto a menudo puede resaltar el hecho de que el ticket en desarrollo es "demasiado grande" y debe dividirse en piezas más pequeñas que pueden ser independientes, por ejemplo:
parece "1 pieza de trabajo". ¡O existen o no! No parece tener sentido separarlo. Sin embargo, la experiencia me ha demostrado que (dependiendo del tamaño y la complejidad de la organización) una ruta más granular podría ser:
Las piezas pequeñas significan revisiones de código más fáciles, pruebas de unidad más fáciles, mejor oportunidad para qa, mejor alineación con el Principio de responsabilidad única, etc.
Para los aspectos prácticos de cuándo hacer tales aplastamientos, existen básicamente dos etapas distintas que tienen su propio flujo de trabajo.
Durante su desarrollo, se compromete 'temprano y con frecuencia' y con mensajes rápidos 'desechables'. Es posible que desee aplastar aquí a veces, por ejemplo, aplastar en wip y confirmaciones de mensajes de todo. Está bien, dentro de la rama, retener múltiples confirmaciones que representan pasos distintos que realizó en el desarrollo. La mayoría de las calabazas que elija hacer deben estar dentro de estas ramas de características, mientras se desarrollan y antes de fusionarse para dominar.
Al agregar a la rama de línea principal, desea que las confirmaciones sean concisas y estén formateadas correctamente de acuerdo con el historial de línea principal existente. Esto podría incluir la identificación del sistema Ticket Tracker, por ejemplo, JIRA como se muestra en los ejemplos. La compresión realmente no se aplica aquí a menos que desee 'acumular' varias confirmaciones distintas en master. Normalmente no lo haces.
El uso
--no-ff
al fusionar con master usará una confirmación para la fusión y también preservará el historial (en la rama). Algunas organizaciones consideran que esta es una mejor práctica. Ver más en https://stackoverflow.com/q/9069061/631619 También verá el efecto práctico engit log
donde un--no-ff
commit será el último commit, en la parte superior de HEAD (cuando se acaba de hacer), mientras que sin--no-ff
él puede ser más abajo en la historia, dependiendo de las fechas y otras confirmaciones.fuente
Debido a que a menudo la persona que saca un RP se preocupa por el efecto neto de la "característica X añadida", no por las "plantillas base, la función de corrección de errores X, la función de agregar Y, los errores tipográficos fijos en los comentarios, los parámetros de escala de datos ajustados, el hashmap funciona mejor que lista "... nivel de detalle
Si crees que tus 16 commits están mejor representados por 2 commits en lugar de 1 "Característica agregada X, re-factorizada Z para usar X", entonces probablemente sea bueno proponer un pr con 2 commits, pero entonces sería mejor proponer 2 pr's separadas en ese caso (si el repositorio todavía insiste en pr's de commit único)
Esto no va en contra del mantra "comprometerse temprano y comprometerse con frecuencia", como en su repositorio, mientras desarrolla aún tiene los detalles granulares, por lo que tiene una mínima posibilidad de perder el trabajo, y otras personas pueden revisar / extraer / proponer PR está en contra de su trabajo mientras se desarrolla el nuevo PR.
fuente
La razón principal de lo que puedo ver es la siguiente:
Merge pull request #123 from joebloggs/fix-snafoo
--first-parent
punto de vista--first-parent
punto de vista (tenga en cuenta que esto solo se solucionó en Git 2.6.2, por lo que podríamos perdonar a GitHub por no tener eso disponible)Entonces, cuando combina las tres situaciones anteriores, obtiene una situación en la que las confirmaciones sin aplastar que se fusionan se ven feas desde la interfaz de usuario de GitHub.
Tu historial con commits aplastados se parecerá
Mientras que sin compromisos aplastados, la historia se verá algo así como
Cuando tiene muchas confirmaciones en un seguimiento de relaciones públicas en el que se produjo un cambio, puede convertirse en una pesadilla si se limita a usar la interfaz de usuario de GitHub .
Por ejemplo, encuentra que un puntero nulo se desreferencia en algún lugar de un archivo ... por lo que dice "¿quién hizo esto y cuándo? ¿Qué versiones de lanzamiento se ven afectadas?". Luego paseas a la vista de culpa en la interfaz de usuario de GitHub y ves que la línea se cambió en
789fdfffdf
... "oh, pero espere un segundo, esa línea solo tenía su sangría cambiada para encajar con el resto del código", así que ahora necesita navegar al estado del árbol para ese archivo en el compromiso principal y volver a visitar la página de la culpa ... eventualmente encuentras el commit ... es un commit de hace 6 meses ... "oh **** esto podría estar afectando a los usuarios durante 6 meses" dices ... ah, pero espera, ese commit en realidad estaba en una solicitud de extracción y solo se fusionó ayer y nadie ha cortado un lanzamiento todavía ... "Maldita sea por fusionar confirmaciones sin aplastar el historial" es el grito que generalmente se puede escuchar después de aproximadamente 2 o 3 expediciones de arqueología de código a través de IU de GitHubAhora consideremos cómo funciona esto si usa la línea de comandos de Git (y la súper increíble 2.6.2 que tiene la solución
git blame --first-parent
)Entonces nuestra historia de compromiso se vería así
Pero también podemos hacer
(En otras palabras: la CLI de Git le permite tener su pastel y comérselo también)
Ahora, cuando nos topamos con el problema del puntero nulo ... bueno, simplemente usamos
git blame --first-parent -w dodgy-file.c
e inmediatamente se nos da la confirmación exacta donde se introdujo la desreferencia del puntero nulo a la rama maestra, ignorando los simples cambios de espacios en blanco.Por supuesto, si está haciendo fusiones usando la interfaz de usuario de GitHub, entonces
git log --first-parent
es realmente horrible gracias a que GitHub obliga a la primera línea del mensaje de confirmación de fusión:Entonces, para resumir una larga historia:
La interfaz de usuario de GitHub (octubre de 2015) tiene una serie de deficiencias con respecto a cómo combina las solicitudes de extracción, cómo presenta el historial de confirmación y cómo atribuye la información de culpa. La mejor forma actual de piratear estos defectos en la interfaz de usuario de GitHub es solicitar a las personas que eliminen sus compromisos antes de fusionarse.
La CLI de Git no tiene estos problemas y puede elegir fácilmente qué vista desea ver para que ambos puedan descubrir la razón por la cual se realizó un cambio en particular de esa manera (mirando el historial de las confirmaciones no aplastadas) y ver los commits efectivamente aplastados.
Publicar guión
La razón final a menudo citada para las confirmaciones de aplastamiento es hacer que el backport sea más fácil ... si solo tiene una confirmación para el puerto de respaldo (es decir, la confirmación aplastada), entonces es fácil elegir ...
Bueno, si está mirando el historial de git
git log --first-parent
, puede elegir los commits de fusión. La mayoría de las personas se confunden al elegir las-m N
opciones de fusión de fusión porque tiene que especificar la opción, pero si obtuvo la confirmación,git log --first-parent
entonces sabe que es el primer padre que desea seguir, por lo que serágit cherry-pick -m 1 ...
fuente
--first-parent
mi fijación para ganar un argumento en contra de aplastar commits ;-)Estoy de acuerdo con los sentimientos expresados en otras respuestas en este hilo sobre mostrar un historial claro y conciso de las características agregadas y los errores corregidos. Sin embargo, quería abordar otro aspecto que su pregunta eludió pero que no mencionó explícitamente. Parte del problema que puede tener sobre algunos de los métodos de trabajo de git es que git le permite reescribir la historia, lo que parece extraño cuando se le presenta a git después de usar otras formas de control de fuente donde tales acciones son imposibles. Además, esto también va en contra del principio generalmente aceptado del control de origen de que una vez que algo se confirma / se registra en el control de origen, debe poder volver a ese estado sin importar los cambios que realice después de ese compromiso. Como implica en su pregunta, esta es una de esas situaciones. Creo que git es un gran sistema de control de versiones; sin embargo, para comprenderlo, debe comprender algunos de los detalles de implementación y las decisiones de diseño que lo respaldan, y como resultado tiene una curva de aprendizaje más pronunciada. Tenga en cuenta que git estaba destinado a ser un sistema de control de versiones distribuido y eso ayudará a explicar por qué los diseñadores permiten que el historial de git se reescriba con confirmaciones de squash como un ejemplo de esto.
fuente
git gc
se haya ejecutado para descartar objetos sin referencia.Debido a la perspectiva ... La mejor práctica es tener una confirmación única por cada
<<issue-management-system>>
problema si es posible.Puede tener tantas confirmaciones como desee en su propia rama / repositorio de funciones, pero es su historial relevante para lo que está haciendo ahora para SU perspectiva ... no es la HISTORIA para todo el EQUIPO / PROYECTO o la aplicación de su perspectiva que se mantendrá dentro de varios meses ...
Por lo tanto, cada vez que desee confirmar una corrección de errores o una función en un repositorio común (este ejemplo es con la rama de desarrollo), puede hacerlo de la siguiente manera:
cómo volver a desarrollar su rama de características para que se desarrolle rápidamente
fuente
Vería si el código se hace público o no.
Cuando los proyectos se mantienen privados:
Yo recomendaría no aplastar y ver la fabricación de la salchicha. Si usa confirmaciones buenas y pequeñas, las herramientas como git bisect son muy útiles y la gente puede identificar rápidamente las confirmaciones de regresión y ver por qué lo hizo (debido al mensaje de confirmación).
Cuando los proyectos se hacen públicos:
Aplasta todo porque algunos commits pueden contener fugas de seguridad. Por ejemplo, una contraseña que se ha confirmado y eliminado nuevamente.
fuente