你不知道的 Git 技巧:如何實現核心程式碼保護

語言: CN / TW / HK

theme: smartblue

本文正在參加「金石計劃 . 瓜分6萬現金大獎」

大家好,我是 shixin。

前段時間完成了一個核心程式碼保護的功能,目標在關鍵程式碼被修改及時同步給其他人,避免沒經過 review 就上線導致問題,提示的效果圖如下:

image.png

在實現的過程中,用到一些平時使用不多的 Git 技巧,這篇文章來總結一下。

如何獲取當前提交使用者資訊

這個比較簡單,通過 git config user.name 即可:

04318deMacBook-Pro % git config user.name zhangshixin

git config 儲存了很多配置資訊,其中常用的有自定義快捷鍵、使用者資訊、專案地址、分支資訊等:

``` 504318deMacBook-Pro % git config -l

//快捷鍵 begin >>> 我們可以定義自己的 git 快捷鍵 alias.st=status
alias.co=checkout alias.cb=checkout alias.p=pull alias.pr=pull alias.pu=push alias.cm=commit alias.br=branch alias.cm=commit alias.undo=reset alias.rbc=rebase alias.save=stash alias.pop=stash //快捷鍵 end <<< 我們可以定義自己的 git 快捷鍵

//使用者名稱稱和郵箱 begin >>> user.name=zhangshixin [email protected] //使用者名稱稱和郵箱 end <<<

//專案和分支資訊 begin >>> [email protected]:android/xxx.git remote.origin.fetch=+refs/heads/:refs/remotes/origin/ branch.master.remote=origin branch.master.merge=refs/heads/master branch.Canary.remote=origin branch.Canary.merge=refs/heads/Canary //專案和分支資訊 end <<<

pull.rebase=true //預設 pull 是 merge 還是 rebase ```

如何獲取當前分支

為了減少提示頻率,最好只檢測核心的分支的提交(包括 merge commit)。如何獲取當前分支呢?有一個簡單的方式:

git symbolic-ref --short HEAD

這句命令主要包括兩個關鍵字:symbolic-refHEAD

symbolic-ref 可以讀取、修改和刪除符號引用。

什麼是符號引用呢?它表示一個以 refs 開頭的檔案(比如 refs/heads/develop),這個檔案儲存著本地每個分支當前所處 commit。

我們可以開啟 git 專案的 .git 資料夾,在其中的 refs/heads 資料夾中會儲存各個分支當前所指向的 commit:

HEAD 指的是 .git/HEAD,就是一個檔案,儲存著當前指向的符號引用:

因此 git symbolic-ref --short HEAD 的含義就是讀取 .git/HEAD 檔案的內容,我這裡就是 refs/heads/develop 檔案,因此就得出當前分支是 develop 分支。

如何獲取本地未 push 的所有 commit

有時候我們會在本地提交多次後再 push,因此在攔截 push 時,需要獲取到當前要 push 的所有 commit 資訊,然後獲取每個 commit 修改的檔案。

獲取要 push 資訊可以通過 git log @{u}.. --oneline:

504318deMacBook-Pro ShixinDemo % git log @{u}.. --oneline 4e4655b (HEAD -> master) 攔截跳轉 f947180 修改檔案

git log 非常強大,它可以有這些使用場景: 1. 獲取本地和遠端的 commit 差異 2. 獲取指定時間內的提交記錄,可以具體到誰、什麼時候、修改了哪些 3. 獲取具體某次提交修改的檔案

上面我們使用的引數 @{u}.. 就是表示獲取本地和遠端的 commit 差異,然後 --oneline 表示不列印具體資訊,只打印 short commit id 和 commit message。

如果要獲取指定時間內的提交記錄,可以這樣: git log --pretty="%an(%cd) %h - %s" --since="2022-09-01" --no-merges --name-status

命令執行結果: ``` 504318deMacBook-Pro ShixinDemo % git log --pretty="%an(%cd) %h - %s" --since="2022-09-01" --no-merges --name-status zhangshixin(Fri Dec 16 22:34:49 2022 +0800) 4e4655b - 攔截跳轉

M app/src/main/java/com/example/heicdemo/MainActivity.kt zhangshixin(Fri Dec 16 22:34:30 2022 +0800) f947180 - 修改檔案

M .idea/gradle.xml M .idea/misc.xml D .idea/runConfigurations.xml A android10_dem_heic_output.heic A app/src/main/assets/android10_dem_heic_output.heic R100 app/src/main/res/drawable/mushroom.jpg app/src/main/assets/mushroom.jpg A app/src/main/assets/mushroom.webp M app/src/main/java/com/example/heicdemo/MainActivity.kt A app/src/main/res/drawable/mushroom.webp M app/src/main/res/layout/activity_main.xml

```

pretty 的引數用於指定列印的內容和格式;since 引數用於指定檢視時間範圍;no-merges 表示過濾掉 merge 時生成的額外 commit;name-status 表示展示出檔案的修改狀態(M 表示修改;D 表示刪除;A 表示增加;R 表示重新命名)。

如何獲取每個 commit 修改的檔案

知道 commit ID 後,可以通過 git show --pretty="" --name-only $commitId 獲取這個 commit 影響的資訊:

04318deMacBook-Pro ShixinDemo % git show --pretty="" --name-only 4e4655b app/src/main/java/com/example/shixindemo/MainActivity.kt

git show 可以用來檢視 commit 的 commit message 和修改的檔案、檔案具體內容等資訊。上面的程式碼中我們使用了 name-only 引數表示只要檢視修改的檔案即可。

總結

這篇文章介紹了通過攔截 git push 時,獲取當前使用者、當前分支、未 push 的 commit 和修改的檔案等命令,通過組合這些命令,就可以實現一個核心程式碼保護功能了!