9

I'm converting an old CVS repository to git, which has worked very well except all the commits are in UTC instead of each author's local timezone.

I would like to change the timezone of these commits on a per-author basis, so for example all commits from one author change from +0000 to +1000, while commits from other authors are unchanged. (So I can perform this procedure once for each author.)

The actual moment in time should stay the same, so a commit that is currently 02:00:00 +0000 should become 12:00:00 +1000.

Is this possible with something like git filter-branch?

Malvineous
  • 25,144
  • 16
  • 116
  • 151

2 Answers2

6

I've come up with this, which seems to do the trick:

git filter-branch --env-filter '
    if [ "$GIT_AUTHOR_EMAIL" == "email@example.com" ]; then
        export GIT_AUTHOR_DATE=`echo $GIT_AUTHOR_DATE | sed s/+0000/+1000/`
    fi
    if [ "$GIT_COMMITTER_EMAIL" == "email@example.com" ]; then
        export GIT_COMMITTER_DATE=`echo $GIT_COMMITTER_DATE | sed s/+0000/+1000/`
    fi'

This changes the timezone for author email@example.com from +0000 to +1000. If the timezone is already something else in a given commit then it will be left unchanged. In the event that this person was the author but not the committer (or vice-versa), only the date for their role will be updated.

It won't handle changing UTC offsets due to DST as @MattJohnson pointed out, but perhaps you can add additional criteria for that if needed.

This works by taking advantage of git's internal date format, which is always measured in seconds since the epoch and looks like @12345 +0000. The timezone here is not used (the number of seconds is always in UTC) which allows you to alter the timezone without changing the effective moment in time that is being referenced. Changing the UTC offset here only affects the default formatting of the date.

Malvineous
  • 25,144
  • 16
  • 116
  • 151
  • The echo required some quoting here, I ended up with: `GIT_AUTHOR_DATE=$(echo "$GIT_AUTHOR_DATE" | sed s/+0000/+1000/)` – Matt Aug 24 '22 at 23:28
6

In addition to @Malvineous' answer:

If it's okay to use the current user's timezone as a reference, you can use Git to do the DST conversion. This did the trick for me, fixing all commits' timezones to the current timezone, including DST change.

git filter-branch --env-filter '
  if [ "$GIT_AUTHOR_EMAIL" == "email@example.com" ]; then
    GIT_AUTHOR_DATE=`echo $GIT_AUTHOR_DATE|sed -e "s/[+-][0-9]\{4\}//g"`
  fi
  if [ "$GIT_COMMITTER_EMAIL" == "email@example.com" ]; then
    GIT_COMMITTER_DATE=`echo $GIT_COMMITTER_DATE|sed -e "s/[+-][0-9]\{4\}//g"`
  fi
'

The sed line strips off the timezone. GIt takes care of the rest.

Please note that this does not support an explicit timezone as initially requested, but takes care of DST.

NOTE: The original answer had an additional lines using date, e.g.,

GIT_AUTHOR_DATE=`date --date=$GIT_AUTHOR_DATE`

However, this is not necessary because handles uses the current timezone (including DST) when none is specified. Therefore, chopping the timezone is sufficient.

Joseph K. Strauss
  • 4,683
  • 1
  • 23
  • 40
Thomas Jacob
  • 618
  • 6
  • 12
  • 1
    Not sure what is meant by "DST conversion" here, but when I ran it in the winter with TZ=Europe/London it converted all times to UTC (+0000) and did not handle the fact that some of the commits had been last summer when London was using British Summer Time. (I have been trying to sort out a repository that I've been committing to from a server in the US which was set to a US time zone and I would rather have my local British time recorded on the commit.) – Silas S. Brown Mar 01 '18 at 10:42