最近遇到一個問題:「GitHub 上的 commit 記錄可以證明一定是某人 commit 的嗎?」。
這個問題的答案是:「NO」。
git commit 不似區塊鏈有能力做出無法偽造的記錄,透過不同的方式,我們可以全面的竄改 git commit 的歷史記錄,不論是作者、上傳者或是時間都有辦法可以修改,以下將一一介紹如何操作。
0. 前置作業
首先先在本機建立一個空的 git repo,接著隨意寫入空的檔案:
1 2 3 4 5 |
$ mkdir git–test $ cd git–test $ git init $ touch README.md $ git add README.md |
1. 基本 Git 設定 – 設定識別資料
根據 git 官方的資料,第一次使用 Git 必須要設定識別資料,而且識別資料會影響到提交的結果:「每次Git提交會使用這些資訊,而且提交後不能再被修改」
1 2 |
$ git config —global user.name “John Doe” $ git config —global user.email johndoe@example.com |
2. 基本 Git 操作
透過 git commit
,我們可以提交修改:
1 |
$ git commit –m “Init repo” |
接著使用 git log
,我們可以觀察到剛剛提交的第一個修改:
1 2 3 4 5 6 7 |
$ git log commit f7ff60f96dea61763eb86f575a03890cb1cd49fc Author: John Doe <johndoe@example.com> Date: Wed May 31 22:56:11 2017 +0800 Init repo (END) |
3. 上傳至 GitHub
我們接著將這個 repo 上傳到 GitHub 上面:
1 2 |
$ git remote add origin https://github.com/mlouielu/git-test.git $ git push –u origin master |
觀察一下 GitHub 上面的 commit 記錄:
4. 小結
我們可以用這樣的方式來偽造任何人的 commit 記錄。可是這樣還不滿足。
5. Git commit 修改之 1 – git commit –amend
如果我們想要修改已經 commit 的 commit message,可以透過 --amend
選項來修改。必須要注意的是,透過這樣的方式修改後 git commit hash 會變得與原本不相符:
1 2 3 4 5 6 7 8 9 10 11 12 |
$ git commit —amend [master 55c782f] Amend the commit message Date: Wed May 31 22:56:11 2017 +0800 1 file changed, 0 insertions(+), 0 deletions(–) create mode 100644 README.md $ git log commit 55c782f27309a86763ad7db87e0e7646657584a5 Author: John Doe <johndoe@example.com> Date: Wed May 31 22:56:11 2017 +0800 Amend the commit message (END) |
對比前面的 commit hash 就能看到不同。要上傳到 GitHub 的話會需要 force push:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
$ git push To https://github.com/mlouielu/git-test.git ! [rejected] master -> master (non–fast–forward) error: failed to push some refs to ‘https://github.com/mlouielu/git-test.git’ hint: Updates were rejected because the tip of your current branch is behind hint: its remote counterpart. Integrate the remote changes (e.g. hint: ‘git pull …’) before pushing again. hint: See the ‘Note about fast-forwards’ in ‘git push –help’ for details. $ git push —force Counting objects: 3, done. Writing objects: 100% (3/3), 224 bytes | 0 bytes/s, done. Total 3 (delta 0), reused 0 (delta 0) To https://github.com/mlouielu/git-test.git + f7ff60f...55c782f master -> master (forced update) |
Refresh 一下 GitHub:
恩,訊息理所當然的變更了。
6. Git commit 修改之 2 – git commit –author –date
只修改 commit message 一點都不好玩,接著我想要把 commit 作者還有時間給換掉:
1 2 3 4 5 6 7 8 |
$ git commit —amend —author=“Guido van Rossum <[email protected]>” —date=“Wed Feb 16 14:00 2011 +0100” $ git log commit 8dcabc0a2598b4cc8a8f54e8ff12463fdded21e2 Author: Guido van Rossum <guido@python.org> Date: Wed Feb 16 14:00:00 2011 +0100 Amend the commit message (END) |
--date
的格式支援三種:Git internal format、RFC 2822、ISO 8601,更多資訊請看:Git date formats。
把這個修改成由 Guido van Rossum 在 2011 年的時候 commit 的樣子。推上去後查看 GitHub commit 記錄:
有兩點不太好。第一在 GitHub commit log 的頁面上變成了 gvanrossum commited with John Doe on Feb 16 2011,我希望變成是 Guido 上傳的,而不是 commited with John Doe。第二,repo 首頁的地方 README.md 的修改時間卻顯示為 3 minutes ago ……?應該要是 6 years ago 啊。
7. 看看完整的 Git informations – git cat-file
原來 git log
並不是完整的資訊,完整資訊要使用 git cat-file
才會顯示出來:
1 2 3 4 5 6 |
$ git cat–file –p HEAD tree f93e3a1a1525fb5b91020da86e44810c87a2d7bc author Guido van Rossum <guido@python.org> 1297861200 +0100 committer John Doe <johndoe@example.com> 1496243512 +0800 Amend the commit message |
Author 跟 Committer 是不同的,所以 GitHub 才會顯示為 committed with John Doe。
8. Git commit 修改之 3 – committer
改 committer 很簡單,用 git config
把 user.name 修改就可以了:
1 2 3 4 5 6 7 8 9 |
$ git config user.name “Guido van Rossum” $ git commit —amend $ git cat–file –p HEAD tree f93e3a1a1525fb5b91020da86e44810c87a2d7bc author Guido van Rossum <guido@python.org> 1297861200 +0100 committer Guido van Rossum <guido@python.org> 1496244450 +0800 Amend the commit message |
9. Git commit 修改之 4 – committer date
剩下 Git committer date 需要修改,修改不能使用 --date
來改,這樣只會修改到 Author 的日期。必須要透過 environment variable GIT_COMMITTER_DATE
來做修正:
1 2 3 4 5 6 7 8 9 10 11 |
$ GIT_COMMITTER_DATE=“Wed Feb 16 14:00 2011 +0100” git commit —amend [master f3b5eae] Amend the commit message Date: Wed Feb 16 14:00:00 2011 +0100 1 file changed, 0 insertions(+), 0 deletions(–) create mode 100644 README.md $ git cat–file –p HEAD tree f93e3a1a1525fb5b91020da86e44810c87a2d7bc author Guido van Rossum <guido@python.org> 1297861200 +0100 committer Guido van Rossum <guido@python.org> 1297861200 +0100 Amend the commit message |
GIT_COMMITTER_DATE
一樣可以接受三種格式。
我們把這個結果上傳到 GitHub 上面看看:
恩,commit log 顯示 gvanrossum committed on 16 Feb 2011,而 repo 首頁 README.md 的 commit 時間顯示為 6 years ago。
10. 總結
至此,我們學會了如何從頭到腳修改一個 commit log,可以將 commit 修改成其他人的資訊了。
至於有沒有辦法讓 git commit 變得可信呢?其實是有的,請參考 Git Pro: Signing Your Work,裡面有提到如何使用 GPG 來簽署 Git commit,非常值得一讀。至於被 GPG 簽署過的 commit 在法律上有沒有效力能夠代表一個自然人的所作所為 (GPG key 對應到自然人),這我就不知道了。
Leave a Reply