Creo que la raíz del problema es que git (y el control de versiones en general) obliga a pensar en términos de secuencias de cambios, sino un conjunto de cambios o característica de rama o lo que llamo una el grupo cohesivo de cambios relacionados en general no es lógicamente secuencial. El orden en que se escribió el código es incidental y no está necesariamente relacionado con el orden en que debe leerse.
No tengo una solución para eso, pero he escrito un Perl script para ayudar a automatizar el proceso de reescribir el historial. Es similar a la secuencia de comandos de Python de @MikaEloranta que no había visto cuando lo escribí.
y rebase --autosquash
son geniales, pero no hacen lo suficiente. Cuando tengo una secuencia de commits A-B-C
y escribo algunos cambios más en mi árbol de trabajo que pertenecen a uno o más commits existentes, tengo que mirar el historial manualmente, decidir qué cambios pertenecen a qué commits, ponerlos en escena y crear el fixup!
confirma. Pero git ya tiene acceso a suficiente información para poder hacer todo eso por mí.
Para cada trozo en git diff
la secuencia de comandos utiliza git blame
para encontrar la confirmación que tocó por último las líneas relevantes, y pide git commit --fixup
escribir las correspondientes fixup!
confirmaciones, esencialmente haciendo lo mismo que hacía manualmente antes.
Si la secuencia de comandos no puede resolver un trozo a una única confirmación inequívoca, lo informará como un trozo fallido y tendrá que recurrir al enfoque manual para esa. Si cambió una línea dos veces en dos confirmaciones separadas, la secuencia de comandos resolverá un cambio en esa línea a la última de esas confirmaciones, que podría no ser siempre la resolución correcta. En mi humilde opinión, en una rama de función de "forma normal", no debe cambiar una línea dos veces en dos confirmaciones diferentes, cada compromiso debe presentar la versión final de las líneas que toca, para ayudar al revisor (es). Sin embargo, puede suceder en una rama de corrección de errores, para crear un ejemplo, la línea foo(bar());
podría ser modificada por la confirmación A (renombre foo
en fox
) y confirme B (renombre bar
en baz
).
Si encuentra útil la secuencia de comandos, no dude en mejorar e iterar en ella y tal vez algún día obtengamos dicha función en git
propiamente dicha. Me encantaría ver una herramienta que pueda entender cómo debe resolverse un conflicto de fusión cuando ha sido introducido por una base de datos interactiva.
¿Por qué un requisito tan extraño que fixA tiene que fusionarse en A? –
porque debería haber estado en A en primer lugar. – elmarco
Hago lo mismo; No estoy seguro de por qué la gente piensa que es extraño. Si intentas organizar commits en piezas pequeñas y lógicamente agrupadas, entonces es natural preparar varios commit inéditos a la vez. (Puede que no sepa si realmente ha terminado con A hasta que termine C). – andy