更改 git commit 時間

最近剛好需要更改 git repo 的 commit time ,研究了一下順便把它記錄下來。

首先需要知道的是,在 git 裡,因為 commit 是可以被修改的,在一個 commit 裡其實會記錄 authorcommitterauthor 就是寫 code 的人, committer 則是真正提交 code 的人,

用法大概是:對某個你不是 maintainer 的 project ,你寫了一個新功能,然後用 git format-patch 生出了 patch ,接著你把這個 patch 送給 maintainer ,在 maintainer 決定採用你的 patch 之後,用 git apply 來採用你的 commit ,接著他再 git commit , code 才進到 repo 裡,這個新 commit 的 author 就是你, committer 就是真的做 git commit 的那個 maintainer 。

為什麼改 commit 時間,會要知道 git 裡的 author 和 committer 呢?因為在更改 commit 時間時,如果沒有特別注意的話,會只改到 commit time ,並且該 commit 的 committer 會變成自己,原本的 author 資訊和 author time 會保留下來,所以如果不想讓人發現曾經改過 commit 的話,必須把 committer 設成原本的 author ,也要把 author time 改成想要的 commit time 。

知道這些之後大概就沒問題了,可以用 git filter-branch (http://git-scm.com/docs/git-filter-branch) 來做:

Script & Setup

[~/modify-commit-time] ➟  ls
modify_commit_time.sh*
[~/modify-commit-time] ➟  cat modify_commit_time.sh
# clear previous backup
rm -rf "$(git rev-parse --git-dir)/refs/original/"

commit="$1"
date=$(date -d "$2" +%s)
git filter-branch --env-filter \
    "if [ \$GIT_COMMIT = '$commit' ]; then
         export GIT_AUTHOR_DATE='$date'
         export GIT_COMMITTER_DATE='$date'
         export GIT_COMMITTER_NAME="\$GIT_AUTHOR_NAME"
         export GIT_COMMITTER_EMAIL="\$GIT_AUTHOR_EMAIL"
     fi"
[~/modify-commit-time] ➟  git init
Initialized empty Git repository in /home/dm4/modify-commit-time/.git/
(master) [~/modify-commit-time] ➟  git add modify_commit_time.sh
(master) [~/modify-commit-time] ➟  git commit -m 'add script'
[master (root-commit) 9c4c1d0] add script
 1 file changed, 12 insertions(+)
 create mode 100755 modify_commit_time.sh
(master) [~/modify-commit-time] ➟  echo '# Hello' > README.md
(master) [~/modify-commit-time] ➟  git add README.md
(master) [~/modify-commit-time] ➟  git commit -m 'add README'
[master a2913a7] add README
 1 file changed, 1 insertion(+)
 create mode 100644 README.md

可以看到現在有兩個 commit

(master) [~/modify-commit-time] ➟  git log --pretty=fuller
commit a2913a7c39977dd3c4f99f8cabc6fae5b3694cb2
Author:     dm4 <test@example.com>
AuthorDate: Sun Apr 19 16:48:33 2015 +0000
Commit:     dm4 <test@example.com>
CommitDate: Sun Apr 19 16:48:33 2015 +0000

    add README

commit 9c4c1d0b4499683ab0ba80dd7041b477c0adb2f0
Author:     dm4 <test@example.com>
AuthorDate: Sun Apr 19 16:48:33 2015 +0000
Commit:     dm4 <test@example.com>
CommitDate: Sun Apr 19 16:48:33 2015 +0000

    add script

Modify Commit Time

(master) [~/modify-commit-time] ➟  ./modify_commit_time.sh 9c4c1d0b4499683ab0ba80dd7041b477c0adb2f0 '3 month ago'
Rewrite a2913a7c39977dd3c4f99f8cabc6fae5b3694cb2 (2/2)
Ref 'refs/heads/master' was rewritten

Result

(master) [~/modify-commit-time] ➟  git log --pretty=fuller
commit 9552b631000134921a75f173fa7313c1a90cb96e
Author:     dm4 <test@example.com>
AuthorDate: Sun Apr 19 16:48:33 2015 +0000
Commit:     dm4 <test@example.com>
CommitDate: Sun Apr 19 16:48:33 2015 +0000

    add README

commit 67e6f5a501703e98f8d9711ade8ab3a51775c265
Author:     dm4 <test@example.com>
AuthorDate: Mon Jan 19 16:49:02 2015 +0000
Commit:     dm4 <test@example.com>
CommitDate: Mon Jan 19 16:49:02 2015 +0000

    add script

這裡可以看到雖然只改了 add script 的 commit ,但是連 add README 的 commit id 也變了,這是因為 git 在算 hash 的時候,也會包含 parent 的 commit id ,所以 parent 的 commit id 變了,所有的 child commit id 都會跟著變,這個在寫 script 批次處理的時候需要注意一下。

Support Me