簡體   English   中英

開發人員如何處理大型 Git 代碼依賴性無法被 Git 跟蹤的存儲庫?

[英]How do developers handle large Git repositories with code dependencies not trackable by Git?

我的公司有一個大型 CPP 客戶端-服務器應用程序的存儲庫。 我們在 our.network 中有一個額外的驅動器,其中包含整個應用程序的最新編譯項目,因此每個開發人員只需構建自己的更改(構建整個應用程序需要幾個小時)。

  • 這些預編譯項目每天更新,可以復制到您的本地驅動器。
  • 我們使用 Visual Studio 進行開發,並將項目配置為首先在本地驅動器上查找編譯文件,然后在 .network 驅動器上查找它們。

這給更新(拉)其分支但不更新網絡驅動器(因為他們將其復制到本地驅動器)的開發人員帶來了問題。 或者反過來,開發人員不更新他們的存儲庫,而是保持驅動器為最新。

解釋:

有兩種重要的文件類型:Header和CPP文件。 運行應用程序時,Visual Studio 首先搜索本地驅動器以查找 Header 文件,然后搜索 .network 驅動器,並對編譯的項目執行相同操作。 所以問題是,你的本地驅動器上總是有所有 Header 文件,因為你顯然克隆了整個項目,但你沒有在你的驅動器上編譯所有項目。 這會導致編譯項目與用於運行應用程序的 Header 文件不匹配。

例子:

項目一:interface.h, implementation.h, implementation.cpp 項目二:dependency.cpp

所以 dependeny.cpp 使用項目 1 的 interface.h。 現在我們有兩個開發人員,開發人員 1interface.h進行了更改並擴展了一個結構並將其推送到上游存儲庫。 開發人員 2不提取更改,但確實從 .network 驅動器獲取最新編譯的項目。 所以現在 Visual Studio 使用本地驅動器中 interface.h 的舊實現,並使用項目 1 的新編譯版本。這會導致非常混亂的運行時錯誤(讀取訪問沖突),因為傳遞給方法的結構具有不同的尺寸。

所以基本上:預編譯的項目必須始終使用您的更改所基於的相同版本( Commit )進行編譯。 (並非總是如此,因為並非所有更改都會引入對頭文件的更改,但通常最好根據編譯的 Commit the.network 驅動器進行本地更改)。

現在實際的問題是:

我們正在切換到 GitLab,這會強制用戶使用分支來接收代碼審查。 分部不太喜歡歷史往前走,但編制的項目每天都會更新。 所以你的分支存在的時間越長,你遇到奇怪的運行時錯誤的可能性就越高。 你怎么能阻止這個?

我的第一個想法是:

  • 每個分支都會在 .network 驅動器上收到它自己的已編譯項目版本。 (更多存儲要花錢。管理層不喜歡為存儲付錢)
  • 每個分支都重新基於網絡驅動器使用的提交。 這要么得由每個開發人員來完成,因此每個人都對自己的分支負責。 或者在構建之后,啟動一個過程,自動將每個分支變基到該提交(合並與電子郵件通知沖突所需的錯誤處理)。 此外,由於我們正在重寫歷史記錄,因此必須對分支進行 --force 推送,如果多個開發人員在同一個分支上工作,這就引入了開發人員意外刪除某人更改的可能性。

我無法想象我們是唯一一家遇到此類問題的公司,並且必須有一些很好的解決方案來解決這個問題,開發人員不必每天都重新設置分支並 --force 推送更改。

所以 dependeny.cpp 使用項目 1 的 interface.h。 現在我們有兩個開發人員,開發人員 1 對 interface.h 進行了更改並擴展了一個結構並將其推送到上游存儲庫。 開發人員 2 不提取更改,但確實從 .network 驅動器獲取最新編譯的項目。 所以現在 Visual Studio 使用您本地驅動器中 interface.h 的舊實現,並使用項目 1 的新編譯版本。

恭喜? 你在做什么:很抱歉。 您的工作流程已完全中斷,必須從總體上解決減少長構建時間的一般問題。 對我來說,只進行夜間構建完全沒有意義,而且許多分支機構不屬於其中。

我的提示:

  • 使用更詳細的構建工具鏈。 這意味着您只編譯這部分代碼,這取決於您的工作分支的變化。 通常不需要每次都進行完全重建。

  • 使用分布式構建服務器。 如果有很多構建機器可用,像distcc這樣的工具就可以很好地工作。 我不能代表 MS 環境,但我相信您也可以為 MS 設置類似的東西。

  • 你可以將這個工具結合起來,比如ccache工具。 這些工具正在緩存 object 個文件。 如果源的 hash 沒有改變,他們並沒有真正再次構建而是返回已經可用的 object 文件,即使不同的分支需要。

  • 查看為什么您的構建時間如此之長。 通常隨着時間的推移而增長的項目會根據需要有更多的依賴關系。 花一些時間重構代碼庫並找到可以隔離的代碼部分總是很有價值的。 創建單獨的庫/組件,它們完全獨立構建或具有嚴格的層次依賴樹。

  • 如果你仍然有超過幾個小時的構建時間,你應該考慮購買一些簡單的 PC 作為編譯奴隸。 如果您使用distcc為集群設置 10 台 PC 以獲得完整構建並按因子減少構建時間(假設為 9),那么您提供一些難以管理的夜間構建二進制文件會產生更大的效果。

在我上一家公司,我們在非常胖的服務器(24 個 CPU 服務器,每個多核 CPU,大量並行 IO 卡等)上也有大量的構建時間。 在為每個開發人員 PC(現場約 200 台 PC)設置 distcc 后,我們將構建時間減少了 20 倍,它並沒有像往常一樣線性縮小。網絡延遲,更大的 IO 倍 on.network 與本地 SSD 等. 但是效果夠大。 從大約 5 小時開始,我們能夠在 go 到 15 分鍾內完成完整構建。 通過使用ccache ,我們“找到”已經編譯的二進制文件,並且可以在幾秒鍾內進行本地構建。 但是所有這一切都需要良好的構建腳本和良好的分支管理維護和設置。 它不是開箱即用的!

如前所述,我們沒有設置目錄結構或其他一些與存儲庫相關的數據存儲來保存已經構建的二進制文件。 這項工作只是通過ccache緩存二進制文件來完成的。 另一方面,我們將本地構建二進制文件保存在反映本地分支的目錄結構中。 這可能會導致構建結構中有多個相同的二進制文件,但可以更輕松地在開發人員 PC 上維護構建腳本。

沒有通用的即用型概念。 但我希望你能理解我們成功使用的一些想法。

(不是答案,這是格式化的評論)

我沒有得到你所有的工作流程:

  1. 如何更新“他所基於的變化”?
  2. 您的構建系統如何管理增量構建? 它會檢查git diff master HEAD嗎?
  3. 外部驅動器上存儲了多少工件副本? “今晚的構建”的一份副本?

這可以通過make和一些腳本輕松解決。 如何將其與 Visual Studio 集成是另一個問題,作為 Unix 用戶,我沒有資格回答。

有一個三步過程:

  1. 檢查構建工件的提交。
  2. 將構建工件從 .network 驅動器復制到適當的位置,就好像它們是在本地計算機上構建的一樣。
  3. 檢查您要構建的提交,然后使用make構建。

這是可行的,因為make在決定哪些文件已更改時會查看時間戳,而 Git 僅簽出已更改的文件。 因此, make會注意到構建產品比除已更改文件之外的所有產品都新,因此只需要重新構建已更改文件和依賴於它們的文件。

也可以使用類似的基於依賴關系的構建管理器和良好的 hash 來解決此問題,例如 SHA-256(或者,為了速度,BLAKE2b):您可以上傳源文件哈希的清單以及構建產品,然后僅構建其依賴項的哈希值已更改的文件。 這可以防止您需要檢查舊版本,但我不知道有任何本機工具可以執行此操作。

我對基於 Perl 的構建系統采用了后一種方法,並且效果很好。 我們的目標永遠不會重建二進制文件,除非需要它,以便用戶可以下載盡可能小的部分更新,並且它有效。

您為使當前系統正常工作所做的任何事情都需要某種自定義工具來構建。 使用make或一組 shell 腳本很容易,但在 Windows 上會比較棘手。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM