GitHub入門 Part.3 GIT版本控制實作教學
繼前一篇配置好git運作環境之後,這篇就是開始教大家實際上的操作。這包括了之前概念介紹時用到的Pull、Push、Commit、Conflict、Branch跟Check out等等常用的動作,並且跟每天上下班的情境做個結合,讓大家能夠把git版本控制融入到日常作業中。
- Part.1 版本控制介紹
- Part.2 工具安裝與環境配置
- Part.3 Git版本控制實作教學
投影片
這次也跟前一篇一樣做了投影片方便講解,但是投影片沒辦法寫很多細節,細節的部份請看下面文字敘述。
上班開始工作:Pull
上班囉!每天開工的第一件工作,就是先把遠端伺服器最新的程式碼下載下來,更新本機端的程式碼吧。
在儲存庫的資料夾底下按右鍵,開啟「Git 同步…」。
點下「拉取」(Pull)按鈕。如果順利的話,你的本機儲存庫就會直接跟遠端伺服器同步,把程式碼都更新為最新的狀態了。
工作中的習慣動作:Commit
當我們為了某些工作修改了儲存庫的原始碼之後,你會發現有些檔案的標示不太一樣。
那些被修改的檔案前面都會有紅色驚嘆號「!」的標示。這表示他的檔案狀態被標示為「已修改」。
當我們修改告一段落之後,我們就可以把目前的版本狀態做一次commit。
首先是在儲存庫按右鍵,執行「Git 提交 –> "gh-pages"」。後面的「gh-pages」表示現在的分支,一般來說,通常會是「Master」主幹。
接著會跳出Commit對話視窗。上面訊息記錄你必須輸入一些文字,記錄你這次修改的內容與目的。中間的變動列表會列出所有你這次修改的檔案。確認無誤之後,按下確定。
出現藍色文字表示Commit成功。
Commit之後,剛剛呈現「已修改」紅色驚嘆號的「.gitignore」檔案已經恢復成「未修改」的綠色鉤鉤。
你可以時常Commit你的儲存庫,Commit的間隔越短越好,但是每次Commit的版本內容最好都是確定可以運作的狀態,而不是改到一半無法運作的系統。
到目前為止,每次Commit其實都是在你本機端進行而已。這跟遠端的GitHub沒有關係,也跟你團隊中其他夥伴的電腦檔案沒有關係。
下班收拾工作:Push
我們今天的工作已經告一個段落了,準備把修改過很多次的程式碼送回遠端伺服器,也就是GitHub上。這時候我們要做的動作就是Push。
跟Pull一樣的,我們在儲存庫資料夾按下右鍵,開啟「Git 同步…」。
不同的是,我們這次要做的動作是Push(推送),請按下「推送」按鈕開始把本機端的儲存庫送到遠端伺服器GitHub上。如果順利的話,你就可以看到藍色的成功文字。
還不能那麼快下班:Conflict
有很多時候Push並不會這麼順利。舉例來說,上圖Computer A跟Computer B對同一份檔案做修改,然後下班時分別將該份檔案Push到伺服器,這樣就會發生衝突 Conflict,其中一方的Push會失敗。
發生衝突的原因:互相衝突的程式碼
團隊合作中很容易發生衝突,現在Computer A跟Computer B都修改了index.html。以下是Computer A對index.html的修改內容:
1: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
2: "http://www.w3.org/TR/html4/loose.dtd">
3: <html xmlns="http://www.w3.org/1999/xhtml">
4: <head>
5: <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
6: <title>New Web Project</title>
7: </head>
8: <body>
9: <h1>New Web Project Page</h1>
10: <!-- test 2 -->
11: </body>
12: </html>
然後是Computer B對index.html的修改內容:
1: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
2: "http://www.w3.org/TR/html4/loose.dtd">
3: <html xmlns="http://www.w3.org/1999/xhtml">
4: <head>
5: <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
6: <title>New Web Project</title>
7: </head>
8: <body>
9: <h1>New Web Project Page</h1>
10: <!-- test 1 -->
11: </body>
12: </html>
其中這兩個檔案的第10行內容是不一樣的,這就是發生衝突的原因。
然後他們修改之後各別Push到了伺服器上,這順序是這樣:
- Computer A Push了index.html,Push成功。
- GitHub上最新的index.html是Computer A的版本。
- Computer B Push了index.html,Push失敗。
現在Computer B嘗試Push,可是他失敗了,因為衝突發生,GitHub無法直接把Computer B的儲存庫加入伺服器中。
接下來,我就是要介紹發生衝突的時候,怎麼使用TortoiseGit來做合併、解決衝突。
1. 發生衝突的話就先Pull吧
既然遠端伺服器不接受你的Push,那就代表遠端伺服器有比較新的版本。我們必須先Pull取回遠端伺服器的版本來做個檢查。
2. 處理衝突清單
這份衝突清單會列出Git發現本機端跟伺服器端不同的檔案。請雙擊檔案名稱,我們來一一解決這些衝突。
3. 合併
TortoiseGit提供了一個精美的編輯器來合併程式碼:TortoiseGitMerge。從上圖中你可以看到左上角是「對方的 – REMOTE」程式碼,也就是代表位於GitHub上最新的程式碼端;右上角則是「我的 – LOCAL」,也就是本機端的程式碼;而下方「已合併 – index.html」則是合併雙方程式碼之後的結果。
請試著把遠端與本地端做個整合,然後再按照上圖所示位置「標記為已解決」。
4. Commit已解決的版本
解決這些已衝突的檔案之後,記得還是要做一次Commit喔。
5. 再度Push
接著我們再做一次Push。
這次的Push就會成功了。
如果又失敗,那可能是又發生衝突了。請再繼續Merge吧!
新功能開發:開啟Branch
接下來我們來實作分支的功能。現在我們試著在下一次commit的時候建立一個新的分支,叫做「demo-branch」。
要建立一個分支很容易,就是在Commit的時候,把「新建分支」打鉤,然後在「提交至」設定新分支的名稱「demo-branch」就可以了。
於是現在儲存庫所在的分支就會變成你新建的分支。按下右鍵時Git提交後面的名稱就是現在所在的分支。
接著你就可以在這個分支修改你要的功能,而不用擔心常常跟其他人衝突囉。
完成新功能開發:合併Branch
當我們的新功能已經開發完成之後,接下來我們就要把分支demo-branch現在的狀態合併到主幹master上。在TortoiseGit裡面有一套作法,請照著以下步驟來操作看看。
1. 切換分支:Checkout
首先,我們要先把儲存庫目前的版本HEAD切換回主要分支master上。這個動作叫做Checkout。
作法是在儲存庫按右鍵,進入TortoiseGit中的「切換/取出」。
先切換到你最終要保留的分支。雖然上圖是寫gh-pages,但通常會是master,也就是穩定的版本。
這個Checkout功能也可以用來切換到標籤、特定版本,方便我們快速回溯到之前的狀態,以便我們偵錯。
2. 合併分支
當你按右鍵的時候,會看到目前儲存庫的狀態移到了分支gh-pages中。然後接著我們使用的是TortoiseGit中的「合併」功能。
請選擇你要拿來合併的分支,也就是你剛剛開發完新功能的分支。
如果你的修改只是比master多推進幾個版本,Git會用Fast-forward merge來進行合併,這不太會有問題。如果順利的話,就會看到上圖藍字的訊息,表示成功。
3. 發生衝突
如果在你開了新分支之後,master又有往前推進幾個commit,那麼合併時就比較容發生衝突。按下左下角的「解決」吧。
這時候跳出了commit對話視窗,下面有變動的檔案清單。
回到檔案總管來看,index.html被標示了黃色三角形驚嘆號,代表這個檔案發生了衝突,需要我們解決。
4. 解決衝突
在發生衝突的檔案index.html上按右鍵,然後進入TortoiseGit選擇「編輯衝突」。
然後會跳出TortoiseGitMerge編輯器。就跟之前在處理Push的衝突一樣,請在下方把衝突處理完,然後點選「標記為已解決」。
5. Commit解決衝突的版本
接著我們再做一次Commit,把解決衝突的版本儲存起來。到目前為止,我們順利地把demo-branch合併到master分支,但這只是本機端作業而已。
6. Push已合併的版本
最後我們把已經修改好了版本Push到GitHub。因為我自己測試時做了幾次解決衝突的過程,所以中間版本列表很多。其中你可以看到最上面一層會有Merge branch的訊息,表示在這之間我們的確做了一次合併分支。
如果Push成功,那麼我們合併分支的工作就大功告成囉!
結語:Git還有很多功能!
我在跟實驗室的同學們介紹完上述的基本功能之後,大家對於Git還是有很多好奇的地方。像是有沒有單一檔案回溯功能啦、或是應該安排時間統一進行Merge,以免一直發生Conflict。大家的意見都很有意思,也加深了我對Git的期許。
上述的基本功能只是基本中的基本,實務上Git還有重新接樹Rebase、全新樹Stashing、里程碑Tag等功能,而GitHub常見的開發模式也並非上述介紹的單一中心式(所有人都連到KALS儲存庫做開發)、而是聯合管理員式(大家都Fork各自的KALS標註系統,然後透過Pull Request來整合到正統Blessed的KALS標註系統,可以想像成是大型Branch的感覺)等方式。想更進一步了解這些概念的人可以參考Littlebtc的「寫給大家的Git教學」投影片。
而TortoiseGit還有許多功能是我們尚未探索到。可能隨著協同作業複雜化,未來我們會繼續探究更多其他的功能吧。
希望透過這些文章的介紹,大家也能一起來co-work,Coding Together吧!