Acabo de leer la modificación de un solo archivo en una confirmación anterior en git, pero desafortunadamente la solución aceptada 'reordena' las confirmaciones, que no es lo que quiero. Entonces esta es mi pregunta:
De vez en cuando, noto un error en mi código mientras trabajo en una función (no relacionada). git blameLuego, un rápido revela que el error se introdujo hace algunas confirmaciones (yo comprometo bastante, por lo que generalmente no es la confirmación más reciente la que introdujo el error). En este punto, suelo hacer esto:
git stash # temporarily put my work aside
git rebase -i <bad_commit>~1 # rebase one step before the bad commit
# mark broken commit for editing
vim <affected_sources> # fix the bug
git add <affected_sources> # stage fixes
git commit -C <bad_commit> # commit fixes using same log message as before
git rebase --continue # base all later changes onto this
Sin embargo, esto sucede con tanta frecuencia que la secuencia anterior se vuelve molesta. Especialmente la 'rebase interactiva' es aburrida. ¿Hay algún atajo a la secuencia anterior, que me permita modificar una confirmación arbitraria en el pasado con los cambios por etapas? Soy perfectamente consciente de que esto cambia la historia, pero cometo errores con tanta frecuencia que me encantaría tener algo como
vim <affected_sources> # fix bug
git add -p <affected_sources> # Mark my 'fixup' hungs for staging
git fixup <bad_commit> # amend the specified commit with staged changes,
# rebase any successors of bad commit on rewritten
# commit.
¿Quizás un script inteligente que pueda reescribir confirmaciones usando herramientas de plomería o algo así?

rebase -i?rebase --onto tmp bad-commit master. Como está escrito, intentará aplicar el compromiso incorrecto al estado de compromiso fijo.Respuestas:
RESPUESTA ACTUALIZADA
Hace un tiempo,
--fixupse agregó un nuevo argumento algit commitque se puede usar para construir una confirmación con un mensaje de registro adecuado paragit rebase --interactive --autosquash. Entonces, la forma más sencilla de arreglar una confirmación anterior es ahora:RESPUESTA ORIGINAL
Aquí hay un pequeño script de Python que escribí hace un tiempo que implementa esta
git fixuplógica que esperaba en mi pregunta original. La secuencia de comandos asume que realizó algunos cambios y luego aplica esos cambios a la confirmación dada.NOTA : Este script es específico de Windows; busca
git.exey establece laGIT_EDITORvariable de entorno usandoset. Ajústelo según sea necesario para otros sistemas operativos.Usando este script puedo implementar precisamente el flujo de trabajo 'arreglar fuentes rotas, arreglar arreglos, ejecutar git fixup' que pedí:
fuente
git stashygit stash popalrededor de su rebase para que ya no requiera un directorio de trabajo limpiogit stashygit stash pop: tienes razón, pero desafortunadamentegit stashes mucho más lento en Windows que en Linux o OS / X. Dado que mi directorio de trabajo suele estar limpio, omití este paso para no ralentizar el comando.git rebase -i --fixup, y se modificó a partir de la confirmación arreglada como punto de partida, por lo que el argumento sha no era necesario en mi caso.git config --global rebase.autosquash trueLo que hago es:
Su editor se abrirá con una lista de las últimas 5 confirmaciones, listas para ser entrometidas. Cambio:
...a:
Guarde y salga de su editor, y la corrección se volverá a colocar en la confirmación a la que pertenece.
Después de haberlo hecho varias veces, lo hará en segundos mientras duerme. El rebase interactivo es la característica que realmente me vendió en git. Es increíblemente útil para esto y más ...
fuente
--autosquashcambiogit rebase, que reordena automáticamente los pasos en el editor. Vea mi respuesta para un script que aprovecha esto para implementar ungit fixupcomando.Un poco tarde para la fiesta, pero aquí hay una solución que funciona como imaginó el autor.
Agregue esto a su .gitconfig:
Uso de ejemplo:
Sin embargo, si tiene cambios sin etapas, debe guardarlos antes de la reorganización.
Puede modificar el alias para ocultarlo automáticamente, en lugar de dar una advertencia. Sin embargo, si la reparación no se aplica correctamente, necesitará sacar el alijo manualmente después de solucionar los conflictos. Hacer tanto guardar como hacer estallar manualmente parece más consistente y menos confuso.
fuente
git fixup HEADes para lo que creé un alias. También me vendría bien enmendar eso, supongo.amend = commit --amend --reuse-message=HEADLuego puede simplemente escribirgit amendogit amend -ay omitir el editor para el mensaje de confirmación.Para arreglar una confirmación:
donde a0b1c2d3 es el compromiso que desea corregir y donde 2 es el número de confirmaciones +1 pegadas que desea cambiar.
Nota: git rebase --autosquash sin -i no funcionó pero con -i funcionó, lo cual es extraño.
fuente
--autosquashsin-itodavía no funciona.EDITOR=true git rebase --autosquash -iACTUALIZACIÓN: ahora se puede encontrar una versión más limpia del script aquí: https://github.com/deiwin/git-dotfiles/blob/docs/bin/git-fixup .
He estado buscando algo similar. Sin embargo, este script de Python parece demasiado complicado, por lo tanto, he elaborado mi propia solución:
Primero, mis alias de git se ven así (tomados de aquí ):
Ahora la función bash se vuelve bastante simple:
Este código primero prepara todos los cambios actuales (puede eliminar esta parte, si desea preparar los archivos usted mismo). Luego crea la reparación (también se puede usar squash, si eso es lo que necesita) commit. Después de eso, comienza una rebase interactiva con la
--autosquashbandera en el padre de la confirmación que le da como argumento. Eso abrirá tu editor de texto configurado, para que puedas verificar que todo es como esperas y simplemente cerrar el editor finalizará el proceso.La
if [[ "$1" == HEAD* ]]parte (tomada de aquí ) se usa, porque si usa, por ejemplo, HEAD ~ 2 como su referencia de compromiso (el compromiso con el que desea corregir los cambios actuales), entonces el HEAD se desplazará después de que se haya creado el compromiso de reparación y necesitaría usar HEAD ~ 3 para referirse a la misma confirmación.fuente
Puede evitar la etapa interactiva utilizando un editor "nulo":
Esto se utilizará
/bin/truecomo editor, en lugar de/usr/bin/vim. Siempre acepta cualquier sugerencia de git, sin preguntar.fuente
call(["set", "GIT_EDITOR=true", "&&", git, "rebase", "-i" ...).Lo que realmente me molestó del flujo de trabajo de reparación fue que tenía que averiguar yo mismo en qué compromiso quería aplastar el cambio cada vez. Creé un comando "git fixup" que ayuda con esto.
Este comando crea confirmaciones de reparación, con la magia añadida de que utiliza git-deps para encontrar automáticamente la confirmación relevante, por lo que el flujo de trabajo a menudo se reduce a:
Esto solo funciona si los cambios por etapas se pueden atribuir sin ambigüedades a una confirmación en particular en el árbol de trabajo (entre el maestro y HEAD). Encuentro que ese es el caso muy a menudo para el tipo de pequeños cambios para los que uso esto, por ejemplo, errores tipográficos en comentarios o nombres de métodos recién introducidos (o renombrados). Si este no es el caso, al menos mostrará una lista de confirmaciones candidatas.
Utilizo mucho esto en mi flujo de trabajo diario, para integrar rápidamente pequeños cambios en líneas previamente cambiadas en confirmaciones en mi rama de trabajo. El guión no es tan hermoso como podría ser, y está escrito en zsh, pero me ha estado haciendo el trabajo lo suficientemente bien durante un buen tiempo, ahora que nunca sentí la necesidad de reescribirlo:
https://github.com/Valodim/git-fixup
fuente
Puede crear una reparación para un archivo en particular utilizando este alias.
Si ha realizado algunos cambios
myfile.txtpero no desea ponerlos en una nueva confirmación,git fixup-file myfile.txtcreará unfixup!para la confirmación dondemyfile.txtse modificó por última vez, y luego lo harárebase --autosquash.fuente
git rebaseno se llamara automáticamente.commit --fixupyrebase --autosquashson geniales, pero no hacen lo suficiente. Cuando tengo una secuencia de confirmacionesA-B-Cy escribo algunos cambios más en mi árbol de trabajo que pertenecen a una o más de esas confirmaciones existentes, tengo que mirar manualmente el historial, decidir qué cambios pertenecen a qué confirmaciones, organizarlos y crear elfixup!se compromete. Pero git ya tiene acceso a suficiente información para poder hacer todo eso por mí, así que escribí un script en Perl que hace precisamente eso.Por cada trozo en
git diffel script, se usagit blamepara encontrar la confirmación que tocó por última vez las líneas relevantes y las llamadasgit commit --fixuppara escribir lasfixup!confirmaciones apropiadas , esencialmente haciendo lo mismo que estaba haciendo manualmente antes.Si lo encuentra útil, siéntase libre de mejorarlo e iterarlo y tal vez algún día tengamos dicha función en forma
gitadecuada. Me encantaría ver una herramienta que pueda comprender cómo se debe resolver un conflicto de fusión cuando ha sido introducido por una rebase interactiva.fuente
Escribí una pequeña función de shell llamada
gcfpara realizar la confirmación de reparación y la rebase automáticamente:Por ejemplo, puede parchear la segunda confirmación antes de la última con:
gcf HEAD~~Aquí está la función . Puedes pegarlo en tu
~/.bashrcSe utiliza
--autostashpara guardar y hacer estallar cualquier cambio no confirmado si es necesario.--autosquashrequiere un--interactiverebase, pero evitamos la interacción usando un maniquíEDITOR.--no-fork-pointprotege las confirmaciones de ser eliminadas silenciosamente en situaciones raras (cuando ha bifurcado una nueva rama y alguien ya ha vuelto a basar las confirmaciones pasadas).fuente
No conozco una forma automatizada, pero aquí hay una solución que podría ser más fácil de manipular por humanos:
fuente
git fixupcomando.--autosquashRecomendaría https://github.com/tummychow/git-absorb :
fuente