Monday 23 July 2018

How to reset date timestamps for one or more git commits

How to reset date timestamps for one or more git commits
Typically, when making changes, I try to git commit as soon as I finish making changes. This way, when trying to track down regression days later, I can correlate regression with my change commit timestamps. The other day though, I made some changes, rsynced changed scripts over to the server, tested for regression, but it wasn't till days later that regression evidence surfaced. When I looked at my git logs and realized that I hadn't commited that change, I wanted to commit with the date of the change (by default, only the commit date will be used). This turned out to be a bit harder than I thought, so I'm documenting the steps for future reference.

Supply custom timestamp during commit

Git makes it easy to commit with the author date in the past by simply supplying custom date by adding "--date=" to the commit command. I could grab the file modification time and pass that along with the commit in one step, like in the following example:
Create a test file:
$ echo "my test file" > test
The file will of course have the current time as last modified:
$ ll test
-rw-rw-r-- 1 ak ak 13 2013-01-05 15:46 test
So I'll change the file's modification date to 30 hours ago:
$ touch -d "30 hours ago" test
$ ll test
-rw-rw-r-- 1 ak ak 13 2013-01-04 09:45 test
To pass the file's modification time in the commit command, I could do:
$ git add test
$ git commit --date="$(stat -c %y test)" -m "testing" test
[master ad1edba] testing
 1 file changed, 1 insertion(+)
 create mode 100644 test
Now, git log will show AuthorDate as the actual last modified time of the file, while CommitDate will show the time of the commit (it's also possible to modify both the AuthorDate and CommitDate, see below):
$ git --no-pager log -1 --stat --pretty=fuller
commit 8bd33981737bbc665804db59ed7e7124d0c8e949
Author:     ak@loon
AuthorDate: Fri Jan 4 09:38:03 2013 -0800
Commit:     ak@loon
CommitDate: Sat Jan 5 15:39:03 2013 -0800

    testing

 test |    1 +
 1 file changed, 1 insertion(+)

Modify/Reset timestamp for already committed change

The above works great for uncommitted changes, but what if you committed the changes and would like to modify the AuthorDate time? Again, git makes that easy for the last commit:
$ git commit --amend --date='' -C HEAD

Modify/Reset timestamps for several already committed changes

But what if you need to go back several commits? I ran into this situation as well and used the following Bash script to reset the AuthorDate time, here's what it does.
For a list of files, it will get the hash of the last commit for each file, get the last modification date of the file, then reset the author timestamp to the file's actual modification date. Be sure to run it from the toplevel of the working tree (git will complain if you don't).
files="
foo.txt
bar.txt
"

for file in $files; do
  dir=""; commit=""; date="";
  dir=$(dirname $(find -name $file))
  commit=$(git --no-pager log -1 --pretty=%H -- path "$dir/$file")
  date="$(stat -c %y $dir/$file)"
  if [ -z "$commit" ] || [ -z "$date" ]; then
    echo "ERROR: required var \$commit or \$date is empty"
  else
    echo "INFO: resetting authorship date of commit '$commit' for file '$dir/$file' to '$date'"
    git filter-branch --env-filter \
      "if test \$GIT_COMMIT = '$commit'; then
         export GIT_AUTHOR_DATE
         GIT_AUTHOR_DATE='$date'
       fi" &&
    rm -fr "$(git rev-parse --git-dir)/refs/original/"
  fi
  echo
done
You could use the above script to reset both the AuthorDate and CommitDate (just add GIT_COMMITTER_DATE to the code above using the example from the Reference below). Though modifying the CommitDate for shared repositories sounds messy as you could be confusing others.
References:

0 comments:

Post a Comment