git

Tag: git

github flow - github 開發流程

Trendy
MacauYeah ・2024-06-20

那些年那個很穩定卻又不受歡迎的 git flow 開發流程 多年前,朋友就向筆者介紹git的團隊整操作流程。筆者深思過後,的確實用,那些年的git-flow,很美滿,由開發、測試,到發佈、修補漏動(backport),都有清楚明確的指引。 原作者連結:git-flow 大家如果沒有更複雜的需求,真的可以照搬,筆者也很推這一個模型。 但在長期推廣下,筆者發現大部份人其實都不熟git的基本操作,什至連git graph也不看,現在看git flow,就更不可能接受。那怕是有常用git的個人團隊,也是不怎使用分支模型。 前一兩年,筆者也不懂,筆者也努力地簡化git flow。例如把master和develop合而為一,但最後也是少有人可以接受,很多人還是卡在分支那邊,對checkout、merge還是很陌生。在跟更多不同人的協作過後,筆者總於意會到一件事。其實大部份人,只想知道最後、最新的狀態,只會更新 master / main ,也因為個人開發,所以連衝突也不會有,更不需要使用merge。那怕是少型團隊,頂多也是維護main的衝突,間中用用merge,而checkout還是用不著。 其實這個情況,並不限於小型團隊。因為 web app 和 DevOps 的流行,所以越來越少機會要維護多個舊的穩定版本。大家都專心於最後一個開發及發佈版本就完事,用戶的某個版本有問題?更新到最新版本吧。(註:越底層的應用開發模式,因為相容性問題,不可能只保留一個穩定版本。) 那麼我們就大力簡化吧 - github flow 開發流程 既然大部份情況,大家都只在乎 main / master / 預設分支,那我們也沒有必要跟著複雜的 git flow 走。但在 DevOps 的角度下,為保證 main / master 穩定性,大家還是至少要遵守branching 、pull (merge) request 、code review 、auto test 原則 。 github就最簡單的branching 、pull request 、code review 提出了它們的 github flow。 簡而言之,就是每個人在開發時,都先從 main 起一個新分支,不斷更新。待合適的時候,就透過 pull requst,向原項目負責人提出申請,只要項目負責人點頭,就可以把改動傳入 main 中。又因為Github 原本的定位在於個人與個人之間的協作,初時已經需要通過fork建立獨立的倉庫,那怕你不愛分支也必需分支。所以 pull request,code review 的作用更明顯,後逐的協作更理所當然。 但若果回到公司團隊協,Github flow 就應該像筆者之前提出協作方案,各自起分支,最後由某個人守門,把所有結果放到 main 中。(前文連結)

何謂 Infrastructure as code - IaC

Trendy
MacauYeah ・2024-06-07

在雲端服務出現後,好多新的名字,或許大家都聽過,筆者也稍為再簡介一下。 Software as a Service (Saas)。就像我們的Web App,不用下載體件,可以直接經雲進行業務操作。 Platform as a service (Paas)。這個概念可能最含糊,筆者理解就是,雲端供應商提供一些底層的軟件,供IT人使用。像是資料庫,Web Engine。 Infrastructure as a Service (Iaas)。這個更底層,雲端供應商給出CPU, IP, Memory, Storage等,頂多就再多個預安裝OS的選項。IT人自己去配搭使用。 多得這些彈性服務,雲端應用才真的跟過去租用實體伺服器有所差異。 但對於IT人來講,要使用這麼多不同的服務,實在也不簡單。對於IT消費方,用錢換來實體硬件的靈活性,但因為硬件沒有邊界之後,軟件的量就暴增。管理也不能說是很方便。 在Docker, Kubernetes等Container(容器)出現後,又為這些管理問題帶來另一種希望,就是Infrastructure as code - IaC。它的目標是,管理基礎設施,要像管理原始碼一樣,checkout 就可以回覆到指定狀態。 初聽之下,大家可能覺得好玄,但其實這個概念,在之前筆者的Docker 教學中,已經有出現過。Docker compose 、Docker stack 指令,它們都是基於yaml檔的IaC。 當筆者更新了yaml 檔,執行一次stack deploy ,docker 就會對比之前狀態,如果replica(分身)不夠多,就自動增加所欠數量,如果image 也更新了,就排隊輪流重起換image 。最重要的是,當我們checkout 舊的yaml 檔,回到過去某個狀況,只要還是執行同一句stack deploy ,系統就自然減少所需的replica數量,下戴過去的image。這就代表,我們對於container 構建而成的環境,都可以放入Git等版本控制中,整個管理模式,就像管理程式碼一樣(GitOps)。 對於更進階的Kubernetes更是如些,除了container外,多種不同的network,storage配置,都通過yaml檔進行控制。這樣,架構即使複雜,但只少可以測試、重現和管理。還有一個,它比Docker stack要強的是,它某程度上支緩刪除的概念。雖然不完全,但總比完全沒有方便。 這個IoC的概念,可能還未達到一定廣泛地應用的階段,但它的核心在於,基建項目有檢測試差異的功能,自動去因為這個差異去加或減資源。用Programmer的講法,就是系統有Diff的功能,自動多除少補。

Git Worktree

Trendy
MacauYeah ・2024-04-09

看了Git 大神的影片 part two,才知道原來切換git分支還是有不同的做法。傳統中,我們使用git checkout BRANCH_NAME_1 來切換到我們想要的分支。通常這樣做,代表我們放棄原來的工作環境,換到另一個工作環境中。 這樣做很好,對不對? 是的。但有些時候,我們只是被逼離開原本的工作環境,跳到一個過去的分支/節點去查一些東西,或者修正一些東西。更什的是我們原本的工作環境都還是混亂狀態下,我們不想做commit(提交),我們只好用git stash,暫時將工作環境存起,然後再git checkout BRANCH_NAME_1。在你想做的事做完後,再git checkout OLD_BRANCH。 看起來其實也沒有很麻煩,是不是? 但其實當你的專案有一定大小,你在不同版本跳來跳去,你的IDE就會不斷地重新編譯。更不幸的是,當你的不同版本中有模組數量的差異,弱一點的IDE,什至會攪死它的cache,之後就會發生鬼打牆。為解決IDE引發的問題,筆者有時會直接cp -r YOUR_PROJECT TEMP_PROJECT,在一個新資料夾下另起爐灶。那就是有兩個不同的資料夾裝載著你的專案。 這樣應該沒有問題了吧,是不是?這次是真的可以了,扣除了筆者個人健忘的問題,就沒什麼問題了。 不知大家有沒有經驗,連續commit了幾次,但最後一次commit卻忘了push(與伺服器同步),然後就跳到其他地方繼續工作。如果我們在同一個git repository下,我們commit了但忘了push,即使我們git checkout去了其他分支,用git GUI畫出commit graph時,也至少可以提醒筆者有一個未與伺服器同步的分支。但如果當初我們用的是cp,那就沒戲唱了,什至乎當初複制了去哪裏都忘了。(當你老闆同時要你跟多個專案,健忘真的很容易發生。) 這問題有解嗎?有的,git在2.5版本以後,就提供了一個git worktree的指令。它有點像cp 指令,更重要的是,它打通了兩個資料夾下的隱藏資料庫.git,當大家在那兩個資料夾底下,都可以看到另一方的存在。大家可以用git branch -a或git log --oneline --graph來看看。 詳細的指令介紹:git worktree git 大神的影片 Part 2

Git: 何謂MONO Repository

Trendy
MacauYeah ・2024-04-02

之前看了一位git大神的演講,提及一個叫MONO Repository的使用情況。後期找資料之後,才發現到這是一個公司成長後的一個重大的挑戰。 何謂MONO Repository git的傳統,就是為每一個獨立的專案,建立一個新的Repository (中譯:倉庫)。這個很直觀,獨立專案,獨立管理。從零開始有很多好處,Repo體積通常會小一點,因為其內的東西都是緊密相關。做更新處理時,維護人員也更清楚自己的影響程度。這種架構方式,就叫Multi Repository。基本上,大家預設也是會走這個模式。 但當公司規模一直變大,多個專案可能不再獨立,各個專案或多或少都有一些關聯性。當任一專案更新,都有機會影響到其他人。如果公司使用Micro Service (微服務),就更有機會提早遇到。每次更新時,要跨專案地找出影響範圍原本就已經不容易,現在每個專案獨立地存放在不同的倉庫中,每個倉庫的更新速度不一樣,想要找到合適的地方、合適的時間點推出更新,更是困難。 所以,就有公司就提出,將所有專案都放在同一個Mono Repository中,方便用工具去檢查更新影響。相比Multi Repository,這樣做還可以保證同一個改動可以發生中同一個Commit中,可以讓跨專案的團隊可以即時合作(強逼修改別人的專案)。但這樣使一定會有很技術問題出現。跨專案團隊不可能每個專案都熟悉,因為不熟悉而引起的副作用一定會有,所以Main / Master分支出現有缺陷的機會提高了。亦有人提出,使用Mono架構,還必要使用trunk base分支模式。也就是那些新功能,雖然要創建分支開發,但亦要盡早整合到Main / Master中。這才能讓不同的團隊盡早知道問題,並解決問題。 除了開發模式更具挑戰外,Mono架構對git的效能也有很大影響。因為多專案混合,Repository的大小基本都會很大。每個git指令都會變慢,所以必需做一些週期性的cache,讓git graph, git status這樣日常操作變得暢順。同樣地,持續整合/發佈需要作出調整。不過這些筆者就不在這邊詳述了,有興趣朋友可以到git 大神的Youtube觀看。 So You Think You Know Git - FOSDEM 2024 註:據筆者的資料搜集,很多大公司(Software龍頭)都有使用Mono Repository去做集中管理。只不過筆者不知道如何Fact check,就不在這裏提了。

Git - 持續整合策略 02 | Git - Continuous integration strategy 02

Trendy
MacauYeah ・2024-03-14

Night Build 實務操作上的注意點 Night build第一個要注意的問題,就是要確保同一個commit,真的可以重複建設。一般來說,大家的目標只在運行測試,而自動測試不具破壞性,就基本可以重複的。而如果測試當中包含發佈測試版本,那就還要考慮重複發佈有沒有生效或造成附作用。 以Java maven為例,重複發佈測試版本需要遵守特定的規則,版本號需要以SNAPSHOT結尾,這是為讓maven每天都會重新下載它們的包。而沒有SNAPSHOT結尾的,就只會做一次性下載,減少重複下載造成的資源浪費。若真遇著不支援重複發佈的情況,就需要以日期時間做版本號,就像vscode的某些插件,就是以時間截結尾以作為區分。 Night build另一個要注意的問題,就是開發圖隊何時進行下一輪開發,這會決定何時有新的版本號。扣除上述因為工具不支援的而引發的副作用,還要考慮沒有更新而發生的問題。 有個尷尬情況是,團隊在發佈現行版本時,release commit與main有機會是同一個commit(也就是未有進行下一輪開發)。若不斷重複發佈,有沒有變相發佈了一些沒有預期的功能?例如Docker image,官方大力建議每日自動發佈。當底層的image更新後,頂層引用它們的image,也可以重新發佈,保持安全性。但這樣做的問題,就是頂層的同一個版本號,昨日與今日的運行結果也可能不一樣。這對追蹤問題,並不友好。 所以大家做分支整合時,要預先對版本號作好規劃。然後還要留意Night build不應與release commit重疊。版本號大家做好語意管理,再加上alpha / beta / SNAPSHOT等區分Night build版本,應該就足夠了。而commit重疊問題,就要留意開發週期,Night build要麼就比release早一個commit(即在release時,不推進Night build),要麼晚一個commit(即馬上規劃下一個版本號進行Night build)。

Git - 持續整合策略 | Git - Continuous integration strategy

Trendy
MacauYeah ・2024-02-23

對於原始碼的管理,平常筆者也有在用gitlab的Continuous integration,針對每次提交(commit),都會有自動編譯和測試。但當一個專案中,有很多關聯庫(dependency library)的引用時,光是專案中每個commit 行auto build就不夠用了。更嚴重的是,若然大家有很多微服務micro service,它們的更新不會反映在commit中。 所以定期重跑動動編譯和測試,是筆者認為可以緩解關聯更新的問題,至少可以提高知道問題所在。 筆者先做了一些功課,參考別人怎樣思考Night build (定期重新編譯)這件事。 每次整合新功能到穩定分支(stable branch)之前,都需要做自動測試。 當專案複雜性越來越大,每次自動測試都把全部測試跑一次,就會遇到效能瓶頸。 所以考慮commit時做單元測試(unit test),然後每個固定的時間問隔做整合測試(integration test)。那個固定的時間間隔就是Night build。 而筆者的問題並不是來自於效能瓶頸,而是涉及關聯性更新問題。這些要麼就有是經code base 層面引發關聯性自動試測,要麼就是Night build重複測試。這兩個功能,gitlab都有提供,只是筆者初步構想下,Night build比較易設定。因為要考慮micro service的於沙盒環境的部署,最簡易的Night build只需要一個共用的環境就夠。但也同樣意味著,Night build需要進行多個不同的分支測試。就需要多個不同的環境。 Night build的測時時機也是一個問題,因為測試當下,並不能百份百對應關聯micro services的提交狀況,大家就更需要做好發佈的版本號語意管理。 不知道看完筆者的策略之後,大家又有何看法?歡迎大家一起加入git筆記的編輯。

Git Submodule

Trendy
MacauYeah ・2023-09-15

Git Submodule 初次實務上使用submodule來同時管理幾個project的更新。如果有任何理解上的錯誤,請在github中提issue或pull request。 Why Submodule 假設你的團隊中有三個人,A君做A Project,B君做B Project,C君做Main Project。如果可以,A,B各提供已編譯的Binary或Library,給C君直接使用就最好。 但要做到好好管理,A,B都要有自己的發佈系統,即是把Binary上傳到某個分享Repo中,這樣C君就能有條理地通過IDE或Compile工具下載對應的版本。如果是javascript,Repo可能就是npm repo,如果是java,可能就是maven repo。這亦代表A,B君對程式編譯、打包、版本命名等都要很熟悉,不能一輩子都命名為v1.0.0。 如果團隊對這些都不熟悉,C君還有什麼方法呢?其實靠著Submodule的功能,C君也可以硬把A,B的Source code取出,做最後打包。 這跟A、B君自己把source code壓縮然後Email寄給C君是有不同的。因為這樣C君並不清楚A,B的git脈絡:C君需要自己做好A、B的版本記錄。想要只回滾A,B的版本普不容易。但經過git Submodule後,C君可以清楚知道現在正使用的是A、B的那一個commit版本。假如有一天,A、B、C三個都更新了,但發現合起來時就跑不動。C君可以保持A、C的版本不變,單獨提取B的某個版本進行測試。當然,你可以說原本Email也可以這樣管理,但始終你不清楚B的版本記錄,Email的日期並不代表Source Code的進度。(因為有時候,Bug Fix是針對舊版本的做更新,新功能的Email日期反而比Bug Fix要早) 同理,如果大家要連結多個沒有發佈系統的文字資料,也可以利用Submodule。例如筆者正在編輯一本書,當中不同的主題,就是使用Submodule的功能串連起。 Command 馬上看來來Submodule可以怎樣做。 假設你已經知道git 怎樣用,也起了git repo。假設你是C君,進入你的本機repo資料夾內,使用submodule參數。 上面的效果,就是把C君當前repo的狀態,連結到B君submodule當時預設分枝(default branch)的最後一個commit 中。然後C君在自己的repo怎樣更新,它引用到B君的submodule版本都不會變。 直到某一刻,B君說他加了一個穩定的新功能,請C也連帶更新一下。C君也做好自己的準備後,使用submodule參數進行更新。 注意,如果C君有多於一個submodule,上述指令會全部一口氣更新。另外,如果你覺得B君的最新版本不能用,還是可以針對B君取得特定的版本。

Git Co-Work Flow

Trendy
MacauYeah ・2023-06-23

Git Co-Work Flow 雖然git面世已很久,但相當一部份澳門朋友都是solo man,很少合作寫code,對git branch始終都有些恐懼。所以這次來解召一個基本原則,至少你不會爛了code救不回來。 若然大家未熟悉git,初次利用git合作寫program,請盡量減少使用共同分支(branch),可以極大地減少問題。 第一個大原則 - 建立一條自己分支 在一個repo中,為自己建立一條分支(branch),可以減少Remote repo中有人比你先commit,而令你push失敗的情況。 Code block由於安全性問題,沒有獨立寫了LifeMag 網誌中,請移到github repo。 除非你的隊友故意你用的分支名先commit,又或者你自己有幾台電腦,幾台一起做改動。不然push 應該不會有問題。 第二個大原則 - 用fetch取代pull 很多人在取用Remote Repo的更新時,都會使用pull。但pull其實是fetch及merge的混合,而且merge還要考慮source branch是那條分支的問題,若然大家都有一條獨立branch,那麼這個無腦pull並不存於每人只有一台電腦下的多人協作中。 fetch的過程中,還可以加入參數--prune,順便依照Remote Repo的指示,同步刪掉本機中一些不再存在的origin/branch。 Code block由於安全性問題,沒有獨立寫了LifeMag 網誌中,請移到github repo。 第三個大原則 - Merge前先Commit 經過前述fetch後,其實他人的改動並未加入自己的分支中,必需經過merge才會出現。但並不是沒有conflict就無腦merge。 假若自己有改動,未commit,應該老虎蟹都先commit。這是為了在merge後,還有機會可以無腦reset,回到之前那個commit。這就像是做任何更新前,先做backup。 Code block由於安全性問題,沒有獨立寫了LifeMag 網誌中,請移到github repo。 第四個大原則 - 由某個特定的人來管理master或main branch main branch(以前叫master branch),是他人下載時的預設分支,也是Github、Gitlab的預設顯示分支。所以該分支存放著的source code,應該在代表信心度比較高。 在協作的環境中,每人都有自己分支,那就代表要有一位人員做管理,他負責checkout main, 然後合併其他已驗證的分支。 Code block由於安全性問題,沒有獨立寫了LifeMag 網誌中,請移到github repo。 在某些比較嚴僅的環境中(例如Github、Gitlab),main分支可能會被系統機制鎖定,必需通過系統內鍵的Pull Request,才能通過審核,合併到main。另外,也有一些關於開發上的Git workflow,主要針對功能管理、版本發佈、錯誤修正等控制。有機會再為大家介紹。 希望以上的流程,可以有效且容易地讓大家協作。如果有任何command錯誤或更新,都可以經Github Pull Request通知筆者。