ultimo renombrar rehacer regresar modificar mensaje descripcion comentario cambiar anterior git git-rewrite-history

git - renombrar - ¿Cómo modificar un commit especificado?



rehacer un commit git (12)

Por lo general envío una lista de confirmaciones para revisión. Si tengo las siguientes confirmaciones:

  1. HEAD
  2. Commit3
  3. Commit2
  4. Commit1

... Sé que puedo modificar head commit con git commit --amend . Pero, ¿cómo puedo modificar Commit1 , dado que no es el commit HEAD ?


Utilice la impresionante rebase interactiva:

git rebase -i @~9 # Show the last 9 commits in a text editor

Encuentre la confirmación que desea, cambie la pick a e ( edit ) y guarde y cierre el archivo. Git retrocederá a ese compromiso, permitiéndole:

  • use git commit --amend para hacer cambios, o
  • use git reset @~ para descartar la última confirmación, pero no los cambios en los archivos (es decir, llevarlo al punto en el que estaba cuando editó los archivos, pero aún no se había confirmado).

El ú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 sobre su confirmación modificada. Se le puede pedir que arregle algunos conflictos de combinación.

Nota: @ es una forma abreviada de HEAD , y ~ es la confirmación antes de la confirmación especificada.

Lea más sobre la reescritura de la historia en los documentos de Git.


No tengas miedo de rebase

ProTip ™: no tenga miedo de experimentar con comandos "peligrosos" que reescriben el historial *: Git no elimina sus confirmaciones por 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 en ninguna de las sucursales en las que estés colaborando.


En muchos sistemas, git rebase -i 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 volver a utilizar el Vim . Si prefiere usar un editor diferente, cámbielo con git config --global core.editor your-favorite-text-editor .


Comando completamente no interactivo (1)

Solo pensé que compartiría un alias que estoy usando para esto. Se basa en rebase interactiva no interactiva. Para agregarlo a su git, ejecute este comando (explicación dada 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''

La mayor ventaja de este comando es el hecho de que es no-vim .

(1) dado que no hay conflictos durante la rebase, por supuesto

Uso

git amend-to <REV> # e.g. git amend-to HEAD~1 git amend-to aaaa1111

El nombre de amend-to parece apropiado en mi humilde opinión. Compare 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á el comando no-git <COMMAND>
  • f() { <BODY> }; f f() { <BODY> }; f - una función bash "anónima".
  • SHA=`git rev-parse "$1"`; - convierte el argumento a git revision y asigna el resultado a la variable SHA
  • git commit --fixup "$SHA" - corrección-commit para SHA . Ver git-commit documentos de git-commit
  • GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^"
    • git rebase --interactive "$SHA^" ha sido cubierta por otras respuestas.
    • --autosquash es lo que se usa junto con git commit --fixup , consulte git-rebase docs para más información
    • GIT_SEQUENCE_EDITOR=true es lo que hace que todo sea no interactivo. Este truco lo aprendí de esta entrada de blog .

Edición de rebase interactiva automatizada seguida de un cambio de conversión listo para una repetición

Me encontré arreglando un compromiso pasado con la frecuencia suficiente para que escribiera un script para él.

Aquí está el flujo de trabajo:

  1. git commit-edit <commit-hash>

    Esto te dejará en la confirmación que deseas editar.

  2. Arregle y ponga en escena el compromiso como deseara en primer lugar.

    (Es posible que desee utilizar git stash save para guardar cualquier archivo que no esté confirmando)

  3. Rehacer el compromiso con - --amend , por ejemplo:

    git commit --amend

  4. Completa la rebase:

    git rebase --continue

Para que funcione lo anterior, coloque el script siguiente en un archivo ejecutable llamado git-commit-edit en algún lugar de su $PATH :

#!/bin/bash set -euo pipefail script_name=${0##*/} warn () { printf ''%s: %s/n'' "$script_name" "$*" >&2; } die () { warn "$@"; exit 1; } [[ $# -ge 2 ]] && die "Expected single commit to edit. Defaults to HEAD~" # Default to editing the parent of the most recent commit # The most recent commit can be edited with `git commit --amend` commit=$(git rev-parse --short "${1:-HEAD~}") message=$(git log -1 --format=''%h %s'' "$commit") if [[ $OSTYPE =~ ^darwin ]]; then sed_inplace=(sed -Ei "") else sed_inplace=(sed -Ei) fi export GIT_SEQUENCE_EDITOR="${sed_inplace[*]} "'' "s/^pick (''"$commit"'' .*)/edit //1/"'' git rebase --quiet --interactive --autostash --autosquash "$commit"~ git reset --quiet @~ "$(git rev-parse --show-toplevel)" # Reset the cache of the toplevel directory to the previous commit git commit --quiet --amend --no-edit --allow-empty # Commit an empty commit so that that cache diffs are un-reversed echo echo "Editing commit: $message" >&2 echo


Basado en la Documentation

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 se verá 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 reword antes de cada mensaje de confirmación que desee cambiar. Digamos que cambia la segunda confirmación en la lista, su archivo tendrá el siguiente aspecto:

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, aparecerá un nuevo editor para que pueda cambiar su mensaje de confirmación, cambiar el mensaje de confirmación y guardar.

Finalmente presionar a la fuerza los compromisos enmendados.

git push --force


Correr:

$ git rebase --interactive commit_hash^

cada ^ indica la cantidad de confirmaciones que desea editar, si solo es una (el hash de confirmación que especificó), entonces solo agrega una ^ .

Usando Vim, cambia la pick palabras para reword las confirmaciones que desea cambiar, guardar y salir ( :wq ). Luego, git le indicará con cada confirmación que marcó como nueva palabra para que pueda cambiar el mensaje de confirmación.

Cada mensaje de confirmación que debe guardar y salir ( :wq ) para ir al siguiente mensaje de confirmación

Si desea salir sin aplicar los cambios, presione :q!

EDIT : para navegar en vim usa j para subir, k para bajar, h para ir a la izquierda y l para ir a la derecha (todo esto en el modo NORMAL , presione ESC para ir al modo NORMAL ). Para editar un texto, presione i para ingresar al modo INSERT , donde inserta el texto. Pulsa ESC para volver al modo NORMAL :)

ACTUALIZACIÓN : Aquí hay un gran enlace de la lista de github Cómo deshacer (casi) cualquier cosa con git


La rebase interactiva con --autosquash es algo que uso con frecuencia cuando necesito corregir los compromisos anteriores más a fondo en la historia. Básicamente, acelera el proceso que ilustra la respuesta de ZelluX, y es especialmente útil cuando tiene más de un compromiso que necesita editar.

De la documentación:

--autosquash

Cuando el mensaje de registro de confirmación comience con "squash! ..." (o "fixup! ..."), y haya una confirmación cuyo título comience con la misma ..., modifique automáticamente la lista de tareas pendientes de rebase -i para que la confirmación Marcado para aplastar llega justo después de la confirmación de modificación.

Supongamos que tiene una historia que se parece a esto:

$ git log --graph --oneline * b42d293 Commit3 * e8adec4 Commit2 * faaf19f Commit1

y tiene cambios que desea enmendar en Commit2 y luego confirme sus cambios usando

$ git commit -m "fixup! Commit2"

como alternativa, puede usar el "fixup! e8adec4 commit-sha en lugar del mensaje de confirmación, así que "fixup! e8adec4 o incluso solo un prefijo del mensaje de confirmación.

Luego inicie una rebase interactiva en el commit 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


Llegué a este enfoque (y probablemente es exactamente lo mismo que usar una rebase interactiva) pero para mí es bastante sencillo.

Nota: Presento este enfoque para ilustrar lo que puede hacer en lugar de una alternativa diaria. Ya que tiene muchos pasos (y posiblemente algunas advertencias).

Digamos que quieres cambiar el commit 0 y estás actualmente en feature-branch

some-commit---0---1---2---(feature-branch)HEAD

Verifique este compromiso y cree una quick-branch . También puede clonar su rama de características como un punto de recuperación (antes de comenzar).

?(git checkout -b feature-branch-backup) git checkout 0 git checkout -b quick-branch

Ahora tendrás algo como esto:

0(quick-branch)HEAD---1---2---(feature-branch)

Cambios de escenario, esconder todo lo demás.

git add ./example.txt git stash

Confirmar cambios y realizar el checkout a feature-branch

git commit --amend git checkout feature-branch

Ahora tendrás algo como esto:

some-commit---0---1---2---(feature-branch)HEAD / ---0''(quick-branch)

Restablecer la feature-branch en feature-branch quick-branch (resolver cualquier conflicto en el camino). Aplica el alijo y quita quick-branch .

git rebase quick-branch git stash pop git branch -D quick-branch

Y terminas con:

some-commit---0''---1''---2''---HEAD(feature-branch)

Git no duplicará (aunque realmente no puedo decir hasta qué punto) el cometer 0 al rebasar.

Nota: todos los hashes de confirmación se cambian a partir de la confirmación que originalmente pretendíamos cambiar.


Para mí fue para eliminar algunas credenciales de un repositorio. Intenté volver a basarme y me encontré con una tonelada de conflictos aparentemente no relacionados en el camino cuando intentaba volver a generar --continuar No se moleste en intentar cambiar de valor, use la herramienta llamada BFG (brew install bfg) en mac.


Para obtener un comando no interactivo, ponga un script con este contenido en su RUTA:

#!/bin/sh # # git-fixup # Use staged changes to modify a specified commit set -e cmt=$(git rev-parse $1) git commit --fixup="$cmt" GIT_EDITOR=true git rebase -i --autosquash "$cmt~1"

Úselo preparando sus cambios (con git add ) y luego ejecute git fixup <commit-to-modify> . Por supuesto, todavía será interactivo si tienes conflictos.


Puede usar git rebase, por ejemplo, si desea volver a modificar para confirmar bbc643cd , ejecute

$ git rebase --interactive ''bbc643cd^''

En el editor predeterminado, modifique la pick para edit en la línea cuyo compromiso desea modificar. Realice sus cambios y luego comprométalos con el mismo mensaje que tenía antes:

$ git commit --all --amend --no-edit

Para modificar el commit, y después de eso.

$ git rebase --continue

Para volver a la cabeza anterior cometer.

ADVERTENCIA : Tenga en cuenta que esto cambiará el SHA-1 de ese compromiso así como todos los hijos ; en otras palabras, esto vuelve a escribir el historial desde ese punto en adelante. Puedes romper los repos haciendo esto si presionas usando el comando git push --force


Resolví esto,

1) creando un nuevo commit con los cambios que quiero ..

r8gs4r commit 0

2) Sé qué compromiso necesito fusionar con él. que es cometer 3.

por lo tanto, git rebase -i HEAD~4 # 4 representa los últimos 4 confirmaciones (aquí commit 3 está en 4to lugar)

3) en el rebase interactivo, el compromiso reciente se encuentra en la parte inferior. se verá igual,

pick q6ade6 commit 3 pick vr43de commit 2 pick ac123d commit 1 pick r8gs4r commit 0

4) Aquí debemos reorganizar el compromiso si desea fusionar con uno específico. debería ser como

parent |_child pick q6ade6 commit 3 f r8gs4r commit 0 pick vr43de commit 2 pick ac123d commit 1

después de reorganizar, debe reemplazar p pick con f (la reparación se fusionará sin mensaje de confirmación) o s (la combinación de squash con el mensaje de confirmación puede cambiar en el tiempo de ejecución)

y luego salva tu arbol.

ahora fusionar hecho con el compromiso existente.

Nota: no es un método preferible a menos que se mantenga por su cuenta. Si tienes un equipo grande, no es un método aceptable para reescribir el árbol git que terminará en conflictos que sabes que otros no. Si desea mantener su árbol limpio con menos compromisos, intente esto y si su pequeño equipo no es preferible ...


Si por alguna razón no le gustan los editores interactivos, puede usar git rebase --onto .

Digamos que quieres modificar Commit1 . Primero, ramifique desde antes de Commit1 :

git checkout -b amending [commit before Commit1]

En segundo lugar, toma Commit1 con cherry-pick :

git cherry-pick Commit1

Ahora, modifique sus cambios, creando Commit1'' :

git add ... git commit --amend -m "new message for Commit1"

Y finalmente, después de haber ocultado cualquier otro cambio, transplante el resto de sus compromisos para master su nuevo compromiso:

git rebase --onto amending Commit1 master

Lea: "rebase, en la amending la rama, todos los compromisos entre Commit1 (no incluido) y master (incluido)". Es decir, Commit2 y Commit3, eliminando completamente el antiguo Commit1. Podrías simplemente elegirlos, pero de esta manera es más fácil.

¡Recuerda limpiar tus ramas!

git branch -d amending