:::

GitHub入門 Part.3 GIT版本控制實作教學

2月 05, 2013 0 Comments Edit Copy Download

image

繼前一篇配置好git運作環境之後,這篇就是開始教大家實際上的操作。這包括了之前概念介紹時用到的Pull、Push、Commit、Conflict、Branch跟Check out等等常用的動作,並且跟每天上下班的情境做個結合,讓大家能夠把git版本控制融入到日常作業中。

  1. Part.1 版本控制介紹
  2. Part.2 工具安裝與環境配置
  3. Part.3 Git版本控制實作教學

投影片

(Google DocSkyDriveBox.net)

這次也跟前一篇一樣做了投影片方便講解,但是投影片沒辦法寫很多細節,細節的部份請看下面文字敘述。

上班開始工作:Pull

image

上班囉!每天開工的第一件工作,就是先把遠端伺服器最新的程式碼下載下來,更新本機端的程式碼吧。

image

在儲存庫的資料夾底下按右鍵,開啟「Git 同步…」。

image

點下「拉取」(Pull)按鈕。如果順利的話,你的本機儲存庫就會直接跟遠端伺服器同步,把程式碼都更新為最新的狀態了。

工作中的習慣動作:Commit

image

當我們為了某些工作修改了儲存庫的原始碼之後,你會發現有些檔案的標示不太一樣。

image那些被修改的檔案前面都會有紅色驚嘆號「」的標示。這表示他的檔案狀態被標示為「已修改」。

image其他「未修改」的檔案則是維持原本的綠色打鉤「ˇ」標示。

當我們修改告一段落之後,我們就可以把目前的版本狀態做一次commit。

image

首先是在儲存庫按右鍵,執行「Git 提交 –> "gh-pages"」。後面的「gh-pages」表示現在的分支,一般來說,通常會是「Master」主幹。

image

接著會跳出Commit對話視窗。上面訊息記錄你必須輸入一些文字,記錄你這次修改的內容與目的。中間的變動列表會列出所有你這次修改的檔案。確認無誤之後,按下確定。

image

出現藍色文字表示Commit成功。

image

Commit之後,剛剛呈現「已修改」紅色驚嘆號的「.gitignore」檔案已經恢復成「未修改」的綠色鉤鉤。

你可以時常Commit你的儲存庫,Commit的間隔越短越好,但是每次Commit的版本內容最好都是確定可以運作的狀態,而不是改到一半無法運作的系統。

到目前為止,每次Commit其實都是在你本機端進行而已。這跟遠端的GitHub沒有關係,也跟你團隊中其他夥伴的電腦檔案沒有關係。

下班收拾工作:Push

image

我們今天的工作已經告一個段落了,準備把修改過很多次的程式碼送回遠端伺服器,也就是GitHub上。這時候我們要做的動作就是Push。

image

跟Pull一樣的,我們在儲存庫資料夾按下右鍵,開啟「Git 同步…」。

image

不同的是,我們這次要做的動作是Push(推送),請按下「推送」按鈕開始把本機端的儲存庫送到遠端伺服器GitHub上。如果順利的話,你就可以看到藍色的成功文字。

還不能那麼快下班:Conflict

image

有很多時候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到了伺服器上,這順序是這樣:

  1. Computer A Push了index.html,Push成功。
  2. GitHub上最新的index.html是Computer A的版本。
  3. Computer B Push了index.html,Push失敗。

image

現在Computer B嘗試Push,可是他失敗了,因為衝突發生,GitHub無法直接把Computer B的儲存庫加入伺服器中。

接下來,我就是要介紹發生衝突的時候,怎麼使用TortoiseGit來做合併、解決衝突。

1. 發生衝突的話就先Pull吧

image

既然遠端伺服器不接受你的Push,那就代表遠端伺服器有比較新的版本。我們必須先Pull取回遠端伺服器的版本來做個檢查。

2. 處理衝突清單

image

這份衝突清單會列出Git發現本機端跟伺服器端不同的檔案。請雙擊檔案名稱,我們來一一解決這些衝突。

3. 合併

image

TortoiseGit提供了一個精美的編輯器來合併程式碼:TortoiseGitMerge。從上圖中你可以看到左上角是「對方的 – REMOTE」程式碼,也就是代表位於GitHub上最新的程式碼端;右上角則是「我的 – LOCAL」,也就是本機端的程式碼;而下方「已合併 – index.html」則是合併雙方程式碼之後的結果。

請試著把遠端與本地端做個整合,然後再按照上圖所示位置「標記為已解決」。

4. Commit已解決的版本

image

解決這些已衝突的檔案之後,記得還是要做一次Commit喔。

5. 再度Push

image

接著我們再做一次Push。

image

這次的Push就會成功了。

如果又失敗,那可能是又發生衝突了。請再繼續Merge吧!

新功能開發:開啟Branch

image

接下來我們來實作分支的功能。現在我們試著在下一次commit的時候建立一個新的分支,叫做「demo-branch」。

image

要建立一個分支很容易,就是在Commit的時候,把「新建分支」打鉤,然後在「提交至」設定新分支的名稱「demo-branch」就可以了。

2013-02-05_200100

於是現在儲存庫所在的分支就會變成你新建的分支。按下右鍵時Git提交後面的名稱就是現在所在的分支。

接著你就可以在這個分支修改你要的功能,而不用擔心常常跟其他人衝突囉。

完成新功能開發:合併Branch

當我們的新功能已經開發完成之後,接下來我們就要把分支demo-branch現在的狀態合併到主幹master上。在TortoiseGit裡面有一套作法,請照著以下步驟來操作看看。

1. 切換分支:Checkout

image

首先,我們要先把儲存庫目前的版本HEAD切換回主要分支master上。這個動作叫做Checkout。

image

作法是在儲存庫按右鍵,進入TortoiseGit中的「切換/取出」。

image

先切換到你最終要保留的分支。雖然上圖是寫gh-pages,但通常會是master,也就是穩定的版本。

這個Checkout功能也可以用來切換到標籤、特定版本,方便我們快速回溯到之前的狀態,以便我們偵錯。

2. 合併分支

image

當你按右鍵的時候,會看到目前儲存庫的狀態移到了分支gh-pages中。然後接著我們使用的是TortoiseGit中的「合併」功能。

image

請選擇你要拿來合併的分支,也就是你剛剛開發完新功能的分支。

image

如果你的修改只是比master多推進幾個版本,Git會用Fast-forward merge來進行合併,這不太會有問題。如果順利的話,就會看到上圖藍字的訊息,表示成功。

3. 發生衝突

image

如果在你開了新分支之後,master又有往前推進幾個commit,那麼合併時就比較容發生衝突。按下左下角的「解決」吧。

2013-02-05_204319

這時候跳出了commit對話視窗,下面有變動的檔案清單。

回到檔案總管來看,index.html被標示了黃色三角形驚嘆號image,代表這個檔案發生了衝突,需要我們解決。

4. 解決衝突

2013-02-05_204533

在發生衝突的檔案index.html上按右鍵,然後進入TortoiseGit選擇「編輯衝突」。

image

然後會跳出TortoiseGitMerge編輯器。就跟之前在處理Push的衝突一樣,請在下方把衝突處理完,然後點選「標記為已解決」。

5. Commit解決衝突的版本

2013-02-05_204805

接著我們再做一次Commit,把解決衝突的版本儲存起來。到目前為止,我們順利地把demo-branch合併到master分支,但這只是本機端作業而已。

6. Push已合併的版本

2013-02-05_205025

最後我們把已經修改好了版本Push到GitHub。因為我自己測試時做了幾次解決衝突的過程,所以中間版本列表很多。其中你可以看到最上面一層會有Merge branch的訊息,表示在這之間我們的確做了一次合併分支。

image

如果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吧!