分享一個我看源碼時的小技巧。
- 2022 年 5 月 9 日
- 筆記
你好呀,我是歪歪。
我在之前的文章裏面不是經常叫大家拉源碼,然後看代碼提交記錄嗎。
也就是看類似於這個界面:

比如上面這個界面中,就可以看到 RedissonBaseLock.java 這個文件,由誰在什麼時候進行過變更,以及變更對應的 commit 信息是什麼。
這樣就能很直觀的看到文件的演變過程。
那麼問題就來了,有好幾個同學都問過我這個問題:怎麼在 idea 裏面查看 git 提交記錄呢?這個界面是藏在哪裡的呢,我的 idea 裏面怎麼沒有呢?
好的,是我疏忽了,我先入為主的認為這個大家應該都知道是怎麼來的。
但是確實是有一些同學是不太清楚的,那我這篇文章就給大家分享一下我通過這個東西看源碼的一點點小技巧,希望能幫助到你。

怎麼搞出來?
那麼怎麼把這個視圖搞出來呢?
首先,你本地得有一個 git.exe。
這個玩意怎麼來的,就不用我說了吧,如果連這個都沒有,說明你之前還沒有接觸過 git,那就是另外一回事兒了,不在本文討論範圍內。趕緊去安裝一個 git,然後學學 git 的用法啥的。
我個人的習慣是先用 gitbash,也就是這個玩意,從 github 上 clone 一個項目下來:

比如我就用之前寫文章的 Redssion 做演示吧,你也可以隨便找一個自己感興趣的開源項目。
執行下面命令把項目下載下來:
git clone //github.com/redisson/redisson.git

下載完成之後,打開你的 idea,導入我們剛剛下載的項目。
然後隨便打開一個文件,點擊右鍵,看看有沒有 Git 這個選項:

如果順利的話,你點擊 ShowHistory 之後,就能看到這個窗口了:

如果不順利,說明你的 git 配置有問題。
在 idea 的 Settings 裏面進行對應的設置:

設置完成之後,可以點擊旁邊的 test 按鈕,如果有彈窗告訴你對應的版本號,那就說明配置成功了:

總之,只要能調出 Version Control 標籤頁或者有的高版本裏面就叫做 git,就代表配置成功了。
怎麼看?
不管是在工作中還是寫文章的時候,我一般在 idea 裏面只是看提交記錄,我不會用 idea 裏面的 git 去做提交代碼的動作。
其實 idea 裏面拉取代碼,提交代碼什麼的可視化頁面做的很好,但是我還是比較喜歡直接在 gitbash 裏面敲命令,也沒有什麼特別的原因,只是這樣顯得逼格高而已。
那麼,到底怎麼去看呢?
以我之前寫的 Redisson 文章為例。
主要是圍繞着 RedissonLock.java 這個類在寫,我是怎麼知道這個類的呢?
其實自己帶着問題去 debug 也肯定能定位到這個類,但是需要一點時間。
我以前就是搭完環境之後,就開始瘋狂的寫案例 debug 了。
現在我學聰明了,環境搞定之後,先去 github 的 issues 裏面拿着關鍵詞去搜一下。
比如我的關鍵詞就是死鎖:

但是我強烈建議你別用中文搜索,用英文,deadLock:

這樣能搜出來的信息就很多,剩下的就是你一個個點開,看看是不是和自己遇到的問題一樣,或者相似。
這個過程會花一點點時間,但是絕對比你一頭扎進源碼裏面找答案快的多。
比如,上面的截圖中,最後一個叫 Deadlock after Redis timeout 的 issue,就是我想要找的東西:

在這個裏面給出了復現的代碼,涉及的版本,以及預期的結果和實際的表現。
比如說我找到這個鏈接之後,對我而言就是找到了一個測試用例,同時他告訴了我一個命令:
CLIENT PAUSE 5000
在這之前,我是不知道這個命令的。我還一直在想,我做 Demo 復現的時候,應該怎麼去模擬 Redis 執行命令超時的現象呢?
我當時能想到的一些方案就是 bigkey,或者灌很多數據進去,然後我執行 keys * 命令,再或者搞個 save 命令,這樣來模擬 Redis 阻塞。
但是,這都是有工作量且阻塞時間不可控的。而這個命令直接解決了我這個問題,至少讓我少走了幾步彎路吧。
同樣,這個 issues 裏面還關聯了幾個其他的 issues ,這些都是官方認為是同一個原因造成的問題:

然後怎麼解決的呢?
常規來說,他們應該關聯一個 pr,通過這個 pr 我就能直接關聯到對應的修復的內容。
但是這次他們搞了一個騷操作,直接先弄了一個 SNAPSHOT 版本,並沒有關聯 pr:

怎麼辦?
這個時候我想去看他是怎麼修復這個問題的,怎麼辦?

前面提到的 idea 裏面的 git 插件就派上用場了。
首先,從他的評論時間我知道是 2019 年 3 月 13 號,那麼我可以直接在工具裏面定位到那一天提交的內容。
點擊 Version Control 視圖裏面的 Log 標籤,就可以看到整個項目歷史上的所有的提交,它會按照時間的順序給你排好序,所有很容易就找到了當天的相關的提交:

你要是覺得難得找,也可以直接通過日期進行過濾:

從當天提交的這個 commit 信息來看,就知道我找對地方了。
而這裡就只是修改了 RedissonLock.java 這個類,所以我就找到了這個關鍵的類:

然後點進去再分析一下這個類具體的修改,這樣算是找到了 debug 的時候我應該重點關注的地方。
又比如看門狗失效的那個 bug:
//github.com/redisson/redisson/issues/3714

在這裏面,就是直接關聯了一個 pr,然後我們可以通過這個鏈接,找到提交的代碼,也可以找到其對應的 issues。

這玩意屬於雙向奔赴了。
而且我也能知道這次提交對應的類叫做 RedissonBaseLock.java:

那我又可以回到 idea 的視圖裏面,直接看看這個類的提交記錄了:

一看才發現,這個哥們一共提交了三次。而且還發現這個類還挺年輕的, 2021 年 1 月 21 日才首次提交。
我之前在《踩到一個關於分佈式鎖的非比尋常的BUG!》這篇文章裏面留了個思考題:

就是由這三次提交引起的。
我帶你看一下這三次提交分別是什麼。
首先第一次提交,加入了 else 分支,裏面執行了一次 cancelExpirationRenewal 方法,入參是 threadId。

含有是把當前線程的重入次數減一。
但是能走到 else 分支裏面來有個大前提是給鎖續命的 lua 腳本返回 false,也就是說這個鎖都沒了。
鎖都沒了,還維護重入次數幹啥呢?
直接從 MAP 裏面把這個對象拿掉就行了。
怎麼拿掉呢?
傳入 null 就可以了:

所以,才有了第二次提交,把入參從 threadId 修改為 null:

那麼第三次提交又是幹啥呢?

是不是完全看不出來是幹啥?
別急,我這樣給你上個截圖你就懂了:

之前是用的 tab 製表符,後來修改為四個空格。這是編碼風格的問題。
提到用 tab 還是用空格,這又是另外一個在編程領域裏面爭論不止的話題了。
我記得之前我看過一個美劇,叫做《硅谷》。裏面的主人公就因為到底應該用 tab 還是用空格和女朋友吵了一架。
然後…

我寫文章的時候還想起了一個無聊的問題,並且去尋找到了答案。
我想知道 Redisson 是在什麼時候引進看門狗機制的,我想看看這個狗子最開始的模樣。
我怎麼找的呢?
首先我知道啟動看門狗的代碼是位於 RedissonLock.java 中的 renewExpiration 這個方法:

那我就在 RedissonLock.java 的歷史提交記錄裏面用找一下 renewExpiration 這個方法什麼時候是第一次提交的就行了。
於是我很快就找到了 2019 年 3 月 13 日的這次:

我才發現原來看門狗還換過名字,它之前叫做 scheduleExpirationRenewal,後來才改名叫 renewExpiration。
很顯然,我覺得新名字更好。
然後我就繼續找 scheduleExpirationRenewal 是什麼時候第一次出現的,我找啊找啊,找到了 2015 年 12 月 14 日的這次提交:

好傢夥,這個狗子還有個叫做 newRefreshTask 的曾用名啊。
最終,找到了 newRefreshTask 第一次出現的地方,就是 2015 年 7 月 4 日:

這就是看門狗的生日,距離今天不到兩個月了,我提前祝它生日快樂。

但是,我不得不吐槽一句。
關於看門狗的這一次提交,提交了非常多的東西。可以在這次提交上右鍵,然後點擊下面框起來的選項:

就能看到這次提交的所有東西:

提交了 31 個文件,其中包含了看門狗機制。
但是提交的 commit 信息非常簡陋,只體現了因為涉及到事務操作,所以使用了 LUA 腳本的這一個特性。
這就是一個非常不好的 commit 提交示例。
但是你轉念一想,你每次提交的時候示例是怎麼寫的,是不是也經常偷懶。
別問我是怎麼知道。

所以,每次提交的 commit 信息還是要認真寫的,因為你要知道,總是有我這樣無聊的人,會去翻一些沒啥卵用的知識點出來。
比如我問你,我找看門狗機制的這段描述,除了讓你知道它的生日和幾個曾用名之外還有什麼卵用嗎?
是的,沒有。
恭喜你又學到了一個沒啥卵用的知識點。
再來一個
我再帶你看一個項目,Dubbo。
還是按照我前面說的,把項目拉下來,然後點擊這裡的 log,就可以看到整個項目歷史上的所有提交:

拉到最下面,可以找到歷史上第一次提交的情況:

第一次提交是梁飛在 2011 年 10 月 20 日 23 點 04 分提交的。
但是從提交的 commit 信息來看,我們也知道這是一次空提交。
真正的第一次提交是 2 分鐘之後的 23 點 06 分:

9 個模塊,共計 669 個文件,就是日後這個一路坎坎坷坷、幾近夭折、友商續命,最終成為 Apache 頂級開源項目的雛形。
11 年前的 10 月 20 日,梁飛從晚上 23 點干到了凌晨 5 點 25 分,終於給 Dubbo 打上了第一個里程碑 tag:2.0.7。

期間,還發佈了一個微博:

而他自己,第二天的中午,也在自己的博客上公布了這件事情:
//www.iteye.com/blog/javatar-1206888

為什麼 Dubbo 會選在這一天進行開源呢?
我想應該是為了趕上兩天之後的 Qcon 全球軟件開發者大會:

那一天,才是 Dubbo 真正意義上,站在大眾視野里,接受讚揚與嘲諷的開始。
在 idea 的視圖裏面,還可以過濾指定的人提交的記錄。
比如梁飛就用過下面這幾個賬號提交代碼:

我過濾了一下,發現多達 1294 次,最後一次提交在 2015 年 4 月 1 日:

而且我還發現他特別能肝,類似這樣時間點的提交記錄有好幾處:



然後我還找了幾個類,想看看經過 10 多年的發展,這些類中還留下多少他的代碼。
首先我給你看看這個負載均衡策略相關的類 AbstractLoadBalance.java。
在這個類上右鍵,然後選擇 git->Annotate 就可以調出左邊的(時間-用戶)的視圖:

這就表示的是當前這個類,每一行代碼是誰在什麼時候提交的。
還是可以看到梁飛的身影。
而且我給你看看這個:

這個方法是 Dubbo 啟動的時候,給新機器預熱,一點點的給權重。第一分鐘給 10% 的流量,第二分鐘給 20% 的流量…第十分鐘這個時候機器基本上已經經過充分的預熱,所以可以給到 100% 的流量。
至於為什麼要預熱呢,這個就和 JVM 相關了,你如果感興趣的話,可以去研究一下。
就是這個功能,這一個核心方法,經過 10 多年時間,除了一點微調,其核心算法、核心邏輯沒有發生一點變化。
再比如,我給你看看最少活躍數負載均衡策略的實現 LeastActiveLoadBalance.java:

從初始化提交之後,一共就沒修改過幾次。
但是你要知道每次提交都是有它的意義的,比如這兩次:

一次提交是把變量 leastIndexs 修改為 leastIndexes,因為 index 是 x 結尾的,以 s、x、sh、ch 結尾的名詞,它的複數形式應該是加 es。這是一個英語小知識。

一次提交是把 Random 替換為 ThreadLocalRandom,因為後者性能更好,這是編程小知識,背後的原因是值得深挖的。就看有沒有有心人了。
你也可以對比一下,初始版本和當前最新的版本,核心算法、核心邏輯基本沒有發生變化:

這兩個類告訴我一個什麼道理?
比起業務代碼的增刪改查,只有算法,穩定的算法才是更容易再歲月的長河中留下來的,而且歷久彌新。
然後,再回到 log 的標籤中,你會發現一個很奇怪的現象。
整個 2014 年到 2015 年,都沒有提交過幾次代碼:

其實從 2013 年開始到 2017 年基本上就沒多少提交了。
這是為什麼呢?
這就不得不說一下 Dubbo 坎坷的一生了。
前面說了,2011 年它是屬於出生豪門,從阿里開源走了出來。
但是在 2012 年 10 月 23 日,Dubbo 2.5.3 發佈後,阿里就基本上停止了對於 Dubbo 的維護升級。
然後一直到 2017 年 9 月 7 日,Dubbo 悄悄在 GitHub 發佈了 2.5.4 版本。隨後,又迅速發佈了 2.5.5、2.5.6、2.5.7 等版本。在 10 月舉行的雲棲大會上,阿里宣布 Dubbo 被列入集團重點維護開源項目,這也就意味着 Dubbo 起死回生,開始重新進入快車道。
在 2012 年到 2017 年這五年間,噹噹網自己拉了一個 Dubbox 的分支開搞,相當於幫 Dubbo 把命給續住了。
2018 年 1 月 8 日,Dubbo 2.6.0 版本發佈,新版本將之前噹噹網開源的 Dubbox 進行了合併,實現了 Dubbo 版本的統一整合。
然後 2018 年 2 月,阿里巴巴宣布將 Dubbo 捐獻給 apache,進入 apache 孵化器。
2019 年 5 月 21 號,經過了漫長的孵化期,Dubbo 迎來了畢業。成為Apache基金會頂級項目。
之後的故事你應該也就知道了,Dubbo 現在都搞到 3.0 了,準備在雲原生的賽道上發力。
所以你看,這妥妥的就是一個爽文的套路啊。
這就是一個富家子弟不慎流落街頭,被人收養,悉心照料,最後在一片驚呼中,又重回巔峰的故事啊。
那麼這個故事告訴了我們一個什麼道理呢?
它告訴我們,有個好爸爸真的是太好了。要是 Dubbo 不是阿里開源出來的,起死回生是很難了,對半已經是消失在歷史的長河中了。
話說回來,前面提到的這些東西,都是可以由我這篇文章給你提到的這個 idea 的視圖衍生出來的。
而且我只是給你介紹了一些非常常規的用法,你可以自己去挖掘出更適合你自己的關注點。
這玩意,平時自己沒事,拉個自己感興趣的項目下來,看看提交記錄,看看新特性。
就像我前面說的,每次提交都是有它的意義的,有的提交背後是值得深挖的,就看有沒有有心人了。
你說,這玩意難道不比小說好看嗎?

歡迎關注公眾號why技術,第一時間接收最新文章。