¿Cómo se puede cambiar la marca de tiempo de una confirmación anterior en Git?

747

Las respuestas a ¿Cómo modificar las confirmaciones existentes y no eliminadas? describa una forma de enmendar los mensajes de confirmación anteriores que aún no se han enviado de manera ascendente. Los nuevos mensajes heredan las marcas de tiempo de las confirmaciones originales. Esto parece lógico, pero ¿hay alguna manera de restablecer también los tiempos?

Dhskjlkakdh
fuente
34
git commit --amend --reset-author
Erick M. Sprengel

Respuestas:

536

Úselo git filter-branchcon un filtro env que se establece GIT_AUTHOR_DATEy GIT_COMMITTER_DATEpara el hash específico de la confirmación que desea solucionar.

Esto invalidará eso y todos los hashes futuros.

Ejemplo:

Si desea cambiar las fechas de confirmación 119f9ecf58069b265ab22f1f97d2b648faf932e0, puede hacerlo con algo como esto:

git filter-branch --env-filter \
    'if [ $GIT_COMMIT = 119f9ecf58069b265ab22f1f97d2b648faf932e0 ]
     then
         export GIT_AUTHOR_DATE="Fri Jan 2 21:38:53 2009 -0800"
         export GIT_COMMITTER_DATE="Sat May 19 01:01:01 2007 -0700"
     fi'
Dustin
fuente
44
Ver "FORMATOS DE FECHA" kernel.org/pub/software/scm/git/docs/git-commit.html
Dustin
8
Eso encontró el valor correcto, pero solo establecer esas variables en realidad no parecía afectar la fecha de la confirmación anterior.
IQAndreas
36
¿Qué quiere decir con "Esto invalidará eso y todos los futuros hashes"?
EpicDavi
16
EpicDavi: Significa que tendrá que forzar la inserción en cualquier repositorio remoto, y cualquier persona que haya retirado el compromiso o cualquier compromiso futuro tendrá que reiniciar y extraer, o eliminar y clonar desde cero. Hasta donde yo sé, no hay ningún método que evite esto.
EriF89
44
Solo como una nota para principiantes, el hash corto no funciona en la declaración if, use el largo SHA-1
40 detectives
780

Puede hacer una nueva versión interactiva y elegir editar para la confirmación cuya fecha desea modificar. Cuando el proceso de rebase se detiene para modificar la confirmación que escribe, por ejemplo:

git commit --amend --date="Wed Feb 16 14:00 2011 +0100"

Luego continúas tu rebase interactivo.

ACTUALIZACIÓN (en respuesta al comentario de studgeek): para cambiar la fecha de confirmación en lugar de la fecha del autor:

GIT_COMMITTER_DATE="Wed Feb 16 14:00 2011 +0100" git commit --amend

Las líneas anteriores establecen una variable de entorno GIT_COMMITTER_DATE que se utiliza en la confirmación de modificación.

Todo se prueba en Git Bash.

Paul Pladijs
fuente
22
@nschum --date = "" y --data "sin fecha de texto", todos producen lo mismo, tomando la fecha de ahora.
Paul Pladijs
12
en git versión 1.7.7.1 usando --date = "ahora" da fatal: formato de fecha inválido: ahora
Aragorn
44
Cuando el commit cuya fecha desea cambiar es el commit más reciente, no tiene que hacer el rebase, solo puede hacer elgit commit --amend
Eponymous
77
En lugar de exportar GIT_COMMITTER_DATE = "", intente desarmar GIT_COMMITTER_DATE.
Mark E. Haase,
2
Estoy usando --no-edit para que puedas usarlo en scripts automáticos. + var fixedDate = strftime(new Date(), "%c"); + var result = shelljs.exec("git commit --amend --date=\"" + fixedDate + "\" --no-edit");
Marcello de Sales
392

Una mejor manera de manejar todas estas sugerencias en un comando es

LC_ALL=C GIT_COMMITTER_DATE="$(date)" git commit --amend --no-edit --date "$(date)"

Esto establecerá la última confirmación del commit y la fecha del autor en "ahora mismo".

Luke Ehresman
fuente
22
Esto funciona muy bien para editar confirmaciones específicas durante un rebase interactivo.
Friederbluemle
2
También puede agregar un alias al shell para ello
kaleissin
14
Parece que Git no tiene en cuenta el formato de fecha, por lo que para ser completamente correcto, tendrá que hacer algo como esto:LANG= GIT_COMMITTER_DATE="`date`" git commit --amend --date "`date`"
Michał Góral
Hago eso cuando vuelvo a crear una base y aplasta una rama, por lo que crea una confirmación única con una marca de tiempo actualizada.
Luke Ehresman
12
También puedes simplemente hacer --date "now". Git> = 2 interpretará eso.
wisbucky
189

Solo hazlo git commit --amend --reset-author --no-edit. Para las confirmaciones anteriores, puede hacer una modificación interactiva y elegir editla confirmación cuya fecha desea modificar.

git rebase -i <ref>

Luego, modifique la confirmación con --reset-authory --no-editpara cambiar la fecha del autor a la fecha actual:

git commit --amend --reset-author --no-edit

Finalmente continúe con su rebase interactivo:

git rebase --continue
Gypaetus
fuente
55
buen uso --reset-author, es nuevo en git 1.6.6 (ref gitlog.wordpress.com/2010/01/13/git-1-6-6 )
Tim Abell
1
Esto funciona muy bien para hacer que Github muestre las confirmaciones de un RP modificado en el orden correcto, ya que las ordenan por marca de tiempo y sin este truco, las marcas de tiempo pueden ser todas iguales.
Nathan Long
44
La nota --reset-authorrestablecerá tanto el Autor como la Fecha del autor hasta ahora.
wisbucky
¿cambiará esto la "FECHA DEL COMITÉ" al mismo tiempo?
luochen1990
134

Escribí un script y un paquete Homebrew para esto. Súper fácil de instalar, puedes encontrarlo en la PotatoLabs/git-redatepágina de GitHub .

Sintaxis:

git redate -c 3

Solo tiene que ejecutar git redatey podrá editar todas las fechas en vim de las 5 confirmaciones más recientes (también hay una -copción para la cantidad de confirmaciones que desea volver, solo se establece de manera predeterminada en 5). ¡Avíseme si tiene alguna pregunta, comentario o sugerencia!

ingrese la descripción de la imagen aquí

papa grande
fuente
2
Grandes cosas, a pesar de que tuve que usar vim en lugar de nano
howdoyouturnthison
Gracias @Edmund por un gran guión. No pude ver la fecha para editar en vi después de ejecutar git redate -c. Todo lo que veo es% cI | XXXXXXXXXXXXXXXX | Compromiso inicial. ¿Podrias ayudarme por favor? Gracias
Kiem Nguyen
@KiemNguyen, ¿podrías probar con git redate (sin -c)?
bigpotato
44
completamente de acuerdo con Mina y @howdoyouturnthison aquí, ¿por qué no lo hace independiente del editor a través de la variable de entorno EDITOR? (También estoy en Linux, no en Mac ...)
ympostor
3
Gracias @ Edmund! Por si acaso, su script tiene un problema con el manejo del valor predeterminado para COMMITS. Si no está configurado, el siguiente código aplica filtros solo a (supongo / encontrado) la última confirmación. "git filter-branch -f --env-filter" $ ENVFILTER "HEAD ~ $ COMMITS..HEAD> / dev / null"
Grigory Entin el
104

Cada confirmación está asociada con dos fechas, la fecha de confirmación y la fecha del autor. Puede ver estas fechas con:

git log --format=fuller

Si desea cambiar la fecha del autor y la fecha del confirmador de las últimas 6 confirmaciones, simplemente puede usar una nueva versión interactiva:

git rebase -i HEAD~6

.

pick c95a4b7 Modification 1
pick 1bc0b44 Modification 2
pick de19ad3 Modification 3
pick c110e7e Modification 4
pick 342256c Modification 5
pick 5108205 Modification 6

# Rebase eadedca..5108205 onto eadedca (6 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit

Para todas las confirmaciones en las que desea cambiar la fecha, reemplácelas pickpor edit(o simplemente e), luego guarde y salga de su editor.

Ahora puede modificar cada confirmación especificando la fecha de autor y la fecha de confirmación en formato ISO-8601:

GIT_COMMITTER_DATE="2017-10-08T09:51:07" git commit --amend --date="2017-10-08T09:51:07"

La primera fecha es la fecha de confirmación, la segunda es la fecha del autor.

Luego vaya al siguiente compromiso con:

git rebase --continue

Repita el proceso hasta que modifique todas sus confirmaciones. Comprueba tu progresión con git status.

Ortomala Lokni
fuente
1
¡Seguí esto y terminé en una 'cabeza separada'!
Simon H
1
@ Simon H He probado nuevamente mi respuesta y funciona bien. Deberías haber escrito algo diferente o ya estabas en una cabeza separada. Si desea regresar de una cabeza separada, haga un git checkout name-of-current-branch.
Ortomala Lokni
44
Esta es la mejor y la respuesta más fácil. Un pequeño consejo: el uso --no-edit de git commit --amend --no-edit --date=2017-10-08T09:51:07mantener el viejo mensaje de registro.
Mariusz Pawelski el
2
Es posible que también desee actualizar GIT_COMMITTER_DATE como se describe aquí eddmann.com/posts/…
smihael
2
@smihael Gracias por el enlace. He incluido tu sugerencia en mi respuesta.
Ortomala Lokni
62
git commit --amend --date="now"
Harald Nordgren
fuente
Corto y al grano. Exactamente lo que necesitaba. ¡Gracias!
typoerrpr
44

Sobre la base de la respuesta de theosp , escribí un script llamado git-cdc(para confirmar la fecha de cambio) que puse en mi PATH.

El nombre es importante: git-xxxen cualquier parte de su le PATHpermite escribir:

git xxx
# here
git cdc ... 

Ese script está en bash, incluso en Windows (ya que Git lo llamará desde su entorno msys )

#!/bin/bash
# commit
# date YYYY-mm-dd HH:MM:SS

commit="$1" datecal="$2"
temp_branch="temp-rebasing-branch"
current_branch="$(git rev-parse --abbrev-ref HEAD)"

date_timestamp=$(date -d "$datecal" +%s)
date_r=$(date -R -d "$datecal")

if [[ -z "$commit" ]]; then
    exit 0
fi

git checkout -b "$temp_branch" "$commit"
GIT_COMMITTER_DATE="$date_timestamp" GIT_AUTHOR_DATE="$date_timestamp" git commit --amend --no-edit --date "$date_r"
git checkout "$current_branch"
git rebase  --autostash --committer-date-is-author-date "$commit" --onto "$temp_branch"
git branch -d "$temp_branch"

Con eso, puedes escribir:

git cdc @~ "2014-07-04 20:32:45"

Eso restablecería la fecha de autor / confirmación de la confirmación antes de HEAD ( @~) a la fecha especificada.

git cdc @~ "2 days ago"

Eso restablecería la fecha de autor / confirmación de la confirmación antes de HEAD ( @~) a la misma hora, pero hace 2 días.


Ilya Semenov menciona en los comentarios :

Para OS X también puede instalar GNU coreutils( brew install coreutils), agregarlo a PATH( PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH") y luego usar la 2 days agosintaxis " ".

VonC
fuente
1
Para mí, esto solo funcionó citando la fecha y la hora en una cita: de lo git cdc @~ "2014-07-04 20:32:45contrario, no reconocería la hora y, por lo tanto, obtendría la hora 00:00:00 (se convierte en el tercer argumento).
peschü
3
Para OS X también puede instalar GNU coreutils ( brew install coreutils), agregarlo a PATH ( PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH") y luego usar la sintaxis "Hace 2 días".
Ilya Semenov
1
@IlyaSemenov Interesante. He incluido tu comentario en la respuesta para mayor visibilidad.
VonC
Estoy tratando de usar su primer ejemplo, pero sigo recibiendo "fatal: formato de fecha no válido:". ¿Qué formato de fecha espera Mac OS X?
usbsnowcrash
@usbsnowcrash no estoy seguro en mac. ¿Funciona el segundo ejemplo " 2 days ago"?
VonC
25

Cómo editar varias fechas de confirmación

Otras respuestas no son muy convenientes para editar varias fechas de confirmación. Volví a esta pregunta después de unos años para compartir una técnica.

Para cambiar las fechas de los últimos 4 commits:

git rebase -i HEAD~4

Edite el rebase de la siguiente manera, insertando execlíneas para modificar las fechas según sea necesario:

pick 4ca564e Do something
exec git commit --amend --no-edit --date "1 Oct 2019 12:00:00 PDT"
pick 1670583 Add another thing
exec git commit --amend --no-edit --date "2 Oct 2019 12:00:00 PDT"
pick b54021c Add some tests
exec git commit --amend --no-edit --date "3 Oct 2019 12:00:00 PDT"
pick e8f6653 Fix the broken thing
exec git commit --amend --no-edit --date "4 Oct 2019 12:00:00 PDT"
Matt Montag
fuente
Buen uso de la opción --amend/ --date. Más simple que mi propia respuesta usando variables de entorno. Votado
VonC
¿Es posible usar la fecha / hora actual como parámetro?
reconoce el
Eso GIT_AUTHOR_DATEsolo se actualiza .
Blaise
Re. '? ¿Es posible el uso de la fecha / hora como parámetro': "ahora" se entiende como una fecha válida, por lo que las líneas exec anterior se convertiríaexec git commit --amend --no-edit --date "now"
Andrew Richards
20

si es anterior último commit.

git rebase  -i HEAD~2
git commit --amend --date=now

si ya presionó para iniciar y puede forzar el uso:

git push --force 

si no puede forzar el empuje y si se empuja, ¡no puede cambiar el compromiso! .

Sergio
fuente
18

Aquí hay un alias conveniente que cambia los tiempos de confirmación y autor del último compromiso a un tiempo aceptado por date --date:

[alias]
    cd = "!d=\"$(date -d \"$1\")\" && shift && GIT_COMMITTER_DATE=\"$d\" \
            git commit --amend --date \"$d\""

Uso: git cd <date_arg>

Ejemplos:

git cd now  # update the last commit time to current time
git cd '1 hour ago'  # set time to 1 hour ago

Editar: Aquí hay una versión más automatizada que verifica que el índice esté limpio (sin cambios no confirmados) y reutiliza el último mensaje de confirmación, o falla de otra manera (a prueba de tontos):

[alias]
    cd = "!d=\"$(date -d \"$1\")\" && shift && \
        git diff-index --cached --quiet HEAD --ignore-submodules -- && \
        GIT_COMMITTER_DATE=\"$d\" git commit --amend -C HEAD --date \"$d\"" \
        || echo >&2 "error: date change failed: index not clean!"
Eold
fuente
17

Creé este paquete npm para cambiar la fecha de las confirmaciones anteriores.

https://github.com/bitriddler/git-change-date

Uso de muestra:

npm install -g git-change-date
cd [your-directory]
git-change-date

Se le pedirá que elija la confirmación que desea modificar y luego ingrese la nueva fecha.

Si desea cambiar una confirmación por hash específico, ejecute esto git-change-date --hash=[hash]

Kareem Elbahrawy
fuente
Solo quería decir que esto es genial y funcionó muy bien. ¡Gracias, me has ahorrado mucho tiempo!
paranza
17

La siguiente función bash cambiará la hora de cualquier confirmación en la rama actual.

Tenga cuidado de no usarlo si ya presionó el commit o si lo usa en otra rama.

# rewrite_commit_date(commit, date_timestamp)
#
# !! Commit has to be on the current branch, and only on the current branch !!
# 
# Usage example:
#
# 1. Set commit 0c935403 date to now:
#
#   rewrite_commit_date 0c935403
#
# 2. Set commit 0c935403 date to 1402221655:
#
#   rewrite_commit_date 0c935403 1402221655
#
rewrite_commit_date () {
    local commit="$1" date_timestamp="$2"
    local date temp_branch="temp-rebasing-branch"
    local current_branch="$(git rev-parse --abbrev-ref HEAD)"

    if [[ -z "$date_timestamp" ]]; then
        date="$(date -R)"
    else
        date="$(date -R --date "@$date_timestamp")"
    fi

    git checkout -b "$temp_branch" "$commit"
    GIT_COMMITTER_DATE="$date" git commit --amend --date "$date"
    git checkout "$current_branch"
    git rebase "$commit" --onto "$temp_branch"
    git branch -d "$temp_branch"
}
theosp
fuente
1
Tiene un error allí: if [[ -z "$commit" ]]->if [[ -z "$date_timestamp" ]]
blueFast
¡Agradable! Recomendaría configurar GIT_COMMITTER_DATE=al final del método para evitar más confirmaciones manuales para mantener la fecha especificada.
loopkin
@loopkin, GIT_COMMITTER_DATE está configurado solo para el comando "git commit", por lo que no es necesario borrarlo después
nimrodm
@nimrodm, acabo de probar de nuevo y tienes razón. Gracias por señalar eso.
loopkin
12

Para cambiar tanto la fecha del autor como la fecha de confirmación:

GIT_COMMITTER_DATE="Wed Sep 23 9:40 2015 +0200" git commit --amend --date "Wed Sep 23 9:40 2015 +0200"
Jan H
fuente
10

Si desea obtener la fecha exacta de otra confirmación (supongamos que modificó la edición de una confirmación y desea que tenga la fecha de la versión original anterior):

git commit --amend --date="$(git show -s --format=%ai a383243)"

Esto corrige la fecha de confirmación HEAD para que sea exactamente la fecha de confirmación a383243 (incluya más dígitos si hay ambigüedades). También abrirá una ventana de editor para que pueda editar el mensaje de confirmación.

Eso es para la fecha del autor, que es lo que generalmente le interesa: vea otras respuestas para la fecha de confirmación.

Mr_and_Mrs_D
fuente
7

Si desea realizar la respuesta aceptada ( https://stackoverflow.com/a/454750/72809 ) en la línea de comandos estándar de Windows, necesita el siguiente comando:

git filter-branch -f --env-filter "if [ $GIT_COMMIT = 578e6a450ff5318981367fe1f6f2390ce60ee045 ]; then export GIT_AUTHOR_DATE='2009-10-16T16:00+03:00'; export GIT_COMMITTER_DATE=$GIT_AUTHOR_DATE; fi"

Notas:

  • Es posible dividir el comando en varias líneas (Windows admite la división de líneas con el símbolo carret ^ ), pero no tuve éxito.
  • Puede escribir fechas ISO, ahorrando mucho tiempo para encontrar el día de la semana correcto y la frustración general sobre el orden de los elementos.
  • Si desea que la fecha de Autor y Comprador sea la misma, puede hacer referencia a la variable establecida previamente.

Muchas gracias a una publicación de blog de Colin Svingen . Aunque su código no funcionó para mí, me ayudó a encontrar la solución correcta.

Peter
fuente
7

Si commit aún no se ha presionado, entonces puedo usar algo así:

git commit --amend --date=" Wed Mar 25 10:05:44 2020 +0300"

después de eso, git bash abre el editor con la fecha ya aplicada, por lo que solo necesita guardarlo escribiendo en el modo de comando del editor VI ": wq" y puede presionarlo

Alex Cumarav
fuente
2
Simplemente agregue a la buena respuesta: si no desea editar el mensaje de confirmación (si solo desea cambiar la fecha de confirmación), use la --no-editopción.
Antonio Vinicius Menezes Medei
Además, si el commit ya se ha enviado, aún puede enviar el commit modificado utilizando git push -f(actualización forzada). Sin embargo, eso puede tener efectos secundarios. (especialmente si muchas personas tienen clones locales del repositorio)
Antonio Vinicius Menezes Medei
2

Ya hay muchas respuestas excelentes, pero cuando quiero cambiar la fecha de varias confirmaciones en un día o en un mes, no encuentro una respuesta adecuada. Así que creo un nuevo script para esto con una explicación, espero que ayude a alguien:

#!/bin/bash

# change GIT_AUTHOR_DATE for commit at Thu Sep 14 13:39:41 2017 +0800
# you can change the data_match to change all commits at any date, one day or one month
# you can also do the same for GIT_COMMITTER_DATE

git filter-branch --force --env-filter '

date_match="^Thu, 14 Sep 2017 13+"              

# GIT_AUTHOR_DATE will be @1505367581 +0800, Git internal format 
author_data=$GIT_AUTHOR_DATE;                   
author_data=${author_data#@}                  
author_data=${author_data% +0800}                # author_data is 1505367581     

oneday=$((24*60*60))

# author_data_str will be "Thu, 14 Sep 2017 13:39:41 +0800", RFC2822 format
author_data_str=`date -R -d @$author_data`      

if [[ $author_data_str =~ $date_match ]];
then
    # remove one day from author_data
    new_data_sec=$(($author_data-$oneday))
    # change to git internal format based on new_data_sec
    new_data="@$new_data_sec +0800"             
    export GIT_AUTHOR_DATE="$new_data"
fi
' --tag-name-filter cat -- --branches --tags

La fecha será cambiada:

AuthorDate: Wed Sep 13 13:39:41 2017 +0800
detective0922
fuente