¿Cómo modifico un compromiso específico?
Tengo el siguiente historial de confirmaciones:
HEAD
HEAD~
HEAD~2
HEAD~3
git commit --amend
modifica la HEAD
confirmación actual. ¿Pero cómo lo modifico HEAD~3
?
Usar git rebase
. Por ejemplo, para modificar el compromiso bbc643cd
, ejecute:
git rebase --interactive bbc643cd~
Tenga en cuenta la tilde ~
al final del comando, porque necesita volver a aplicar confirmaciones además de la confirmación anterior debbc643cd
(es decir bbc643cd~
).
En el editor predeterminado, modifíquelo pick
en edit
la línea que mencionabbc643cd
.
Guarda el archivo y cierra. git interpretará y ejecutará automáticamente los comandos del archivo. Te encontrarás en la situación anterior en la que acabas de crear el compromiso.bbc643cd
.
En este punto, bbc643cd
es su último compromiso y puede modificarlo fácilmente . Realice sus cambios y luego confírmelos con el comando:
git commit --all --amend --no-edit
Después de eso, regrese al compromiso HEAD anterior usando:
git rebase --continue
ADVERTENCIA : Tenga en cuenta que esto cambiará el SHA-1 de esa confirmación, así como de todos los elementos secundarios ; en otras palabras, esto reescribe la historia desde ese momento en adelante. Puedes romper repositorios haciendo esto si presionas usando el comando git push --force
.
Utilice la increíble rebase interactiva:
git rebase -i # Show your commits in a text editor
Busque la confirmación que desee, cámbiela pick
a e
( edit
), guarde y cierre el archivo. Git rebobinará hasta ese compromiso, permitiéndole:
- utilizar
git commit --amend
para realizar cambios, o - utilícelo
git reset @~
para descartar la última confirmación, pero no los cambios en los archivos (es decir, llevarlo al punto en el que se encontraba cuando editó los archivos, pero aún no se había comprometido).
Este último es útil para hacer cosas más complejas como dividir en múltiples confirmaciones.
Luego, ejecute git rebase --continue
y Git reproducirá los cambios posteriores además de su confirmación modificada. Es posible que se le solicite que solucione algunos conflictos de fusión.
Nota: @
es una abreviatura de HEAD
y ~
es la confirmación antes de la confirmación especificada.
Lea más sobre cómo reescribir el historial en los documentos de Git.
No tengas miedo de rebase
ProTip™: No tengas miedo de experimentar con comandos "peligrosos" que reescriben el historial*: Git no elimina tus confirmaciones durante 90 días de forma predeterminada; Puedes encontrarlos en el reflog:
$ git reset @~3 # go back 3 commits
$ git reflog
c4f708b HEAD@{0}: reset: moving to @~3
2c52489 HEAD@{1}: commit: more changes
4a5246d HEAD@{2}: commit: make important changes
e8571e4 HEAD@{3}: commit: make some changes
... earlier commits ...
$ git reset 2c52489
... and you're back where you started
* Tenga cuidado con opciones como --hard
y --force
aunque: pueden descartar datos.
* Además, no reescribas el historial de ninguna rama en la que estés colaborando.
En muchos sistemas, git rebase -i
se abrirá Vim de forma predeterminada. Vim no funciona como la mayoría de los editores de texto modernos, así que eche un vistazo a cómo cambiar la base usando Vim . Si prefieres utilizar un editor diferente, cámbialo con git config --global core.editor your-favorite-text-editor
.
Rebase interactivo con--autosquash
uso con frecuencia cuando necesito arreglar confirmaciones anteriores más profundas en el historial. Básicamente, acelera el proceso que ilustra la respuesta de ZelluX y es especialmente útil cuando tiene más de una confirmación que necesita editar.
De la documentación:
--autosquash
Cuando el mensaje de registro de confirmación comienza con "squash! …" (o "¡reparación! …"), y hay una confirmación cuyo título comienza con el mismo …, modifica automáticamente la lista de tareas pendientes de rebase -i para que la confirmación marcado para aplastamiento viene justo después del compromiso que se va a modificar
Suponga que tiene un historial similar a este:
$ git log --graph --oneline
* b42d293 Commit3
* e8adec4 Commit2
* faaf19f Commit1
y tiene cambios que desea modificar en Commit2, luego confirme sus cambios usando
$ git commit -m "fixup! Commit2"
alternativamente, puede usar commit-sha en lugar del mensaje de confirmación, "fixup! e8adec4
o incluso simplemente un prefijo del mensaje de confirmación.
Luego inicie una rebase interactiva en la confirmación antes
$ git rebase e8adec4^ -i --autosquash
su editor se abrirá con las confirmaciones ya ordenadas correctamente
pick e8adec4 Commit2
fixup 54e1a99 fixup! Commit2
pick b42d293 Commit3
todo lo que necesitas hacer es guardar y salir
Basado en documentación
Modificar el mensaje de mensajes de confirmación más antiguos o múltiples
git rebase -i HEAD~3
Lo anterior muestra una lista de las últimas 3 confirmaciones en la rama actual, cambie 3 a otra cosa si desea más. La lista será similar a la siguiente:
pick e499d89 Delete CNAME
pick 0c39034 Better README
pick f7fde4a Change the commit message but push the same commit.
Reemplace pick con reformular antes de cada mensaje de confirmación que desee cambiar. Digamos que cambia la segunda confirmación en la lista, su archivo se verá así:
pick e499d89 Delete CNAME
reword 0c39034 Better README
pick f7fde4a Change the commit message but push the same commit.
Guarde y cierre el archivo de la lista de confirmación; esto abrirá un nuevo editor para que pueda cambiar su mensaje de confirmación, cambiar el mensaje de confirmación y guardar.
Finalmente, fuerce las confirmaciones modificadas.
git push --force
Correr:
$ git rebase --interactive commit_hash^
cada uno ^
indica cuántas confirmaciones desea editar; si es solo una (el hash de confirmación que especificó), simplemente agrega una ^
.
Al usar Vim, cambia las palabras pick
para reword
las confirmaciones que desea cambiar, guardar y salir ( :wq
). Luego, git le indicará cada confirmación que marcó como reformulación para que pueda cambiar el mensaje de confirmación.
Cada mensaje de confirmación debe guardarse y salir ( :wq
) para ir al siguiente mensaje de confirmación.
Si desea salir sin aplicar los cambios, presione:q!
EDITAR : para navegar vim
usas j
subir, k
bajar, h
ir a la izquierda e l
ir a la derecha (todo esto en NORMAL
modo, presiona ESC
para ir al NORMAL
modo). Para editar un texto, presione i
para ingresar al INSERT
modo donde inserta texto. Pulsa ESC
para volver al NORMAL
modo :)
ACTUALIZACIÓN : Aquí hay un excelente enlace de la lista de github Cómo deshacer (casi) cualquier cosa con git
Comando completamente no interactivo (1)
Sólo pensé en compartir un alias que estoy usando para esto. Se basa en una rebase interactiva no interactiva . Para agregarlo a su git, ejecute este comando (la explicación se proporciona a continuación):
git config --global alias.amend-to '!f() { SHA=`git rev-parse "$1"`; git commit --fixup "$SHA" && GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^"; }; f'
O bien, una versión que también puede manejar archivos no preparados (guardándolos y luego anulándolos):
git config --global alias.amend-to '!f() { SHA=`git rev-parse "$1"`; git stash -k && git commit --fixup "$SHA" && GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^" && git stash pop; }; f'
La mayor ventaja de este comando es el hecho de que no es vim .
(1) dado que no hay conflictos durante el rebase, por supuesto
Uso
git amend-to <REV> # e.g.
git amend-to HEAD~1
git amend-to aaaa1111
El nombre amend-to
parece apropiado en mi humilde opinión. Compara el flujo con --amend
:
git add . && git commit --amend --no-edit
# vs
git add . && git amend-to <REV>
Explicación
git config --global alias.<NAME> '!<COMMAND>'
- crea un alias global de git llamado<NAME>
que ejecutará un comando que no sea de git<COMMAND>
f() { <BODY> }; f
- una función bash "anónima".SHA=`git rev-parse "$1"`;
- convierte el argumento a revisión de git y asigna el resultado a la variableSHA
git commit --fixup "$SHA"
- compromiso de reparación paraSHA
. Vergit-commit
documentosGIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^"
git rebase --interactive "$SHA^"
parte ha sido cubierta por otras respuestas.--autosquash
es lo que se usa junto congit commit --fixup
, consultegit-rebase
los documentos para obtener más informaciónGIT_SEQUENCE_EDITOR=true
es lo que hace que todo el asunto no sea interactivo. Este truco lo aprendí de esta publicación de blog .