Mercurial: ¿cómo modificar la última confirmación?

211

Estoy buscando una contraparte de git commit --amenden Mercurial, es decir, una forma de modificar la confirmación a la que está vinculada mi copia de trabajo. Solo me interesa la última confirmación, no una confirmación previa arbitraria.

Los requisitos para este procedimiento de modificación son:

  • si es posible, no debería requerir ninguna extensión. No debe requerir extensiones no predeterminadas , es decir, extensiones que no vienen con una instalación oficial de Mercurial.

  • si el compromiso de enmendar es un jefe de mi rama actual, no se debe crear un nuevo jefe . Si el commit no es head, se puede crear un nuevo head.

  • el procedimiento debe ser seguro de manera que si, por cualquier motivo, la modificación falla, quiero tener la misma copia de trabajo y el mismo estado de repositorio restaurado que antes de la modificación. En otras palabras, si la enmienda misma puede fallar, debe haber un procedimiento a prueba de fallas para restaurar la copia de trabajo y el estado del repositorio. Me refiero a "fallas" que se encuentran en la naturaleza del procedimiento de enmienda (como, por ejemplo, conflictos), no a problemas relacionados con el sistema de archivos (como restricciones de acceso, no poder bloquear un archivo para escritura, ... )

Actualización (1):

  • El procedimiento debe ser automatizable , por lo que puede ser realizado por un cliente GUI sin necesidad de interacción del usuario.

Actualización (2):

  • los archivos en el directorio de trabajo no deben tocarse (puede haber bloqueos del sistema de archivos en ciertos archivos modificados). Esto significa especialmente que un posible enfoque en ningún momento puede requerir un directorio de trabajo limpio.
mstrap
fuente

Respuestas:

289

Con el lanzamiento de Mercurial 2.2 , puede usar la --amendopción hg commitpara actualizar la última confirmación con el directorio de trabajo actual

De la referencia de línea de comando :

El indicador --amend se puede usar para enmendar el padre del directorio de trabajo con un nuevo compromiso que contiene los cambios en el padre además de los informados actualmente por el estado hg, si hay alguno. La confirmación anterior se almacena en un paquete de respaldo en .hg / strip-backup (consulte el paquete de ayuda hg y el paquete de ayuda hg para saber cómo restaurarlo).

El mensaje, el usuario y la fecha se toman de la confirmación modificada a menos que se especifique. Cuando no se especifica un mensaje en la línea de comando, el editor se abrirá con el mensaje de la confirmación modificada.

Lo bueno es que este mecanismo es "seguro", ya que se basa en la característica relativamente nueva "Fases" para evitar actualizaciones que cambiarían el historial que ya está disponible fuera del repositorio local.

Chris Phillips
fuente
2
¡Buena respuesta! La extensión experimental evolve le permite modificar de forma segura los commits que no son head . El antiguo commit se marcará como obsoleto y oculto. Con un servidor que no es de publicación, incluso puede hacerlo de manera segura después de haber presionado los conjuntos de cambios.
Martin Geisler
55
Para actualizar el mensaje en la última confirmación: hg commit --amend -m "este es mi nuevo mensaje"
Jay Sheth
52

Tiene 3 opciones para editar confirmaciones en Mercurial:

  1. hg strip --keep --rev -1deshaga los últimos (1) commit (s), para que pueda hacerlo nuevamente (consulte esta respuesta para obtener más información).

  2. Usando la extensión MQ , que se envía con Mercurial

  3. Incluso si no se envía con Mercurial, vale la pena mencionar la extensión Histedit

También puede echar un vistazo a la página de Historial de edición de la wiki de Mercurial.

En resumen, editar la historia es realmente difícil y desalentado . Y si ya ha presionado sus cambios, apenas hay nada que pueda hacer, excepto si tiene el control total de todos los demás clones.

No estoy realmente familiarizado con el git commit --amendcomando, pero AFAIK, Histedit es lo que parece ser el enfoque más cercano, pero lamentablemente no se envía con Mercurial. MQ es realmente complicado de usar, pero puedes hacer casi cualquier cosa con él.

krtek
fuente
1
No estoy seguro de por qué me perdí la reversión, pero parece hacer (casi) lo que quiero. El único problema es que, cuando un archivo se ha eliminado para mi confirmación original y se ha resucitado para mi confirmación modificada: antes de la reversión se desversará, después de la reversión, se programará para su eliminación (pero el archivo aún existe en el directorio de trabajo)
mstrap
@Marc No estoy seguro de entender tu problema, pero mira el comando olvidar, creo que es lo que estás buscando.
krtek
No creo que "olvidar" sea útil aquí. Aquí está el problema con más detalle: (1) Estoy en la revisión 2 (2) Eliminar "archivo" y tener algunos otros cambios (3) Confirmar cambios, resultando en la revisión 3 (4) Ahora cambiaré de opinión y decidiré "file" no debe eliminarse del commit, por lo que quiero enmendar la revisión 3. Por lo tanto, volveré a agregar "file" que ahora no está versionado (5) Ahora realizo la reversión: restablecerá el directorio y marcará " archivo "como eliminado. (6) Al realizar "hg commit" de nuevo ahora, "archivo" permanecerá como eliminado, aunque ya no debería. ¿Cómo podría ser una solución automática para eso?
mstrap
1
Para la parte automatizada no lo sé, pero puedes hacer hg revert myfilepara deshacer la eliminación. Tal vez volver a agregar con hg addel archivo después de que rollbacktambién funcione.
krtek
3
Estoy de acuerdo en que se debe evitar el historial de edición de los cambios publicados, pero la edición de mi historial local es uno de los aspectos más destacados de un DVCS. MQ con su qimport es pura edición de historia, AFAICT.
mstrap
38

GUI equivalente para hg commit --amend:

Esto también funciona desde la GUI de TortoiseHG (estoy usando v2.5):

Cambie a la vista 'Confirmar' o, en la vista del banco de trabajo, seleccione la entrada 'directorio de trabajo'. El botón 'Confirmar' tiene una opción llamada 'Modificar la revisión actual' (haga clic en la flecha desplegable del botón para encontrarla).

ingrese la descripción de la imagen aquí

          ||
          ||
          \/

ingrese la descripción de la imagen aquí

Advertencia :

Esta opción adicional solo se habilitará si la versión mercurial es al menos 2.2.0, y si la revisión actual no es pública, no es un parche y no tiene hijos. [...]

Al hacer clic en el botón, se llamará 'commit --amend' para 'enmendar' la revisión.

Más información sobre esto en el canal de desarrollo de THG

Cristian Diaconescu
fuente
Muy servicial, gracias. THG es lo suficientemente inteligente como para predeterminar el mensaje de confirmación (enmendar) al mensaje de la confirmación anterior, justo lo que quería.
UuDdLrLrSs
7

Estoy sintonizando lo que Krtek ha escrito. Más específicamente la solución 1:

Suposiciones

  • ha cometido un (!) conjunto de cambios pero aún no lo ha presionado
  • desea modificar este conjunto de cambios (por ejemplo, agregar, eliminar o cambiar archivos y / o el mensaje de confirmación)

Solución:

  • use hg rollbackpara deshacer la última confirmación
  • comprometerse de nuevo con los nuevos cambios en su lugar

La reversión realmente deshace la última operación. Su forma de trabajar es bastante simple: las operaciones normales en HG solo se agregarán a los archivos; Esto incluye un commit. Mercurial realiza un seguimiento de la longitud de los archivos de la última transacción y, por lo tanto, puede deshacer completamente un paso truncando los archivos a sus longitudes anteriores.

Lucero
fuente
1
Gracias por la solución de ajuste (1); solo queda un pequeño problema con la reversión, consulte mi comentario en la solución de krtek.
mstrap
8
Una cosa para enfatizar en la reversión, porque atrapa a las personas, es que es la última transacción en el repositorio que se revierte, no la última confirmación. Entonces, si algo más ha causado una escritura en el repositorio, la reversión no ayudará. Es algo sutil pero importante para recordar. MQ e histedit pueden ayudar una vez que se ha cerrado la ventana de reversión, pero solo hasta cierto punto.
Paul S
7

Suponiendo que aún no ha propagado sus cambios, esto es lo que puede hacer.

  • Agregue a su .hgrc:

    [extensions]
    mq =
    
  • En tu repositorio:

    hg qimport -r0:tip
    hg qpop -a
    

    Por supuesto, no necesita comenzar con la revisión cero o hacer estallar todos los parches, ya que para el último solo basta con un pop ( hg qpop) (ver más abajo).

  • elimine la última entrada del .hg/patches/seriesarchivo o los parches que no le gustan. El reordenamiento también es posible.

  • hg qpush -a; hg qfinish -a
  • elimine los .diffarchivos (parches no aplicados) aún en .hg / parches (debería ser uno en su caso).

Si usted no desea a recuperar todo de su parche, se puede editar mediante el uso hg qimport -r0:tip(o similar), a continuación, editar la materia y el uso hg qrefreshde fusionar los cambios en el parche superior de la pila. Leer hg help qrefresh.

Al editar .hg/patches/series, incluso puede eliminar varios parches o reordenar algunos. Si su última revisión es 99, puede usarla hg qimport -r98:tip; hg qpop; [edit series file]; hg qpush -a; hg qfinish -a.

Por supuesto, este procedimiento es altamente desalentador y arriesgado . ¡Haga una copia de seguridad de todo antes de hacer esto!

Como nota al margen, lo he hecho millones de veces en repositorios privados.

hochl
fuente
También había considerado usar mq-extension, sin embargo, requiere muchas operaciones para las cuales algunas de ellas pueden fallar (por ejemplo, si están involucrados archivos binarios). Además, tener que editar .hg / patch / series no será aceptable, ya que este procedimiento debe usarse dentro de un cliente GUI (he actualizado los requisitos anteriores)
mstrap
Hmmm, lamento que esto no sea para ti, en un repositorio privado esto realmente patea el culo (con copias de seguridad, ya he destruido a un representante con él ^^). Es bastante fresco para combinar los parches en uno antes de empujar los cambios locales utilizando hg qfold, por cierto
Hochl
+1 por usar MQ, pero creo que te has pasado de la raya. Solo pregunta si se modifica la última confirmación. Además, esa importación desaparecerá tan pronto como llegue a una fusión. 'qimport -r tip; <editar cosas>; qrefresh -e; qfin -a 'hará el trabajo (-e para editar el mensaje de confirmación)
Paul S
Es cierto, las fusiones son un problema, por lo general solo uso un parche y lo uso hg import -r<prev>:tip. Una pena que no haya un atajo para la versión anterior, como en subversion.
hochl
2

Las versiones recientes de Mercurial incluyen la evolveextensión que proporciona el hg amendcomando. Esto permite enmendar una confirmación sin perder el historial previo a la modificación en su control de versión.

hg modificar [OPCIÓN] ... [ARCHIVO] ...

alias: actualizar

combinar un conjunto de cambios con actualizaciones y reemplazarlo por uno nuevo

Commits a new changeset incorporating both the changes to the given files
and all the changes from the current parent changeset into the repository.

See 'hg commit' for details about committing changes.

If you don't specify -m, the parent's message will be reused.

Behind the scenes, Mercurial first commits the update as a regular child
of the current parent. Then it creates a new commit on the parent's
parents with the updated contents. Then it changes the working copy parent
to this new combined changeset. Finally, the old changeset and its update
are hidden from 'hg log' (unless you use --hidden with log).

Consulte https://www.mercurial-scm.org/doc/evolution/user-guide.html#example-3-amend-a-changeset-with-evolve para obtener una descripción completa de la evolveextensión.

Karl Bartel
fuente
¡Reutilizar el mismo mensaje de confirmación es una buena característica!
mpen
1

Es posible que no resuelva todos los problemas en la pregunta original, pero dado que esta parece ser la publicación de facto sobre cómo Mercurial puede enmendar la confirmación anterior, agregaré mi información de 2 centavos.

Si eres como yo y solo deseas modificar el mensaje de confirmación anterior (corregir un error tipográfico, etc.) sin agregar ningún archivo, esto funcionará

hg commit -X 'glob:**' --amend

Sin ningún patrón de inclusión o exclusión, se hg commitincluirán por defecto todos los archivos en el directorio de trabajo. La aplicación del patrón -X 'glob:**'excluirá todos los archivos posibles, permitiendo solo modificar el mensaje de confirmación.

Funcionalmente es igual que git commit --amendcuando no hay archivos en el índice / etapa.

kaskelotti
fuente
0

Otra solución podría ser usar el uncommitcomando para excluir un archivo específico de la confirmación actual.

hg uncommit [file/directory]

Esto es muy útil cuando desea mantener la confirmación actual y deseleccionar algunos archivos de la confirmación (especialmente útil para files/directorieshaber sido eliminados).

Sam Liao
fuente