Comment peut-on changer l'horodatage d'un ancien commit dans Git?


747

Les réponses à Comment modifier les validations existantes et non poussées? décrire un moyen de modifier les messages de validation précédents qui n'ont pas encore été poussés en amont. Les nouveaux messages héritent des horodatages des validations d'origine. Cela semble logique, mais existe-t-il un moyen de réinitialiser également les temps?



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

Réponses:


536

À utiliser git filter-branchavec un filtre env qui définit GIT_AUTHOR_DATEet GIT_COMMITTER_DATEpour le hachage spécifique de la validation que vous cherchez à corriger.

Cela invalidera cela et tous les hachages futurs.

Exemple:

Si vous souhaitez modifier les dates de validation 119f9ecf58069b265ab22f1f97d2b648faf932e0, vous pouvez le faire avec quelque chose comme ceci:

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
Cela a trouvé la valeur correcte, mais le simple fait de définir ces variables ne semble pas réellement affecter la date de l'ancien commit.
IQAndreas

36
Que voulez-vous dire par «Cela invalidera cela et tous les hachages futurs»?
EpicDavi

16
EpicDavi: Cela signifie que vous devrez forcer le push vers n'importe quel référentiel distant, et quiconque ayant tiré le commit ou tout futur commit devra réinitialiser et tirer, ou supprimer et cloner à partir de zéro. Pour autant que je sache, il n'existe aucune méthode permettant de contourner ce problème.
EriF89

4
Tout comme une note pour les débutants, le hachage court ne fonctionne pas dans l'instruction if, utilisez le long SHA-1
40detectives

780

Vous pouvez effectuer un rebase interactif et choisir de modifier le commit dont vous souhaitez modifier la date. Lorsque le processus de rebase s'arrête pour modifier la validation que vous tapez par exemple:

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

Ensuite, vous continuez votre rebase interactif.

UPDATE (en réponse au commentaire de studgeek): pour changer la date de commit au lieu de la date de l'auteur:

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

Les lignes ci-dessus définissent une variable d'environnement GIT_COMMITTER_DATE qui est utilisée pour modifier la validation.

Tout est testé dans Git Bash.


22
@nschum --date = "" et --data "non-date-text" produisent tous la même chose, en prenant la date de maintenant.
Paul Pladijs

12
sur git version 1.7.7.1 en utilisant --date = "now" donne fatal: format de date invalide: maintenant
Aragorn

4
Lorsque le commit dont vous voulez changer la date est le commit le plus récent, vous n'avez pas à faire le rebase, vous pouvez simplement faire legit commit --amend
Éponyme

7
Au lieu d'exporter GIT_COMMITTER_DATE = "", essayez de désactiver GIT_COMMITTER_DATE.
Mark E. Haase

2
J'utilise --no-edit pour que vous puissiez l'utiliser dans des scripts automatisés! + var fixedDate = strftime(new Date(), "%c"); + var result = shelljs.exec("git commit --amend --date=\"" + fixedDate + "\" --no-edit");
Marcello de Sales

392

Une meilleure façon de gérer toutes ces suggestions dans une seule commande est

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

Cela définira la date de validation et d'auteur du dernier commit sur "dès maintenant".


22
Cela fonctionne très bien pour modifier des validations spécifiques lors d'un rebase interactif.
friederbluemle

2
Vous pouvez aussi ajouter un alias à la coque
kaleissin

14
Il semble que Git ne soit pas au courant du format de date, donc pour être complètement correct, vous devrez en faire quelque chose comme ceci:LANG= GIT_COMMITTER_DATE="`date`" git commit --amend --date "`date`"
Michał Góral

Je le fais lorsque je rebase et écrase une branche, donc cela crée un seul commit avec un horodatage mis à jour.
Luke Ehresman

12
vous pouvez aussi le faire --date "now". Git> = 2 interprétera cela.
wisbucky

189

Faites-le git commit --amend --reset-author --no-edit. Pour editles validations plus anciennes, vous pouvez effectuer une rebase interactive et choisir la validation dont vous souhaitez modifier la date.

git rebase -i <ref>

Modifiez ensuite le commit avec --reset-authoret --no-editpour remplacer la date de l'auteur par la date actuelle:

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

Enfin, poursuivez votre rebase interactif:

git rebase --continue

5
bon appel à l'utilisation --reset-author, c'est nouveau dans git 1.6.6 (ref gitlog.wordpress.com/2010/01/13/git-1-6-6 )
Tim Abell

1
Cela fonctionne bien pour que Github affiche les commits d'un PR rebasé dans le bon ordre, car ils les classent par horodatage et sans cette astuce, les horodatages peuvent tous être les mêmes.
Nathan Long

4
Remarque --reset-authorréinitialise à la fois l'auteur et la date de l'auteur.
wisbucky

cela changera-t-il la "DATE ​​D'ENGAGEMENT" en même temps?
luochen1990

134

J'ai écrit un script et un package Homebrew pour cela. Super facile à installer, vous pouvez le trouver sur la PotatoLabs/git-redatepage GitHub .

Syntaxe:

git redate -c 3

Il vous suffit d'exécuter git redateet vous pourrez modifier toutes les dates dans vim des 5 derniers commits (il y a aussi une -coption pour le nombre de commits que vous souhaitez revenir en arrière, il est juste 5 par défaut). Faites-moi savoir si vous avez des questions, des commentaires ou des suggestions!

entrez la description de l'image ici


2
Super truc, même si je devais utiliser vim plutôt que nano
howdoyouturnthison

Merci @Edmund pour un excellent script. Je n'ai pas pu voir la date à modifier dans vi après avoir exécuté git redate -c. Tout ce que je vois c'est% cI | XXXXXXXXXXXXXXXX | Validation initiale. S'il te plait peux-tu aider? Merci
Kiem Nguyen

@KiemNguyen pourriez-vous essayer juste git redate (sans le -c)?
bigpotato

4
complètement d'accord avec Mina et @howdoyouturnthison ici, pourquoi ne pas le rendre éditeur agnostique via la variable d'environnement EDITOR? (aussi je suis sur linux, pas mac ...)
ympostor

3
Merci @Edmund! Juste au cas où, votre script a un problème avec la gestion de la valeur par défaut pour COMMITS. S'il n'est pas défini, le code suivant applique des filtres uniquement (je suppose / trouve) au dernier commit. "git filter-branch -f --env-filter" $ ENVFILTER "HEAD ~ $ COMMITS..HEAD> / dev / null"
Grigory Entin

104

Chaque commit est associé à deux dates, la date du commiteur et la date de l'auteur. Vous pouvez consulter ces dates avec:

git log --format=fuller

Si vous souhaitez modifier la date d'auteur et la date de validation des 6 derniers validations, vous pouvez simplement utiliser un rebase interactif:

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

Pour toutes les validations où vous souhaitez modifier la date, remplacez pickpar edit(ou tout simplement e), puis enregistrez et quittez votre éditeur.

Vous pouvez maintenant modifier chaque commit en spécifiant la date de l'auteur et la date du commit au format ISO-8601:

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

La première date est la date de validation, la seconde est la date de l'auteur.

Passez ensuite au commit suivant avec:

git rebase --continue

Répétez le processus jusqu'à ce que vous modifiiez tous vos commits. Vérifiez votre progression avec git status.


1
J'ai suivi cela et je me suis retrouvé sur une «tête détachée»!
Simon H

1
@Simon H J'ai testé à nouveau ma réponse et cela fonctionne bien. Vous auriez dû taper quelque chose de différent ou vous étiez déjà dans une tête détachée. Si vous voulez revenir d'une tête détachée, faites a git checkout name-of-current-branch.
Ortomala Lokni le

4
C'est la meilleure et la plus simple réponse. Petit conseil: utilisez --no-edit in git commit --amend --no-edit --date=2017-10-08T09:51:07pour conserver l'ancien message de validation.
Mariusz Pawelski

2
Vous pouvez également mettre à jour GIT_COMMITTER_DATE comme décrit ici eddmann.com/posts/…
smihael

2
@smihael Merci pour le lien. J'ai inclus votre suggestion dans ma réponse.
Ortomala Lokni


44

Sur la base de la réponse de theosp , j'ai écrit un script appelé git-cdc(pour changer la date de validation) que j'ai mis dans monPATH .

Le nom est important: git-xxxn'importe où dans votre PATHclavier vous permet de taper:

git xxx
# here
git cdc ... 

Ce script est en bash, même sous Windows (puisque Git l'appellera depuis son environnement 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"

Avec cela, vous pouvez taper:

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

Cela réinitialiserait la date auteur / validation du commit avant HEAD ( @~) à la date spécifiée.

git cdc @~ "2 days ago"

Cela réinitialiserait la date auteur / validation de la validation avant HEAD ( @~) à la même heure, mais il y a 2 jours.


Ilya Semenov mentionne dans les commentaires :

Pour OS X, vous pouvez également installer GNU coreutils( brew install coreutils), l'ajouter à PATH( PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH") puis utiliser la 2 days agosyntaxe " ".


1
Pour moi, cela ne fonctionnait qu'en citant la date et l'heure en une seule citation: git cdc @~ "2014-07-04 20:32:45sinon, il ne reconnaîtrait pas l'heure et donc obtiendrait l'heure 00:00:00 (cela devient le troisième argument).
peschü

3
Pour OS X, vous pouvez également installer GNU coreutils ( brew install coreutils), l'ajouter à PATH ( PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH") puis utiliser la syntaxe "il y a 2 jours".
Ilya Semenov

1
@IlyaSemenov Intéressant. J'ai inclus votre commentaire dans la réponse pour plus de visibilité.
VonC

J'essaie d'utiliser votre premier exemple mais je reçois toujours "fatal: format de date invalide:". Quel format de date Mac OS X attend-il?
usbsnowcrash

@usbsnowcrash pas sûr sur mac. Le deuxième exemple " 2 days ago" fonctionne-t-il?
VonC

25

Comment modifier plusieurs dates de validation

Les autres réponses ne sont pas très pratiques pour modifier plusieurs dates de validation. Je suis revenu sur cette question après quelques années pour partager une technique.

Pour modifier les dates des 4 derniers commits:

git rebase -i HEAD~4

Modifiez le rebase comme suit, en insérant des execlignes pour modifier les dates au besoin:

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"

Belle utilisation de l' option --amend/ --date. Plus simple que ma propre réponse en utilisant des variables d'environnement. A voté.
VonC

Est-il possible d'utiliser la date / heure actuelle comme paramètre?
accfews

Cela se met à jour GIT_AUTHOR_DATEuniquement.
Blaise

Ré. « Est - il possible d'utiliser la date / heure actuelle comme paramètre »: « maintenant » est comprise comme une date valide, de sorte que les lignes ci - dessus exec deviendraitexec git commit --amend --no-edit --date "now"
Andrew Richards

20

s'il s'agit du dernier commit précédent.

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

si vous poussez déjà en orgin et pouvez forcer l'utilisation:

git push --force 

si vous ne pouvez pas forcer la poussée et si elle est poussée, vous ne pouvez pas changer le commit! .


18

Voici un alias pratique qui change les heures de validation et de création de la dernière validation en une heure acceptée par date --date:

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

Usage: git cd <date_arg>

Exemples:

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

Edit: Voici une version plus automatisée qui vérifie que l'index est propre (pas de modifications non validées) et réutilise le dernier message de validation, ou échoue dans le cas contraire (infaillible):

[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

J'ai créé ce package npm pour changer la date des anciens commits.

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

Exemple d'utilisation:

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

Vous serez invité à choisir le commit que vous souhaitez modifier puis à saisir la nouvelle date.

Si vous souhaitez modifier une validation par hachage spécifique, exécutez cette git-change-date --hash=[hash]


Je voulais juste dire que c'était génial et fonctionnait magnifiquement. Merci, vous m'avez fait gagner beaucoup de temps!
paranza

17

La fonction bash suivante changera l'heure de tout commit sur la branche courante.

Attention à ne pas l'utiliser si vous avez déjà poussé le commit ou si vous utilisez le commit dans une autre branche.

# 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
Vous avez un bug là-dedans: if [[ -z "$commit" ]]->if [[ -z "$date_timestamp" ]]
blueFast

Agréable! Je recommanderais de définir GIT_COMMITTER_DATE=à la fin de la méthode pour empêcher toute autre validation manuelle de conserver la date spécifiée.
loopkin

@loopkin, GIT_COMMITTER_DATE est défini juste pour la commande "git commit" donc pas besoin de l'effacer par la suite
nimrodm

@nimrodm, je viens de tester à nouveau et vous avez raison. Merci d'avoir fait remarquer cela.
loopkin

12

Pour modifier à la fois la date de l'auteur et la date de validation:

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

10

Si vous souhaitez obtenir la date exacte d'un autre commit (supposons que vous rebasiez un commit modifié et que vous vouliez qu'il ait la date de la version originale de pré-rebase):

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

Cela corrige la date de la validation HEAD pour être exactement la date de la validation a383243 (inclure plus de chiffres s'il y a des ambiguïtés). Il fera également apparaître une fenêtre d'éditeur afin que vous puissiez modifier le message de validation.

C'est pour la date de l'auteur, ce qui vous intéresse généralement - voir les autres réponses pour la date du committer.


7

Si vous souhaitez effectuer la réponse acceptée ( https://stackoverflow.com/a/454750/72809 ) dans la ligne de commande Windows standard, vous avez besoin de la commande suivante:

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"

Remarques:

  • Il peut être possible de fractionner la commande sur plusieurs lignes (Windows prend en charge le fractionnement de ligne avec le symbole carret ^ ), mais je n'ai pas réussi.
  • Vous pouvez écrire des dates ISO, gagner beaucoup de temps à trouver le bon jour de la semaine et une frustration générale sur l'ordre des éléments.
  • Si vous souhaitez que la date de l'auteur et de la personne responsable soit la même, vous pouvez simplement référencer la variable précédemment définie.

Merci beaucoup à un article de blog de Colin Svingen . Même si son code ne fonctionnait pas pour moi, il m'a aidé à trouver la bonne solution.


7

Si le commit n'est pas encore poussé, je peux utiliser quelque chose comme ça:

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

après que git bash ouvre l'éditeur avec la date déjà appliquée, il vous suffit de l'enregistrer en tapant dans le mode de commande de l'éditeur de VI ": wq" et vous pouvez le pousser


2
Ajout juste à la bonne réponse: si vous ne voulez pas éditer le message de validation (si vous voulez juste changer la date de validation), utilisez l' --no-editoption.
Antonio Vinicius Menezes Medei

De plus, si le commit a déjà été poussé, vous pouvez toujours pousser le commit modifié à l'aide de git push -f(mise à jour forcée). Cela peut cependant avoir des effets secondaires. (surtout si beaucoup de gens ont des clones locaux du référentiel)
Antonio Vinicius Menezes Medei


2

Il y a déjà beaucoup de bonnes réponses, mais quand je veux changer la date de plusieurs validations en une journée ou en un mois, je ne trouve pas de bonne réponse. Je crée donc un nouveau script pour cela avec explication, j'espère que cela aidera quelqu'un:

#!/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 date sera modifiée:

AuthorDate: Wed Sep 13 13:39:41 2017 +0800
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.