¿Cómo modificar un commit especificado en git?


Normalmente envío una lista de confirmaciones para su revisión. Si tengo:

  • HEAD
  • Commit3
  • Commit2
  • Commit1

, sé que puedo modificar cabeza comprometerse con git commit --amend, pero ¿cómo puedo modificar Commit1, dado que no es el HEAD cometer?

Author: Chris Martin, 2009-07-27

12 answers

Puede usar git rebase, por ejemplo, si desea modificar de nuevo para confirmar bbc643cd, ejecute

$ git rebase --interactive 'bbc643cd^'

En el editor predeterminado, modifique pick a edit en la línea cuya confirmación desea modificar. Haz tus cambios y luego envíalos con el mismo mensaje que tenías antes:

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

Para modificar el commit, y después de eso

$ git rebase --continue

Para volver a la confirmación de head anterior.

ADVERTENCIA : Tenga en cuenta que esto cambiará el SHA-1 de esa confirmación , así como todos children in en otras palabras, esto reescribe la historia desde ese punto en adelante. Puedes romper repos haciendo esto si envías usando el comando git push --force

 2294
Author: ZelluX,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-14 14:14:16

Usa el impresionante rebase interactivo:

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

Encuentra la confirmación que deseas, cambia pick a e (edit), y guardar y cerrar el archivo. Git rebobinará a esa confirmación, permitiéndote:

  • 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 había editado los archivos, pero aún no se había confirmado).

Este último es útil para hacer más complejos cosas como dividirse en varias confirmaciones.

Luego, ejecuta git rebase --continue, y Git reproducirá los cambios posteriores en la parte superior de tu confirmación modificada. Se le puede pedir que solucione algunos conflictos de fusión.

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

Lee más sobre reescribir el historial en los documentos de Git.


No tengas miedo de rebase

ProTip™: No tengas miedo para experimentar con comandos "peligrosos" que reescriben el historial * - Git no elimina tus commits durante 90 días por defecto; 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

* Sin embargo, ten cuidado con opciones como --hard y --force: pueden descartar datos.
* Además, no reescribas el historial en ninguna rama en la que estés colaborando.



En muchos sistemas, git rebase -i abrirá Vim por defecto. Vim no funciona como la mayoría de los editores de texto modernos, por lo que echa un vistazo a cómo rebase usando Vim. Si prefieres usar un editor diferente, cámbialo con git config --global core.editor your-favorite-text-editor.

 319
Author: Zaz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:18:24

Interactive rebase with --autosquash es algo que uso con frecuencia cuando necesito reparar confirmaciones anteriores más profundas en el historial. Esencialmente 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! fix "(o " fixup! ... "), y hay un commit cuyo título comienza con el mismo …​, modifica automáticamente la lista de tareas de rebase-i para que el commit marcado para squashing llegue justo después del commit que se va a modificar

Supongamos que tiene un historial que se ve así:

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

Y tiene cambios que desea modificar a Commit2, luego confirme sus cambios usando

$ git commit -m "fixup! Commit2"

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

Luego inicie una rebase interactiva en el commit antes de

$ 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 necesita hacer es guardar y salir

 60
Author: thrau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-29 17:59:45

Ejecutar:

$ git rebase --interactive commit_hash^

Cada ^ indica cuántas confirmaciones desea editar, si es solo una (el hash de confirmación que especificó), entonces solo agrega una ^.

Usando Vim cambias las palabras pick a reword para las confirmaciones que quieres cambiar, guardar y salir(:wq). Luego, git te preguntará con cada confirmación que marques como reword para que puedas cambiar el mensaje de confirmación.

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

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

EDITAR: para navegar en vim se 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, pulse ESC para ir al modo NORMAL). Para editar un texto, presione i para entrar en el modo INSERT, donde inserta texto. Pulse 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

 31
Author: betoharres,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-13 19:45:40

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

Digamos que desea modificar Commit1. Primero, rama de antes Commit1:

git checkout -b amending [commit before Commit1]

Segundo, agarra 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 guardado cualquier otro cambio, transplante el resto de sus confirmaciones hasta master en la parte superior de su nueva confirmación:

git rebase --onto amending Commit1 master

Lee: "rebase, en la rama amending, todo commits between Commit1 (non-inclusive) and master (inclusive)". Es decir, Commit2 y Commit3, eliminando por completo el antiguo Commit1. Podrías elegirlos, pero de esta manera es más fácil.

¡Recuerda limpiar tus ramas!

git branch -d amending
 13
Author: FeepingCreature,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-22 12:19:44

Llegó a este enfoque (y probablemente sea exactamente lo mismo que usar rebase interactivo), pero para mí es algo sencillo.

Nota: Presento este enfoque por el bien de la ilustración de lo que puede hacer en lugar de una alternativa cotidiana. Ya que tiene muchos pasos (y posiblemente algunas advertencias.)

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

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

Checkout a este commit y crea un quick-branch. También puede clonar su característica branch como 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: {[16]]}

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

El escenario cambia, guarda todo lo demás.

git add ./example.txt
git stash

Confirmar cambios y pagar de nuevo a feature-branch

git commit --amend
git checkout feature-branch

Ahora tendrás algo como esto: {[16]]}

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

Rebase feature-branch en quick-branch (resolver cualquier conflicto en el camino). Aplicar stash y eliminar 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 yo realmente no se puede decir en qué medida) el 0 commit al rebasing.

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

 6
Author: Olga,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-23 16:51:41

Comando completamente no interactivo(1)

Solo pensé en compartir un alias que estoy usando para esto. Está basado en no interactivo rebase interactivo. Para añadirlo a tu git, ejecuta 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 no vim-.


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

Uso

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

El name 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á un comando no-git <COMMAND>
  • 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" - fixup-commit para SHA. Véase git-commit docs
  • GIT_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 con git commit --fixup, ver git-rebase docs para más información
    • GIT_SEQUENCE_EDITOR=true es lo que hace que todo esto no sea interactivo. Este truco lo aprendí de esta entrada de blog.
 6
Author: Dethariel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-27 01:47:51

Para obtener un comando no interactivo, coloque 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"

Utilícelo organizando sus cambios (con git add) y luego ejecute git fixup <commit-to-modify>. Por supuesto, seguirá siendo interactivo si tienes conflictos.

 5
Author: Pelle Nilsson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-16 15:27:09

Basado en Documentación

Modificar el mensaje de mensajes de confirmación anteriores o múltiples

git rebase -i HEAD~3 

Lo anterior muestra una lista de las últimas 3 confirmaciones en la rama actual, cambia 3 a otra cosa si quieres 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.

Reemplazar seleccionar con reformular antes de cada mensaje de confirmación de que desea cambiar. Digamos que cambia la segunda confirmación en la lista, su archivo se verá como el siguiente:

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 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 Forzar-empujar las confirmaciones modificadas.

git push --force
 2
Author: justMe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-17 08:38:57

Para mí fue para eliminar algunas credenciales de un repositorio. Traté de rebase y me encontré con un montón de conflictos aparentemente no relacionados en el camino al tratar de rebase continue continuar. No se moleste en intentar rebase usted mismo, utilice la herramienta llamada BFG (brew install bfg) en mac.

 1
Author: Pellet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-07 07:24:20

Resolví esto,

1) creando una nueva confirmación con los cambios que quiero..

r8gs4r commit 0

2) sé qué commit necesito combinar con él. que es commit 3.

Así que, git rebase -i HEAD~4 # 4 representa 4 commit recientes (aquí commit 3 está en 4to lugar)

3) en rebase interactivo, la confirmación reciente se ubicará en la parte inferior. se parece,

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

4) aquí necesitamos reorganizar commit si desea fusionarse 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 reorganizarte necesidad de reemplazar p pick con f (fixup se fusionará sin mensaje de confirmación) o s (squash merge with commit message can change in run time)

Y luego salva tu árbol.

Ahora merge done con commit existente.

Nota: No es el método preferible a menos que se mantenga por su cuenta. si tienes un gran tamaño de equipo no es un método aceptable para reescribir git árbol terminará en conflictos que usted sabe que otros no. Si quieres a mantener su árbol limpio con menos commits puede probar esto y si su equipo pequeño de lo contrario no es preferible.....

 1
Author: Mohideen ibn Mohammed,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-05 18:35:50

Edición de rebase interactiva automatizada seguida de reversión de confirmación lista para un do-over

Me encontré arreglando un commit pasado con suficiente frecuencia que escribí un script para él.

Aquí está el flujo de trabajo:

  1. git commit-edit <commit-hash>
    

    Esto te llevará a la confirmación que deseas editar.

  2. Arregla y prepara la confirmación como deseas que hubiera sido en primer lugar.

    (Es posible que desee usar git stash save para mantener cualquier archivo que no esté cometer)

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

    git commit --amend
    
  4. Completa la rebase:

    git rebase --continue
    

Para que lo anterior funcione, coloque el siguiente script 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
 1
Author: Tom Hale,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-14 04:41:11