《嚴防後宮起火-以無聊宅宅的視角來理解版本控制的概念》


Posted by Eloise-Elixir on 2020-08-13

〈前言〉 – 我全都要 (雷豹, 1994)

初見 Git,我便認為這東西真真是極好的。韓國文化中有個已過時的流行語叫「漁場管理」,用來形容對身邊的複數異性皆保持曖昧關係、卻不進一步交往,就像到處撒了漁網後,保持著隨時可以捕獲的狀態,在各個場域中遊走流連、愜意巡弋,卻始終不收網。因為愛情不是排位賽,不需要二、三、四名,第一個人抵達終點後,比賽就直接結束了,剩下在座各位,都是垃圾。

在工程師的世界裡,這種到處釣魚的渣男行為,就叫做版本控制。這不是表示工程師都是渣男,決定性的差別在於,歐巴進行漁場管理是出於想要繼續尋找更大更美的魚,工程師進行版本控制,是出於想要保護好辛苦爆肝的勞動成果,因為……修改很麻煩。

就算一個完全不會 code 的程式小白,一定都或多或少聽說過「為了解決一個 Bug 花掉一整天時間」、「解決了一個 Bug 結果產生了三個新的 Bug」這類的修羅場,如果從頭到尾工程師們都是在原始版本的唯一檔案中做修改,恐怕一個失誤導致專案炸裂,在被客戶電到飛天前,光是想到明天上班還要面對幾十萬行不知錯在哪裡、改了哪邊的東西從頭找起,就會在下班路上順路去買一條童軍繩了。

說得太嚴重了,但反正絕望的程度差不多就是這樣。

不管是哪種出發點,反正渣男跟工程師的思維都脫離不了豹頭的野心:我全都要。俗話說的好,留得青山在,不怕沒柴燒,給自己留點退路實屬人之常情,包含用如此俗濫的諺語來寫文章,也是一種人之常情,因為才寫了四段就有點想不到文章該怎麼接下去。

由於鄙人並沒有資本與足夠厚的臉皮跟足夠低的道德心進行漁場管理,這方面是完全沒有經驗,所以看到 Git 時,唯一聯想到的東西只有以前孤單寂寞覺得冷時玩的後宮養成遊戲──我是一朵清麗脫俗、善良天真的白蓮花,世上所有帥哥都愛我的那種遊戲──翹腳叼菸玩的(開玩笑的辣)。

在前文提到的三者之間,背後的運作其實蠻類似的。工程師控制他們的專案,是為防案子炸裂,我跟渣男,是為防後宮起火,因為我跟工程師跟渣男,其實說到底,都是人類。是人就會貪,不管是貪輕鬆還是貪快樂,但我都花錢花時間了,當然要全部破台,不然遊戲白買了。

這三者之間的運作類似一個樹狀結構,起始點都是一個,然而隨著時光推移,我們會遇到分歧,渣男可能東窗事發被所有人暴打、專案可能要一邊測試新功能一邊修 Bug,而我要選擇要不要接受男主的求婚。

因為我怕我會後悔太早跟男主結婚,工程師會怕解決了一個 Bug 結果產生了三個新的 Bug,渣男會怕……算了,不提渣男了,他都當渣男了他應該什麼都不怕。反正,為了避免萬一,在沒有人生重來槍的情形下,我們有了 Git,就可以隨時讀檔重來,皇上挑後宮亦似如此,長得不錯的我就留著,我很可能這輩子都不會臨幸她,說不定明天就忘了她長怎樣,但那又怎樣呢,反正老子擁有她。

〈概念釐清、舉例比較與簡單說明〉

為了更好理解,我們來舉個例子,對照一下管理專案跟管理後宮的概念。

工程師
建立新專案 打開新遊戲
寫基本架構 跑劇情序章
需要新功能 想看新帥哥
寫出一堆 Bug 沒照攻略跑錯選項
功能改版 角色第二種結局

就像這樣,進行一個專案跟跑一個遊戲一樣,隨著進度往前,不定時地會到處開闢新的戰場,但我們為了避免專案爆炸/後宮起火,在確保正宮安穩的同時,需要分散風險也需要分散煙硝味,因此在版本控制的領域裡,我們會使用到 Branch 這個東西,也就是分支。

Branch & Master

在進入二擇一的重要局面前,我們要把目前進度存起來,先跑選項一的劇情,這就是其中一個分支,我們就先叫 Branch 1。跑完之後我也想看看選項二會有什麼劇情,就再載入檔案,從剛剛二擇一的地方 開始,這就是 Branch 2 。

Git 我的後宮 存檔點/分歧事件
Master (主版本) 封面官配男主HE路線 走完序章後照著劇情跑,答應男主的追求
Branch1-新增功能 聽聞劇情很不錯的青梅竹馬線1 妥善拒絕男主的追求,搬回鄉下且開始種田
Branch2-優化寫法 純粹看顏值跑的背德不倫線2 答應男主的追求,去他公司上班,跟他同事訴苦訴到床上去
Branch3-Bug Fix 會崩潰搞監禁的致鬱病嬌男3 用惡劣的方法拒絕男主的追求,被搞到身敗名裂只好去賣身
Branch4-加點好玩的 開朗的治癒系年下犬系男4 答應男主的追求,但留在原本職場跟新進後輩精神出軌
Branch5-產生更多Bug 玩到結尾發現是自己血親的胃痛線 妥善拒絕男主的追求,搬回鄉下但外出求職
Branch6-整個程式崩潰 封面官配男主隱藏壞結局 答應男主的追求後各種劈腿再莫名其妙開始賣身

以上這個表格,不重要,而且也不準確,我只是想再列個表格。

總之,我們現在可以理解,管理各種不同版本,我們會新建很多的 Branch。然後我們現在要知道這些分支是如何分出來的。劇情發展要有基石,也就是我們開好專案後一開始寫的那個基本架構的部分,在Git裡稱為 Master,這就是我們發展出那麼多分支的主幹,不管我們加多少東西進去,這個主幹都是不變的,因為你不管玩什麼角色,每次打開這個遊戲序章都是一樣的,就像你每天打開FaceBook,它都是一個社群網站,不會突然變成網路銀行。

好的,那麼問題來了。當我們新寫好一個功能,我們要怎麼在我們的基本架構上新增這個功能呢?畢竟,我們新增功能就是要用(不然呢!)。我今天建了一個網站,然後開個分支新增了一個功能,我必須要讓新功能出現在網站上,也就是要把這個分支插回去樹幹上,但在我們進行插的動作之前,我們要讓樹幹知道小夫我要進去了。(欸欸欸欸!)(不知道的不要去查你的童年會碎掉)

讀到這裡,想必你已經發現我放棄後宮遊戲改成用最陽春的樹幹來比喻了。

Staged/Untrack/Commit/Merge

在進行版本控制的時候,檔案會被分為兩種狀態:

Staged:在控制之下
Untrack:未進行追蹤控制

所以我們需要先將檔案加入 Stage ,讓電腦知道需要注意這個檔案,因為我有改動它,而這個改動至關重要,關係到最後我們這棵樹會長成什麼樣子。然後我們會稍稍來進行一個叫做 Commit 的動作,用了非常多的冗字只是想表達這個類似於存檔的概念。當我們完成了新增/修改,要讓電腦知道我們要保留這個精美的樹枝。

最後我們會再來進行一個叫做 Merge 的帥氣動作,把我們的新東西插回去主幹上。接著我們會發現一個版本控制與後宮遊戲最決定性也最讓人哀傷的差異:使用 Git 進行版本控制時,我們可以 Merge 全部的東西讓他們合而為一,但我卻無法像真正的皇帝一樣將所有男角合併一個後宮,想去哪睡就去哪睡。

我恨這個世界。因為我無法一次擁有八個男人。

〈做法/指令〉

稍微知道概念之後,就來簡單示範一下要怎麼操作。使用 Git Bash 來進行版本控制,以下是幾個會使用到的指令:

git init :初始化
git branch 指定名稱 :新建一個分支

git add 檔名 :將檔案加入 Stage
git commit :儲存這個版本
git merge :合併版本

git status :看檔案狀態
git log :看歷史 Commit 紀錄
git checkout :切換回到特定版本

因為在此寫一個遊戲劇本太費時,我擔心手指不受控制一不小心寫了十萬字,所以我們用一個很爛的小明笑話來舉例。我們先寫個笑話的開頭:有一天,小明出門時被車撞… → 存檔 小明被撞.txt

這個就是我們的Master,我們有一個角色叫小明,這是不變的,而他註定每次出門都一定會被撞。然後我們要開始來發展這個笑話的劇情,首先我先想到了一段,於是我們要開一個新分支:

git branch 下場1
新建好一個分支,就會直接跳到這個新分支,我們在這個分支下編輯這個笑話:有一天,小明出門時被車撞,他死了。然後我們就粗暴地存檔。 →存檔 小明被撞.txt (於下場1分支)

然後我們要把 小明被撞.txt 加入版本控制:

git add 小明被撞.txt

將檔案加入 Stage ,然後我們再輸入:

git commit -m 小明死了

這個 -m 小明死了 就是在 Commit 時加入一個訊息,來說明這個版本大概是什麼東西。

但是我後來覺得小明死得太快,應該讓他多受一些折磨,所以我:

git checkout master

回到劇情主幹上,這時候小明才剛被撞而已,我們再重新開始,寫一個新版本。

git branch 下場2

有一天,小明出門時被車撞,被送到醫院電擊一百次,又活下來了,可喜可賀。然後我存檔。

git add 小明被撞.txt
git commit -m 小明被電

我覺得這兩個下場都不錯,所以我要把他們融合在一起,就會有雙倍的笑點雙倍的快樂。所以我:

git checkout master

切換到我的笑話主幹,然後:

git merge 下場1

把小明的第一個結局加進來, 然後再 git merge 下場2 ,把第二個結局也加進來……但是我失敗了,因為我的笑話產生了衝突,小明沒辦法一邊活著一邊死掉。

我們產生了新的問題,寫程式就是在解決別人的問題時一邊給自己製造一堆新的問題,至於怎麼解決,我現在懶得教你,你自己去學。因為,我只是想寫一篇關於版本控制到底是什麼的廢文而已,沒有要讓你精通的意思。


#Git







Related Posts

自駕車控制 high-level 概念理解

自駕車控制 high-level 概念理解

如何在 CoderBridge 上撰寫文章?

如何在 CoderBridge 上撰寫文章?

[Week 2] JavaScript - 變數、陣列、物件、== 與 ===

[Week 2] JavaScript - 變數、陣列、物件、== 與 ===


Comments