天天看點

記錄一次無聊的(經曆了Nodejs -> Shell -> C)的探索問題過程

提出問題

在運作項目的伺服器的git是1.8.3.1版本的時候,pm2 deploy 項目,伺服器fetch不到最新的一次commit。

對于這個問題,在pm2的github也有issues讨論。然後開issues的人表示 pm2-deploy is garbage  并且覺得  I find it funny that it is easier for the authors to blame the problem on git or anything else rather than change one single line of code to make it work... excelent pm2 deploy couldn't be any more wonderfull.  em…   呵呵,表示不服,其實這個問題真的有一半原因得歸咎于git …

解決方案(針對伺服器上git版本 < 1.9.0)

1. 更新伺服器git版本 >= 1.9.0

2. 回退pm2版本至1.x,如果該項目用不到pm2 後期版本的一些功能的話...

由于文章中的測試驗證過程略顯無聊(一步一步的挖掘問題所在),且以上已給出解決方案,有遇到類似問題的小夥伴可參考方案解決問題,有興趣交流下debugger過程的同學可繼續往下看。

git都出了2.14.1了,為什麼還在用1.8.3.1的老版本呢?

我們用的是阿裡雲的伺服器,使用yum安裝的git包,然而yum源裡的git包是1.8.3.1的,對于像我這種的新手來說,要不是遇到問題,我的态度是 "還有這操作? (。◕ˇ∀ˇ◕)"

進入探索流程

問題由pm2出發,首先我們找到pm2是怎麼處理deploy指令的:

于是打開該Deploy.js:

由此,我們又将查找對象指向了pm2-deploy子產品的Deploy對象

好了,現在到了shell了...

打開deploy的sh檔案 => 找到deploy方法(所幸作者打了閃閃發光的注釋,很簡單的我們就找到哪裡是重點):

好了,看出差別了, git fetch --all  和  git fetch --depth=5 --all --tags 

于是上git官網查這2個參數,然後失望而歸,官網文檔最老版本僅能找到1.9.0的,那麼怎麼辦?

大家來找茬 + 推測 --tags 參數的描述可能是導緻問題的關鍵 :refspec(Reference Specification/參考規範,這裡個人覺得了解為本地和遠端的對應關系更适合),1.8.3.1 的說這個操作是基于明确的映射關系滴,是以預設的映射關系将被覆寫并且不被使用。

那麼到底是不是refspecs存在問題呢? 還是明明是 remotes tags 存在問題導緻不能fetch到?先測試看看結果,不同版本、不同參數的 git fetch 測試:

初始化

建立檔案 test.txt 内容為 test > 3

push 到 test 分支

伺服器 pull 代碼,確定test.txt檔案存在且内容值為 test > 3

如圖:

記錄一次無聊的(經曆了Nodejs -> Shell -> C)的探索問題過程

1.8.3.1版本測試:

修改test.txt 為 test > 4

伺服器上執行 git fetch --all --tags --depth=5

效果如圖:

記錄一次無聊的(經曆了Nodejs -> Shell -> C)的探索問題過程

輸出 test > 3

接下來去掉--tags 參數試試

伺服器上執行 git fetch --all --depth=5

記錄一次無聊的(經曆了Nodejs -> Shell -> C)的探索問題過程

輸出 test > 4

結果正确(但由于沒有--tags參數,其實并沒有拉取到所有tags)

人為指定映射關系,驗證是不是因為 --tags 影響refspec而導緻問題

到這裡,對于問題而言我們确定了是 --tags 導緻fetch不到最新代碼,但不能确定是refspec的問題,那麼接着下一步的驗證:

修改test.txt 為 test > 5

push 代碼

伺服器上執行 git fetch origin test:refs/remotes/origin/test --depth=5 --all --tags

記錄一次無聊的(經曆了Nodejs -> Shell -> C)的探索問題過程

英文版報錯:fetch --all does not take a repository argument

那麼暫時去掉 --all ,接下去驗證猜想

伺服器上執行 git fetch origin test:refs/remotes/origin/test --depth=5 --tags

記錄一次無聊的(經曆了Nodejs -> Shell -> C)的探索問題過程

輸出 test > 5

結果正确

2.7.4版本測試 

修改test.txt 為 test > 6

伺服器上執行 git fetch --depth=5 --all --tags

記錄一次無聊的(經曆了Nodejs -> Shell -> C)的探索問題過程

輸出 test > 6

結論:1.8.3.1 版本 git fetch --depth=5 --all --tags  的時候由于加了--tags 導緻refspec出現問題

1.8.3.1版本裡的 fetch 做了什麼導緻refspec不正确呢?

上面是加了列印測試的代碼,并未修改其邏輯,然後編譯 => 配置 => 運作試試

測試ref_count和tags的列印結果

修改test.txt 為 test > 7

執行指令 git fetch --all --tags --depth=5

記錄一次無聊的(經曆了Nodejs -> Shell -> C)的探索問題過程

得出結果 ref_count = 0,并且都 Already up-to-date 了,拉沒拉到最新送出,心裡也有點B數了...

然後執行指定映射關系的指令 git fetch origin test:refs/remotes/origin/test --tags --depth=5

記錄一次無聊的(經曆了Nodejs -> Shell -> C)的探索問題過程

由于指定了映射關系,git知道該fetch哪些代碼,于是擷取到了最新的送出。

然後再看1.9.0的 fetch 代碼

tags == TAGS_SET 和 refspec_count 單獨判斷,在 refspec_count = 0  的時候使用預設的refspec,這樣get到的ref_map便是正确的,git之後的版本裡把在 refspec_count 判斷裡的tags == TAGS_SET 判斷和get_fetch_map移除了。但其實1.8.3.1官方文檔說的覆寫和不使用預設的refspec,在上面代碼裡我還是沒能看出是在哪裡操作的(實在汗顔),猜測是在  Merge everything on the command line  這步,同時也求大神解釋...  之前沒接觸過 C …

其實在這過程中,也産生了個問題,就是 refspec 關系的操作是怎麼處理的,這個也值得探究探究額,決定再刷刷書熟悉下git核心那塊,然後再根據源碼探一探 

git fetch 的參考文檔

說完git fetch的鍋,然後回到之前說的 “有一半原因得歸咎于git” ,另一半鍋還是得pm2-deploy背,pm2-deploy在fetch的時候理應做個相容,哪怕這個相容并不是個很好的實踐(因為pm2新版本有對git倉庫的管理做了更嚴謹的把控)

比如在檢測機器上git版本< 1.9.0,則走原先的 git fetch --all

如下代碼:

<(▰˘◡˘▰)>  完!  就這麼一段無聊的debugger過程…   各位客官看看即可   有深入了解的大神也給小弟多分享下,非常感謝~ 不然隻能以後自己功力深了再來解釋了

繼續閱讀