¿Editar la confirmación de raíz en Git?

328

Hay formas de cambiar el mensaje de confirmaciones posteriores:

git commit --amend                    # for the most recent commit
git rebase --interactive master~2     # but requires *parent*

¿Cómo puede cambiar el mensaje de confirmación de la primera confirmación (que no tiene padre)?

13ren
fuente
En particular: el uso de la variable de entorno GIT_COMMIT en el script degit filter-branch --msg-filter
fork0
1
ver también stackoverflow.com/a/2309391/264607
BlackICE

Respuestas:

284

Suponiendo que tiene un árbol de trabajo limpio, puede hacer lo siguiente.

# checkout the root commit
git checkout <sha1-of-root>

# amend the commit
git commit --amend

# rebase all the other commits in master onto the amended root
git rebase --onto HEAD HEAD master
CB Bailey
fuente
23
Creo que esto debería ser git rebase --onto HEAD <sha1-of-root> master.
Andrew
55
Correcto, pero desea la confirmación raíz original para el <upstream> de git rebase. git rebaseaplica confirmaciones en <branch> ( master) que no están en <upstream>; HEADno está en master, así que su versión intenta aplicar todo master.
Andrew
77
Sí, asegúrese de que sea git rebase --onto HEAD <sha1-of-root>maestro, donde <sha1-of-root>se usa lo mismo git checkout <sha1-of-root>. De lo contrario, tendrá 2 first commit's.
Andy
2
@ Cupcake: ¿Probaste la versión anterior del comando? Debería funcionar bien. La modificación está cambiando el mensaje de confirmación solo para que las confirmaciones de raíz antiguas y nuevas introduzcan exactamente los mismos cambios, de modo que la confirmación de raíz anterior se omita automáticamente. El segundo HEADasegura que se consideren todos los commits y que podamos usar la versión de dos parámetros de rebase para volver al master. Tenga en cuenta que esta respuesta es anterior a la existencia de la --rootopción de rebase.
CB Bailey
99
La respuesta de ecdpalma a continuación es mucho más fácil y simple y tiene más votos, ¡desplácese hacia abajo!
Flimm
567

A partir de la versión 1.7.12 de Git , ahora puede usar

git rebase -i --root

Documentación

ecdpalma
fuente
2
¿Es posible cambiar la base de todas las ramas usando este comando? Parece que esto separará la rama actual en la nueva raíz y todas las demás ramas permanecerán en la antigua raíz
woojoo666
@ woojoo666 tendrá que volver a crear ramas en una nueva raíz. como siempre.
berkus
@Atcold no funciona si no hay una raíz aguas arriba
Kai
Advertencia: asumí erróneamente que esto haría la raíz de mi rama desprotegida, pero lleva un tiempo cargar todas las confirmaciones y luego volver a modificarlas.
Leo
2
@Leo, ¿qué significa tu comentario? No puedo ver el vínculo entre la primera parte y la segunda, ¿qué tiene que ver con tomar un tiempo?
boycy
66

Para ampliar la respuesta de ecdpalma , ahora puede usar la --rootopción para indicar rebaseque desea reescribir la raíz / primer commit:

git rebase --interactive --root

Luego, la confirmación de raíz se mostrará en la lista TODO de rebase, y puede seleccionar editarla o reformularla:

reword <root commit sha> <original message>
pick <other commit sha> <message>
...

Esta es la explicación de --rootde los docs Git rebase (énfasis mío):

Rebase todas las confirmaciones accesibles desde <branch>, en lugar de limitarlas con un <upstream>. Esto le permite cambiar la base de las confirmaciones de raíz en una rama .

Comunidad
fuente
12

Solo para proporcionar una alternativa a las respuestas mejor calificadas:

Si está creando un repositorio y sabe de antemano que hará un rebase además de su "primer" compromiso real en el futuro, puede evitar este problema por completo haciendo un compromiso vacío explícito al principio:

git commit --allow-empty -m "Initial commit"

y solo entonces comienza a hacer commits "reales". Luego, puede reescribir fácilmente además de ese compromiso de la manera estándar, por ejemplogit rebase -i HEAD^

jakub.g
fuente
44
¿No significa esto que, para que esto funcione, necesita tener la previsión (o ser psíquico) para hacer un compromiso vacío justo al comienzo de su proyecto ? Esto parece ser extremadamente situacional , para mí, y generalmente no práctico . ¿Qué piensas? ¿Qué sucede si ya hice 100 confirmaciones y de repente necesito editar la confirmación raíz? ¿Funcionará esto, en ese caso, si no hice esa confirmación vacía al principio?
2
Editar el mensaje de la confirmación raíz probablemente no sea algo que harías después de tener cientos de ellos. A veces sucede que solo quiero tener un repositorio git, hacer algunos compromisos de mala calidad, sabiendo que una vez que llegue a un estado utilizable, los aplastaré en uno, por ejemplo, y volveré a redactar el mensaje. De todos modos, ahora cambié de opinión y creo que lo más útil para el primer commit sería poner el .gitattributesarchivo en lugar de hacer un commit vacío.
jakub.g
4

Podrías usar git filter-branch:

cd test
git init

touch initial
git add -A
git commit -m "Initial commit"

touch a
git add -A
git commit -m "a"

touch b
git add -A
git commit -m "b"

git log

-->
8e6b49e... b
945e92a... a
72fc158... Initial commit

git filter-branch --msg-filter \
"sed \"s|^Initial commit|New initial commit|g\"" -- --all

git log
-->
c5988ea... b
e0331fd... a
51995f1... New initial commit
Alexander Groß
fuente
Estoy usando filter-branch cambiar el autor / committer, y el -- --all opción de hecho es la clave en este caso para poder manejar también el commit raíz.
sschuberth