Como alguém pode alterar o registro de data e hora de um commit antigo no Git?


747

As respostas para Como modificar confirmações existentes e não enviadas? descreva uma maneira de alterar as mensagens de confirmação anteriores que ainda não foram enviadas a montante. As novas mensagens herdam os carimbos de data e hora das confirmações originais. Isso parece lógico, mas existe uma maneira de também redefinir os horários?



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

Respostas:


535

Use git filter-branchcom um filtro env que define GIT_AUTHOR_DATEe GIT_COMMITTER_DATEpara o hash específico do commit que você deseja corrigir.

Isso invalidará esse e todos os futuros hashes.

Exemplo:

Se você quiser alterar as datas da confirmação 119f9ecf58069b265ab22f1f97d2b648faf932e0, poderá fazê-lo com algo como isto:

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'


8
Isso encontrou o valor correto, mas apenas a definição dessas variáveis ​​não pareceu afetar a data da confirmação antiga.
IQAndreas

36
O que você quer dizer com "Isso invalidará esse e todos os futuros hashes".
EpicDavi

16
EpicDavi: Isso significa que você precisará forçar o envio para qualquer repositório remoto, e qualquer pessoa que tenha retirado a confirmação ou qualquer confirmação futura terá que redefinir e retirar, ou excluir e clonar do zero. Até onde eu sei, não existe um método que contorna isso.
EriF89

4
Assim como uma observação para iniciantes, o hash curto não funciona na instrução if, use o longo SHA-1
40detectives

780

Você pode fazer uma nova reformulação interativa e escolher editar para o commit cuja data você deseja alterar. Quando o processo de rebase parar para alterar a confirmação, você digita, por exemplo:

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

Posteriormente, você continua sua recuperação interativa.

UPDATE (em resposta ao comentário de studgeek): para alterar a data de confirmação em vez da data do autor:

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

As linhas acima definem uma variável de ambiente GIT_COMMITTER_DATE que é usada na alteração de confirmação.

Tudo é testado no Git Bash.


22
@nschum --date = "" e --data "non-date-text" produzem o mesmo, levando a data de agora.
Paul Pladijs

12
no git versão 1.7.7.1 usando --date = "now" fornece fatal: formato de data inválido: now
Aragorn

4
Quando o commit cuja data você deseja alterar é o commit mais recente, você não precisa fazer o rebase, você pode simplesmente fazer ogit commit --amend
Eponymous

7
Em vez de exportar GIT_COMMITTER_DATE = "", tente desabilitar GIT_COMMITTER_DATE.
Mark E. Haase

2
Estou usando --no-edit para que você possa usar em scripts automatizados! + var fixedDate = strftime(new Date(), "%c"); + var result = shelljs.exec("git commit --amend --date=\"" + fixedDate + "\" --no-edit");
Marcello de Sales

392

Uma maneira melhor de lidar com todas essas sugestões em um comando é

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

Isso definirá a data de confirmação e autor do último commit como "agora".


22
Isso funciona muito bem para editar confirmações específicas durante um rebase interativo.
Friederbluemle

2
Você pode adicionar um alias para o shell para ele também
kaleissin

14
Parece que o Git não reconhece o formato de data da localidade; portanto, para estar completamente correto, você terá que fazer algo assim: #:LANG= GIT_COMMITTER_DATE="`date`" git commit --amend --date "`date`"
Michał Góral

Faço isso ao refazer e compactar uma ramificação para criar uma única confirmação com um carimbo de data / hora atualizado.
Luke Ehresman

12
você também pode fazer --date "now". Git> = 2 interpretará isso.
wisbucky

189

Apenas faça git commit --amend --reset-author --no-edit. Para confirmações mais antigas, você pode fazer uma nova reformulação interativa e escolher edita confirmação cuja data você deseja modificar.

git rebase -i <ref>

Em seguida, altere o commit com --reset-authore --no-editpara alterar a data do autor para a data atual:

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

Por fim, continue com o seu rebase interativo:

git rebase --continue

5
boa chamada sobre o uso --reset-author, é nova no git 1.6.6 (ref gitlog.wordpress.com/2010/01/13/git-1-6-6 )
Tim Abell

1
Isso funciona muito bem para fazer o Github mostrar os commits de um PR recuperado na ordem correta, uma vez que eles os ordenam por carimbo de data e hora e sem esse truque, os carimbos de hora podem ser os mesmos.
Nathan Long

4
A nota --reset-authorredefinirá o autor e a data do autor para agora.
23818 wisbucky

isso mudará a "DATA DE COMISSÃO" ao mesmo tempo?
luochen1990 16/04

134

Eu escrevi um script e um pacote Homebrew para isso. Super fácil de instalar, você pode encontrá-lo na PotatoLabs/git-redatepágina do GitHub .

Sintaxe:

git redate -c 3

Você só precisa executar git redatee poderá editar todas as datas no vim dos 5 commits mais recentes (também há uma -copção para quantos commits você deseja voltar, o padrão é 5). Deixe-me saber se você tiver quaisquer perguntas, comentários ou sugestões!

insira a descrição da imagem aqui


2
Grandes coisas, embora eu tive que usar vim ao invés de nano
howdoyouturnthison

Obrigado a Edmund por um ótimo roteiro. Não consegui ver a data para editar no vi depois de executar o git redate -c. Tudo o que vejo é% cI | XXXXXXXXXXXXXXXX | Confirmação inicial. Poderia ajudar por favor? Obrigado
Kiem Nguyen

@KiemNguyen você poderia tentar apenas redit git (sem o -c)?
Bigpotato 22/04

4
Concordo completamente com Mina e @howdoyouturnthison aqui, por que você não o torna independente de editor via variável de ambiente EDITOR? (também estou no linux, não no mac ...)
ympostor

3
Obrigado @Edmund! Por precaução, seu script tem um problema ao lidar com o valor padrão para COMMITS. Se não estiver definido, o código a seguir aplica filtros apenas para (eu acho / encontrei) o último commit. "git filter-branch -f --env-filter" $ ENVFILTER "HEAD ~ $ COMMITS..HEAD> / dev / null"
Grigory Entin

103

Cada confirmação está associada a duas datas, a data do confirmador e a data do autor. Você pode ver essas datas com:

git log --format=fuller

Se você deseja alterar a data do autor e a data do consolidador dos últimos 6 confirmados, você pode simplesmente usar um rebase interativo:

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 as confirmações nas quais você deseja alterar a data, substitua pickpor edit(ou apenas e) e salve e saia do seu editor.

Agora você pode alterar cada confirmação especificando a data do autor e a data do commit no formato ISO-8601:

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

A primeira data é a data de confirmação, o segundo é a data do autor.

Em seguida, vá para o próximo commit com:

git rebase --continue

Repita o processo até alterar todos os seus commits. Verifique sua progressão com git status.


1
Eu segui isso e acabei com uma 'cabeça desanexada'!
Simon H

1
@ Simon H Testei novamente minha resposta e funciona bem. Você deveria ter digitado algo diferente ou já estava com uma cabeça desapegada. Se você quiser voltar de uma cabeça separada, faça a git checkout name-of-current-branch.
Ortomala Lokni

4
Essa é a melhor e a resposta mais fácil. Uma pequena dica: use --no-edit em git commit --amend --no-edit --date=2017-10-08T09:51:07manter a antiga mensagem de confirmação.
Mariusz Pawelski 16/04/19

2
Você também pode querer atualização GIT_COMMITTER_DATE , conforme descrito aqui eddmann.com/posts/...
smihael

2
@smihael Obrigado pelo link. Incluí sua sugestão na minha resposta.
Ortomala Lokni 31/07


44

Com base theosp 's resposta , escrevi um script chamado git-cdc(data de alteração para cometer) que eu coloquei no meu PATH.

O nome é importante: git-xxxem qualquer lugar do seu PATHcomputador, você pode digitar:

git xxx
# here
git cdc ... 

Esse script está no bash, mesmo no Windows (já que o Git o chamará do ambiente 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"

Com isso, você pode digitar:

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

Isso redefiniria a data de autor / confirmação do commit antes de HEAD ( @~) para a data especificada.

git cdc @~ "2 days ago"

Isso redefiniria a data de autor / confirmação do commit antes de HEAD ( @~) para a mesma hora, mas 2 dias atrás.


Ilya Semenov menciona nos comentários :

No OS X, você também pode instalar o GNU coreutils( brew install coreutils), adicioná-lo a PATH( PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH") e usar a " 2 days ago" sintaxe.


1
Para mim, isso funcionou apenas citando a data e a hora em uma citação: git cdc @~ "2014-07-04 20:32:45caso contrário, não reconheceria a hora e, portanto, obteria a hora 00:00:00 (torna-se o terceiro argumento).
peschü 12/11/14

3
Para o OS X, você também pode instalar o GNU coreutils ( brew install coreutils), adicioná-lo ao PATH ( PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH") e usar a sintaxe "2 dias atrás".
Ilya Semenov

1
@IlyaSemenov Interesting. Incluímos seu comentário na resposta para obter mais visibilidade.
VonC 04/12/2015

Estou tentando usar o seu primeiro exemplo, mas continuo recebendo "fatal: formato de data inválido:". Que formato de data o Mac OS X espera?
usbsnowcrash

@usbsnowcrash não tenho certeza no mac. O segundo exemplo " 2 days ago" funciona?
VonC

25

Como editar várias datas de confirmação

Outras respostas não são muito convenientes para editar várias datas de confirmação. Voltei a esta questão depois de alguns anos para compartilhar uma técnica.

Para alterar as datas dos 4 últimos commits:

git rebase -i HEAD~4

Edite a rebase da seguinte maneira, inserindo execlinhas para modificar as datas conforme necessário:

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"

Bom uso da opção --amend/ --date. Mais simples do que minha própria resposta usando variáveis ​​de ambiente. Votado.
VonC 30/10/19

É possível usar a data / hora atual como parâmetro?
accfews 08/12/19

Isso atualiza GIT_AUTHOR_DATEapenas.
Blaise

Ré. 'É possível usar a data / hora atual como parâmetro?': "Now" é entendido como uma data válida, para que as linhas de execução acima se tornemexec git commit --amend --no-edit --date "now"
Andrew Richards

20

se for o último commit anterior.

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

se você já pressiona a orgin e pode forçar o uso:

git push --force 

se você não pode forçar o push e se for pressionado, não pode alterar o commit! .


18

Aqui está um alias conveniente que altera os tempos de confirmação e autor da última confirmação para um horário aceito por date --date:

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

Uso: git cd <date_arg>

Exemplos:

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

Edit: Aqui está uma versão mais automatizada que verifica se o índice está limpo (sem alterações não confirmadas) e reutiliza a última mensagem de confirmação ou falha de outra forma (à prova de falhas):

[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!"

17

Eu criei este pacote npm para alterar a data de confirmações antigas.

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

Uso da amostra:

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

Você será solicitado a escolher o commit que deseja modificar e inserir a nova data.

Se você deseja alterar um commit por hash específico, execute este git-change-date --hash=[hash]


Eu só queria dizer que isso é ótimo e funcionou lindamente. Obrigado, você me salvou muito tempo!
paranza 26/04

17

A seguinte função bash mudará o horário de qualquer confirmação na ramificação atual.

Tenha cuidado para não usar se você já enviou o commit ou se o usa em outro ramo.

# 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"
}

1
Você tem um bug lá: if [[ -z "$commit" ]]->if [[ -z "$date_timestamp" ]]
blueFast

Agradável! Eu recomendaria definir GIT_COMMITTER_DATE=no final do método para impedir que mais confirmações manuais mantenham a data especificada.
loopkin

@loopkin, GIT_COMMITTER_DATE está definido apenas para o comando "git commit", portanto não há necessidade de limpá-lo posteriormente
nimrodm

@nimrodm, acabei de testar novamente e você está correto. Obrigado por apontar isso.
loopkin 27/04

12

Para alterar a data do autor e a data de confirmação:

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

10

Se você deseja obter a data exata de outra confirmação (digamos que você reformulou a edição de uma confirmação e deseja que ela tenha a data da versão original de pré-recuperação):

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

Isso corrige a data do commit HEAD para ser exatamente a data do commit a383243 (inclua mais dígitos se houver ambiguidades). Também será exibida uma janela do editor para que você possa editar a mensagem de confirmação.

Essa é a data do autor, que é o que você costuma cuidar - veja outras respostas para a data do committer.


7

Se você deseja executar a resposta aceita ( https://stackoverflow.com/a/454750/72809 ) na linha de comando padrão do Windows, você precisa do seguinte 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:

  • Pode ser possível dividir o comando em várias linhas (o Windows oferece suporte à divisão de linhas com o símbolo carret ^), mas não obtive êxito.
  • Você pode escrever datas ISO, economizando muito tempo encontrando o dia da semana certo e a frustração geral acima da ordem dos elementos.
  • Se você deseja que a data do Autor e do Committer seja a mesma, basta referenciar a variável definida anteriormente.

Muito obrigado a um post de Colin Svingen . Mesmo que o código dele não funcionasse para mim, ele me ajudou a encontrar a solução correta.


7

Se o commit ainda não foi enviado, posso usar algo assim:

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

depois disso, o git bash abre o editor com a data já aplicada, então você precisa salvá-lo digitando no modo de comando do editor VI ": wq" e pode pressioná-lo


2
Apenas adicionando à boa resposta: se você não quiser editar a mensagem de confirmação (se quiser alterar a data de confirmação), use a --no-editopção
Antonio Vinicius Menezes Medei 15/01

Além disso, se a confirmação já tiver sido enviada por push, você ainda poderá enviar por push a confirmação alterada usando git push -f(atualização forçada). Isso pode ter efeitos colaterais, no entanto. (especialmente se muitas pessoas tiverem clones locais do repositório)
Antonio Vinicius Menezes Medei 15/01


2

Já existem muitas ótimas respostas, mas quando quero alterar a data para várias confirmações em um dia ou em um mês, não encontro uma resposta adequada. Então, eu crio um novo script para isso com explicações, espero que ajude alguém:

#!/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

A data será alterada:

AuthorDate: Wed Sep 13 13:39:41 2017 +0800
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.