程式碼時光機:應用 Git 版本控制,即使犯錯也不怕


每個人都會犯錯,這是人性的一部分。我肯定每個人都曾在編寫程式碼時犯過嚴重錯誤,嚴重到希望有一部時光機,讓時間倒流回犯錯之前。正因為這種錯誤,每個程式工程師都應該在開發專案中使用版本控制;不使用版本控制的後果,就等於電腦不備份一樣,一個突然的意外或資料遺失就會讓整個專案受到極大影響。

版本控制能讓你回溯之前的專案版本,可以回復遺失的資料,或是查看程式碼的進程。另外,使用版本控制後,與其他人合作同一個專案就容易得多。相信許多人都會同意 Git 是最佳的版本控制系統,而非常幸運地,現在 Xcode 已經將 Git 整合在開發平台內了!

很多人都錯誤以為 GitHub 和 Git 是同一樣東西,但這是錯的。Git 是一個在你自己電腦本機端運行的版本控制系統,而 GitHub 則是一個線上服務,讓你將 Git 版本資訊儲放至雲端,就像是 iCloud 雲端硬碟,但它是專屬於程式碼的應用,而且功能更強大。

Apple 在推出 Xcode 9 的時候已經與 GitHub 合作,讓開發者可以輕易在他們的 App 中使用版本控制。在 iOS 專案中使用 Git 與 Github,開發者不再需要另外寫command line。現在所有的功能全都放在 Xcode 內了!

在本次教學,我將會說明 Git 的基本原理,以及如何在 Xcode 9 設定與使用 Git。我也會說明如何連結 GitHub 帳戶,將專案程式碼儲存到雲端。

注意:本篇教學需要使用 Xcode 9 版本的功能,請確認 Xcode 是否已更新至最新版本。另外,你也需要一個 GitHub 帳戶。

來開始吧

因為我們是要學習的是 GitHub 而非 Swift,所以本篇教學使用專案非常簡單,只是向你說明 GitHub 的功能。你亦可使用自己的專案,這樣的話你可以直接跳到 Git 是如何運作的部分。

建立專案

來建立一個專案吧!請打開 Xcode,點選 FileNew Project,接著選取 Single View App,命名這個專案,我會將它取名為 Git Tutorial,設定語言為 Swift,我們不需要 Core Data、Unit 和 UI Tests,請不要勾選。

接著這個部份非常重要!在下一個視窗,請務必勾選 Create Git Repository on my Mac,這將會初始化你專案的 Git 專案目錄。點選 Create,然後就可以準備開始了!

Git 是如何運作的

在說明如何使用 GitHub 和 Xcode 之前,我們先來談談 Git 是如何運作的。

上圖說明了一個檔案在 Git 儲存區的不同狀態,以及你可以對它們使用的各種指令。

Working Directory 存放你正在編輯的檔案。而 Staging Area 則存放 commit (提交) 前的檔案,在這裡的檔案就是準備要 commit。當你決定 commit 這些檔案時,檔案就會加到你的本機儲存區。當你進行 push,就會將你的本機儲存區和遠端儲存區同步,今天我們用的遠端儲存區就是 GitHub。每次進行 push,就可將在本機端的改動加到遠端儲存區;換而言之,進行 pull 的話,就可以將在遠端儲存區的改動,加入到本機儲存區中。

假設你和夥伴正在合作開發一個簡單的待辦事項 App,App 內有三個頁面,分別是 to-docompletedsettings。比如說,你今天想開發 settings 的部分,首先你需要從遠端儲存區進行 pull,確保你的版本已包含其他夥伴做過的程式碼改動。然後,你可以開始在 settings 編寫程式碼,此時檔案就在你的 working directory。當你在 settings 完成了一個功能、或是某個重要的部分後,就 git add 檔案到 staging。如果你加入了任何檔案或圖片,亦要把它們加到 staging。現在你可以準備 commit 了,commit 的時候,請加入注釋說明做過的改動。最後,你可以用 git push 同步本機儲存區與遠端區。你的夥伴也需要進行 pull,這樣就可以知道你在 setting 頁面做了什麼改動。

概念聽起來可能有點困惑,但其實很簡單。接續的教學部份將能讓你更理解相關的概念。

現在,讓我來說明一些 Git 的指令:

  • git init: 這個指令可以初始化 Git 專案目錄。Xcode 其實會為你設定好,不過如果你在 git 使用 command line 的話,你將會用到這個指令。
  • git status: 顧明思義,這個指令可以顯示你 git 儲存區的狀態。在你的指令列中,設定了沒被追蹤的檔案 (不在 staging) 顯示為紅色,有被追蹤的檔案 (在 staging) 則顯示為綠色。Xcode 會在 Project Navigator 顯示你檔案的狀態,下文我們會再深入說明。
  • git add: 這個指令可以把你的檔案加到 staging。在 Xcode 中,要 commit 一個檔案,你只需要在勾選在 staging 中需要 commit 的檔案即可,這一點我們亦會在下文深入說明。
  • git commit: 這個指令可以 commit 你在 staging 的檔案到本機儲存區。
  • git push: 這個指令可以將你做的改動 push 到遠端儲存區 (GitHub)。
  • git pull: 這個指令可以將改動從遠端儲存區 pull 回來。你與夥伴開發同一個專案時,你會需要將其他夥伴的改動 pull 回來,並同步至你的本機儲存區中。

這些都是基礎指令,我們接著進入下一步吧!

你的第一次 Commit

當你建立專案時,如果勾選了啟用 Create Git Repository,其實 Xcode 已經幫你做了初始的 commit。如果你一開始沒有勾選選項,你可以在 Xcode 選單列中按 source control,點選 create git repositories,就可以為你的專案初始化儲存區。選單列中的 source control 應如下圖所示:

現在,讓我們來做些改動,實作另一個 commit!請到 Project Navigator 的 ViewController.swift ,並加入任何能執行的程式碼。我已加入了一些字串常數,並 print 了一個 ViewDidLoad 的方法。

從程式碼可見,我在專案中針對樣板程式碼做了兩個改動,就是加入了一個常數和一個 print statement。但一般而言,要在一段程式碼中找出每一個改動並非易事,所以就讓 Xcode 來幫忙吧。

Xcode 有一個非常靈巧的工具 version editor。在 assistant editor 的旁邊,點選有兩個反方向箭頭的按鈕,就可以打開 version editor。

打開 version editor 後,你將會看見兩邊的程式碼有部分 highlight 了,標注著兩者的分別。左邊顯示著你正在編輯的程式碼,而右邊顯示的則是同一個檔案、但是你上一次 commit 到本機 git 儲存區的版本。這功能真的很強大!這樣你就可以看到從上次 commit 後做過的改動。如果修改後的程式碼執行有誤,你就可以輕易地追蹤回去。

你可以清楚看到我增加及移除了甚麼。此外,我們還有另一種方法可以看到從上次 commit 後我們改動過哪些檔案。看一下你的 project navigator。

ViewController.swift 檔案旁邊有個 M 字,它表示 ViewController 檔案自從上次 commit 後,已經做了改動 (Modified);如果你看到是 A,則表示這個檔案已經被 Added 了。這是另一個好方法,讓你追蹤檔案與儲存狀況。

知道了做過甚麼改動後,就來 commit 我們的改動吧。在選單列中,點選 Source Control,然後接 Commit,你應該可以看到這個畫面:

這個 Commit 視窗,讓你可以直接將檔案做 staging 與 commit。如你所見,Version Editor 的左邊也顯示著現在改動的版本,右邊顯示著最近一次 commit 的檔案版本。

現在來看一下左邊的檔案列表,它列出了從最近一次 commit 後所有改動過的檔案。你可以看看每個檔案做過的改動,來幫你寫個好的 commit 注釋。注意,這些檔案旁邊都有一個複選框,這就是 Xcode 的 git add 功能,只有勾選了的檔案會被 commit。

談到 commit 注釋,看一下視窗下方的文字方塊,這就是填寫注釋的地方。記住,一個好的 commit 訊息應該簡而精,重點說明做過的改動。填寫注釋是為了 1) 讓你的夥伴知道你在準備 commit ,及 2) 讓你回溯工作日誌並看看做過的改動。如果你發現一個 bug,一個好的 commit 訊息可以輕易追蹤問題在何時何處發生。

現在就來寫個訊息說明改動,再點選 commit # file(s)

建立一個分支 (Branch)

現在,我們來建立一個分支,並談談這個功能吧。分支是什麼?他其實是一個獨立的小儲存區,通常專注於一個功能。因為分支獨立而不影響專案的其他部分,所以共同開發專案時就很好用了。也就是說,就算你搞砸了某個分支的程式碼,亦不會影響到專案中的其他程式碼。

再回到我們的待辦事項 App,假如你想要增加一個新功能,以允許使用者將日程同步到 iCloud 日曆上。你可以從主要分支 (Master Branch) 中建立一個分支,名為 “calendar”。主要分支就是大家在此教學中一起實作的頁面。

新的 “calendar” 分支雖然從原專案移植了所有程式碼,但現在你可以獨立作改動。當你 commit 改動時,你 commit 的是 calendar 分支,而非主要分支。一完成了 calendar 的程式碼編輯,確認了同步功能正常,你可以將它合併到主要分支。若此時開發團隊決定停用 calendar 功能,你就可以直接移除這個分支,而不會造成任何影響。使用分支既可以讓你的 App 開發更有系統,又可以防止意外影響到整體專案開發,讓過程更加安全。

現在示範一下,我們來新增一個新函數到練習專案中。加入一個字串做為參數,進行 reverse 和 return。我們將在另一個分支建立這個函數。

首先,到 Source Control Navigator,它是在左上方 Project Navigator 的旁邊。如下圖所示:

打開資料夾,你會看到另外三個資料夾:BranchesTagsRemote。打開 Branches 資料夾,你會看到裡面的主要分支,右鍵點擊主要分支,點選 Branch From Master

請為你的新分支命名,我把分支名為 “reverse”,因為我會用以來增加一個 reverse 函數。

現在你可以在 branches 資料夾看到新分支,旁邊有個字 (current),這表示你轉去編輯新分支。直到你 check out 之前,所有 commit 都會實行於這個新分支內。

然後,在 viewDidLoad 下方加入 reverse 的函數:

viewDidLoad 函數加入:

接著,到 Source Control,並再次點選 commit,你將會看到程式碼的改動,請細心留意程式碼下的檔案路徑。

你會注意到我們都是在 reverse 分支下處理編輯。寫下你的 commit 訊息,並進行 commit。

我們已完成了新功能,而且功能正常運作中,是時候把它合併到主要分支了。回到 Source Control Navigator,點選分支目錄,右鍵點擊主要分支。

讓我解釋一下這幾個功能選項:

  • Checkout,第三個選項:在 Git 裡面,Checkout 代表著切換分支。比如說,當我想要處理主要分支的另一個功能,我就要 checkout 主要分支,在主要分支編寫程式碼;當我想要開發 resverse,我就要 checkout Reserve 分支再繼續編寫。
  • Merge “master” into “reverse”:這表示將主要分支合併到 reverse 分支。我們不建議這樣做!因為這會將你主要分支的所有程式碼放到 “reverse” 分支,把主要分支合併到其他分支是一個不好的概念。
  • Merge “reverse” into “master”:這就是我們要執行的做法。這表示將 “reverse” 的所有程式碼合併到 “master”,繼而將 reverse 開發的功能特色加到專案內。請點這個選項,並按下 merge

你會看到 version editor 顯示的版本記錄、和主要分支最新的 commit,請在左下方再點選 Merge 一次。

合併過程會列在 commit 的記錄上,主要分支亦變為 current 分支。恭喜你,已經建立了第一個分支、加入了一個功能、並把它 merge 到主要分支了!

連結到 GitHub

現在,我們開始說明一個非常好用的工具:連結你的 GitHub 帳戶!因此,在開始前請確認你有 GitHub 帳戶。

首先,我們要連結帳戶。請到 Xcode 偏好設定 (Menubar > Xcode > Preferences),然後在 Accounts 的頁面,點選左下方的加號,選擇 GitHub 並繼續。輸入你的 GitHub 帳號與密碼就完成了!你已經成功連結 GitHub 帳戶了!

在 GitHub 為專案建立一個儲存區,在 Source Control Navigator 中,右鍵點擊你的專案檔案,並點選 “Create GitTutorial remote on GitHub”。

現在應該會有個視窗讓你設定儲存區,請先確認你是否有點選自己的帳戶。為你的儲存區命名 (默認設置為你專案的名字),並考慮是否需要為專案加入敘述。在這頁面,你更可以選擇是否要公開儲存區 (只有付費帳戶或是學生帳戶才可設為私人儲存區)。輸入好所有設定後,請點選 create

然後,請到你的 GitHub 帳戶,並到儲存區 (頁面右上方的個人頭像 > your profile > repositories),第一個就是你的開發專案。

點選它後,你就會看到儲存區頁面,你也可以看到專案的描述、commit 過多少次、以及專案內的所有檔案。單在 Xcode 就能完成所有事情啦,是不是很酷!

如何使用 Push

現在,我們來做其他改動吧!這次 commit 完後,我們再將這些改動 Push 到 GitHub 上。

我會在 ViewController 加入一個 label (文字標籤) 到 storyboard,並將 label 設定為 outlet。使用 reverse 方法後,我將會把字串輸出至 label 來顯示。

這是我做的方式:

提醒:別忘了要在 storyboard 將 label 設定為 outlet。

在本教學專案開發中,我們是第一次在 storyboard 做改動。注意 ViewController.swift 和 storyboard 檔案都有 M 字在旁邊。接著,打開 version editor 並點選 storyboard,它的檔案格式為 XML 檔,代表 version editor 可相容 storyboard 的格式,所以可以顯示你在 storyboard 做過的改動。

現在,再到 source control 做 commit。這次在 commit 視窗,你會看到 ViewController 與 storyboard 檔,請確認你兩個檔案都有勾選,才可以兩個檔案都 commit。

現在你已經 commit 了改動,來把改動 push 到 Github 吧!現在回到 Source Control,點選 push,然後在彈出來的視窗中選擇主要分支,再點選一次 push

當你的 push 完成後,會有個綠色勾號表示 Push Successful。現在請到你的 GitHub 帳戶,進入儲存區,你會看到你的 commit 訊息顯示和上傳時間於檔案旁邊。

恭喜你!你已經用 Xcode 完成了第一個 push!

如何使用 pull

如果你正和夥伴一起開發專案,就會需要用到 pull。假設其中一個夥伴複製了你的儲存區,在 ViewController 做了些改動。他做完改動後,就會 commit 並 push 到儲存區。要把這些改動同步到你的本機儲存區內,就會需要這個 pull 功能。

現在讓我們來做個示範。建立一個名為 FileToPull 的新檔案於 GitHub 儲存區。你當然是想 pull 一個全新或更新了的檔案。

在選單中的 Source Control 內,點選 pull,在這個專案中請選擇主要分支,再按 pull

我 pull 了一個新檔案,成功後它會在 project navigator 裡:

然而,如果你 pull 了一個原有檔案的更新版本,這就是 Xcode 一個很好的功能。在這個情況下,version editor 可以展示你的原有檔案,與你準備要 pull 的檔案做對比,這樣你就可以看到其他夥伴所做的改動。你可以選擇把所有改動 pull 回來並同步到你的專案中,或是只 pull 某些改動亦可。

結論

希望本篇教學能帶你進入 Git 與 GitHub 的神奇世界。版本控制在開發專案中,是一個相當重要而有用的工具,我相信你在任何開發工作中都會經常用到的。

如果你對本篇教學有任何疑問,請在下方留言,我們將會盡力解答。若想要了解如何使用 GitHub,請參考 GitHub 指南

譯者簡介:Oliver Chen-工程師,喜歡美麗的事物,所以也愛上 Apple,目前在 iOS 程式設計上仍是新手,正研讀 Swift 與 Sketch 中。生活另一個身份是兩個孩子的爸,喜歡和孩子一起玩樂高,幻想著某天自己開發的 App,可以讓孩子覺得老爸好棒!。聯絡方式:電郵 [email protected]

原文Understanding Git Version Control and Learn how to Use it in Xcode 9


擁有多年 iOS 程式開發經驗,自2013年開始,已開發了 12 個不同類型的 App。他曾獲 2016 及 2017 年度的 WWDC Scholarship 。Mitchell 現於羅切斯特理工學院(Rochester Institute of Technology)就讀,除熱愛研究 UI 設計外,也非常喜歡將自己的iOS開發經驗和大家分享。

blog comments powered by Disqus
訂閲電子報

訂閲電子報

AppCoda致力於發佈優質iOS程式教學,你不必每天上站,輸入你的電子郵件地址訂閱網站的最新教學文章。每當有新文章發佈,我們會使用電子郵件通知你。

已收你的指示。請你檢查你的電郵,我們已寄出一封認證信,點擊信中鏈結才算完成訂閱。

Shares
Share This