2012 年的時候,我與朋友一起接了一個網站的案子,當年的我還只是個剛學寫程式的菜鳥新手。我們使用 Linux 主機架了網站伺服器(Web Server),並透過 Samba 服務將伺服器的目錄共享出來,讓 Windows 開發機可以修改伺服器上的檔案。我們是先在本機改好程式,再上傳到這個共享目錄做測試。
在協作的過程中發現了一個難解的問題:我跟朋友手上的原始碼有落差,上傳的時候很容易覆蓋對方寫好的原始碼。主要是因為我們都只專注在自己想要改的程式,而不清楚其他人改了什麼。
覆蓋的影響可能不只是一段程式不見了。其他功能可能正在依賴那段程式的行為,如果沒有注意到,就有機會在覆蓋後破壞其他功能的預期。有些錯誤會立即發現,也有些要在特定情境下才會出現。
而另一個更痛的地方在於,當蓋上去之後,舊的程式如果沒備份,就會真的不見了。讀者可能會想說,本機不是有備份嗎?不,有時候只是改幾個邏輯做測試,測成功是很開心,但把伺服器上的檔案複製回本機備份後,才發現下載的是已經被對方覆蓋的版本,連本機原本留著的修改也被蓋掉了。
互相覆蓋的問題,後來是透過事前溝通與事後審查來處理,並共同決定下一個版本的原始碼該怎麼改。但這仍然對開發過程造成困擾,因此我們開始做一件事:完成一個階段、確認程式能正常運作時,就把它打包成壓縮檔,並用日期當檔名。
於是我們就有了不同日期的壓縮檔,檔名格式大致如下。這裡只是命名示意,YYYYMMDD 代表日期,後面的數字用來區分同一天的備份:
YYYYMMDD-001.zip
YYYYMMDD-002.zip
這是我經歷過最原始的版本控制。把不同時間點完成的程式保存下來,未來有需要時,就可以回頭查閱當時的內容。
題外話:沒過多久,大概在 2012 年 3 月,我就開始學習 Git 了。
回頭看這個做法,壓縮檔留下了當時完整的原始碼,但從檔名只能知道是哪時備份的,無法知道裡面改了什麼。另外,拿到兩份壓縮檔後,仍然要比較內容,才能找出新增、修改或刪除的部分。
即使找出了差異,也還有另一個更困難的問題:當時我為什麼要這樣改?
原始碼可以呈現最終的結果,但不一定能看出當時遇到什麼問題、有哪些限制,以及經過了哪些討論後,又為什麼做了這個決定。這些資訊如果沒有留下來,之後查閱的人就得重新找人確認,或是從現有內容通靈。
對於多人協作,我們會希望透過版本控制,追查修改的歷史與理由,並比較不同版本的差異,讓團隊能理解彼此改了什麼,判斷影響並整合各自的程式。
版本控制(Version Control)是記錄與管理檔案版本的方法,讓我們能在需要時查看、比較或恢復過去的內容。前面的壓縮檔,就是用人工保存版本的做法。Pro Git 的介紹也從複製檔案、保留不同版本的情境開始,說明為什麼需要專門的工具。
Git 這類協助管理版本的工具,稱為版本控制系統(Version Control System,簡稱 VCS)。以 Git 為例,開發者透過提交(commit)留下選定的檔案狀態,並附上提交訊息。之後可以查閱提交歷史與提交訊息,也能比較不同提交之間的內容差異。
Git 可以記錄的是開發者自主提交的內容和訊息。Git 不會因為我們在編輯器裡存檔,就自動把每次修改都加入提交歷史。這也是為什麼有了工具、知道怎麼操作,通常還是不夠。我們還需要決定什麼時候記錄、記錄哪些修改,以及如何說明修改的原因。
提交歷史可以告訴我們哪些檔案曾經修改,但修改的原因需要有人說明。
過去我最常提交的懶人訊息就是「Fix」。如果提交訊息只寫了修正問題,查閱的人仍然不知道修正了什麼。留下問題發生的情境、修改原因,或是相關需求與討論的連結,才比較容易理解當時的決定。
這裡有一個我真實經歷過的追查情境:提交訊息不完整,發布版本與設定資訊也不明確,最後只能大約推測某個時段的原始碼內容有問題。即使找到可能的版本,因為缺少執行環境與必要依賴的資訊,也無法重現當時的執行結果。花了大量的時間追查到最後,得到的只有「可能」的推測,沒有足夠資料確認答案。
這個情境說明,保存原始碼能提供查閱的依據,但如果要回答當時為什麼這樣做、實際執行的是什麼,還是需要保留相關資訊。
回到開頭的協作問題:如果要把自己修改的程式整合到共同使用的版本,就需要知道自己是從哪個版本開始修改,以及這段期間其他人又改了什麼。
版本控制系統可以協助找出檔案內容的差異,開發者再根據這些差異,判斷手上的程式是否需要跟著調整。尤其當別人改到自己依賴的功能時,還要確認修改後的行為是否符合需求。
因此,比較差異之後,仍然需要理解修改的目的,必要時找對方討論,並驗證整合後的結果。
版本記錄讓我們有依據可以查閱、比較,也能在需要時找回過去的內容。不過,回到開頭互相覆蓋原始碼的問題,團隊還需要處理另一件事:成員各自修改的內容,要怎麼整合成共同使用的版本?
大多數版本控制系統都有提供分支功能,在使用分支時,我們可以先在自己的分支上開發,但要把寫好的程式放進共同使用的版本,仍然需要整合。
下一篇會來討論使用分支的概念,以及具體可能會遇到的問題。