1. 程式人生 > >Linux 桌面玩家指南:13. 使用 Git 及其 和 Eclipse 的整合

Linux 桌面玩家指南:13. 使用 Git 及其 和 Eclipse 的整合

特別說明:要在我的隨筆後寫評論的小夥伴們請注意了,我的部落格開啟了 MathJax 數學公式支援,MathJax 使用$標記數學公式的開始和結束。如果某條評論中出現了兩個$,MathJax 會將兩個$之間的內容按照數學公式進行排版,從而導致評論區格式混亂。如果大家的評論中用到了$,但是又不是為了使用數學公式,就請使用\$轉義一下,謝謝。

想從頭閱讀該系列嗎?下面是傳送門:

參考資料

我是通過閱讀《Pro Git》這本書學習 Git 的,我讀的時候還是第一版的英文版,現在已經出第二版了,而且英文版和中文版都有。英文第二版的地址是 https://git-scm.com/book/en/v2,中文第二版的地址是https://git-scm.com/book/zh/v2。想看第一版的話把地址中的v2改成v1就可以了。如果哪天突然連結打不開了,也彆著急,記住《Pro Git》這個招牌,使用搜索引擎很快就能找到它。

Git 是什麼

Git 是一個版本控制系統,它可以儲存工作檔案的所有修訂版本。有了它你就可以將某個檔案回溯到之前的狀態,甚至將整個專案都回退到過去某個時間點的狀態,你可以比較檔案的變化細節,查出最後是誰修改了哪個地方,從而找出導致怪異問題出現的原因,又是誰在何時報告了某個功能缺陷等等。使用版本控制系統通常還意味著,就算你亂來一氣把整個專案中的檔案改的改刪的刪,你也照樣可以輕鬆恢復到原先的樣子。但額外增加的工作量卻微乎其微。

Git 的特點:

  1. Git是分散式的版本控制系統,它沒有中心伺服器的概念(雖然實際開發中可以建一箇中心伺服器),每一臺開發機器上都儲存完整的歷史記錄;但是它有原生代碼倉庫和遠端程式碼倉庫的概念(不然怎麼多人協作?),而且可以追蹤多個遠端倉庫。
  2. Git 在沒有網的情況下也可以工作。Git在本地磁碟上儲存有專案的完整歷史,Git 中的絕大多數操作都只需要訪問本地檔案和資源,一般不需要來自網路上其它計算機的資訊。所以 Git 能夠非常快地建立分支和合並分支,並具有強大的跟蹤分支和切換分支的能力。大部分操作看起來瞬間完成。有網的時候,再向遠端倉庫 push 一下就行了。
  3. Git 一般只新增資料。你執行的 Git 操作,幾乎只往 Git 資料庫中增加資料。 很難讓 Git 執行任何不可逆操作,或者讓它以任何方式清除資料。一旦你提交資料到 Git 中,就難以再丟失資料,特別是如果你定期的推送資料庫到其它倉庫的話。

下面是我簡化了的 Git 使用小結,圖片都來源於《Pro Git》第一版。

每一個專案都應該有一個工作目錄(Working directory),我們可以自己建一個目錄,然後把這個目錄裡面的程式碼用 Git 管理起來(使用git init命令和git add命令),也可以通過git clone命令從別的地方克隆一個專案過來自動生成一個工作目錄。在工作目錄中的檔案就是當前編輯和修改的檔案,如果是新建立的目錄或新克隆來的目錄,工作目錄中的檔案就是該專案最新的狀態。Git 是在本地儲存有所有的歷史記錄和分支記錄的,這些內容都在工作目錄的.git目錄中,稱之為本地倉庫(local repository)。當切換分支或檢視以前的歷史版本時,工作目錄中的檔案自動改變(這才是重點,工作無需切換目錄,目錄中的檔案會自動切換)。工作目錄中的檔案有三種狀態:已修改(modified)、已暫存(staged)、已提交(committed)。修改後的檔案可以先加入暫存區域,一次工作結束後一起提交。

Git是分散式的,沒有中心伺服器的概念,但實際工作中仍然可以把程式碼倉庫放到一臺大家都可以訪問的伺服器上,做實際的中心伺服器使用(僅在小團隊時使用此工作流程,原因後面詳述)。在本地機器上工作完後,使用git push命令把倉庫推送到伺服器上,換一個地方換一臺機器後,只需要git clone一下,又可以獲得所有的程式碼(包含所有的歷史記錄及分支)繼續工作。伺服器故障也沒問題,因為每一個工作的機器上都儲存有完整的程式碼倉庫,所以從不用擔心程式碼丟失。沒有網路也沒有關係,在本地機器上照樣可以提交(git commit),因為整個倉庫就在自己的機器上,當有網路時,git push一下就可以了。

Git有遠端倉庫(remote repository)的概念,而且可以管理很多個遠端倉庫,遠端倉庫可以是伺服器,也可以是別人的個人計算機(但一般沒有人這麼用),每一個遠端倉庫都有一個簡短的名字和一個地址,最開始用git clone克隆程式碼的那個遠端倉庫別名往往預設為 origin,自己新增的遠端倉庫可以隨意指定別名,當然所有的遠端倉庫都可以隨意修改別名。可以從遠端倉庫獲取程式碼(git fetch命令或git pull命令),也可以把自己的程式碼推送到遠端倉庫(git push命令,需要寫許可權)。

既然 Git 即可以隨便從遠端倉庫獲取程式碼,又可以把自己的程式碼推送到遠端倉庫,那麼當多人協作時,豈不會亂套嗎?解決這個問題的,就是 Git 的必殺之技——建立分支及分支合併。

首先,隨著一次次的提交,在原生代碼庫中形成一個主分支,如下圖:

有時為了開發新特性,隨時可以開一個新分支,如下圖:

新分支和主分支之間可以隨意切換,隨著分支的發展,形式如下圖:

主分支也可以向前發展,如下:

最終,當新分支程式碼很穩定以後,可以將其合併到主分支,如下圖:

而能夠防止多人協作時出現混亂的關鍵就在於,當從遠端倉庫 clone 程式碼庫到本地或 fetch 程式碼庫到本地時,遠端分支的標記並不等於本地分支的標記。從遠端 clone 一個程式碼庫到本地後,其 master 分支有兩個標記,一個標記為 origin/master 表示遠端庫中的 master 分支,一個標記為 master,表示本地的 master 分支。如下圖:

可以想象,由於別人的工作,遠端倉庫中的 master 分支肯定會向前繼續移動,但是在下次聯網之前,該 origin/master 標記不會移動。而本地的 master 標記繼續向前移動。

直到下次聯網,使用git fetch命令將遠端倉庫的內容取回本地,origin/master 標記才會改變位置,這時,看起來就像是兩個分支,如下圖:

最後,將 origin/master 分支合併到 master 分支中(使用git merge命令),原生代碼庫又一次變成了一個單一的 master 分支,繼續向前開發,並可以將它 push 到遠端倉庫,供別人使用。

Git衝突的處理完全靠人工完成。(從邏輯上講,機器也不可能完美處理衝突。)比如一個小型團隊一起工作,他們可以設定一個伺服器用於儲存遠端 Git 倉庫,然後每個人工作之前先從該遠端倉庫 fetch 程式碼,接著工作,工作完成後,先在本地提交,最後 push 到遠端倉庫。但是當一個人 push 的時候,已經有人在他之前 push 了,如果他們工作在同一個分支,就會出現衝突。解決衝突的辦法就是先把別人 push 的內容再次 fetch 下來,合併分支,然後再 push。

通過前面對git原理的瞭解,可以分析得出使用Git時有以下幾種工作流程:

  1. 一個人單幹,不需要考慮衝突,隨時可以開分支、合併分支和切換分支,隨時可以本地提交。如果為了防止程式碼丟失,可以開一個伺服器,每次工作完成就 push 到伺服器上;
  2. 小型團隊合作,如前所述,開一個伺服器儲存程式碼倉庫,然後所有的人把該伺服器當成遠端倉庫,工作之前先 fetch,工作之後再 push。如果有衝突,則先 fetch,合併分支解決衝突後再 push。如果團隊人數太多,每個人都向該伺服器 push,那衝突該是有多少?有可能一個開發者第一次向伺服器 push 的時候,有人在他之前已經 push 過了,他只好先 fetch,手工合併解決衝突,可等他再次 push 的時候,發現又有人再他之前已經 push 了,於是他只好再做一次解決衝突的流程,可是如果在他工作的時候,又有人 push 了呢?這也是之前講的該工作流程只適合小型開發團隊的原因。
    以上流程經過適當修改也可以供大型團隊使用,那就是將團隊分組,每個組的成員共用一個伺服器當遠端倉庫,組長合併了該組的工作成果後,再push到另一個伺服器當總的遠端倉庫,這樣就可以大大減少衝突的數量,減少工作量。
  3. 開源專案的合作,在這種情況下,每個人都把自己的倉庫暴露在網際網路上。開源專案的組織者或負責人將所有人的倉庫設為遠端倉庫,並把有意義的工作合併到主分支,然後釋出官方的 Git 倉庫。每個開發者從官方倉庫 fetch 程式碼後,完成自己的工作,然後再把它 push 到網際網路上自己的倉庫,等著專案負責人將自己的工作整合到官方倉庫中。如果專案負責人不幹了,改人了,只要還有人繼續開發,該專案就可以繼續下去。碰到團隊比較大的情況,也可以進行分組。

Git 伺服器的建設也相當簡單,因為 Git 支援以 SSH、HTTP 等協議傳輸資料,如果需要對伺服器有寫許可權,就開通 SSH 服務吧,設一個賬戶供所有人訪問 Git 倉庫即可。如果只需要讀許可權,使用任何一個 HTTP 伺服器均可。關於 Git 伺服器的建設,請自行參考官方文件。如果是個人的、開源的專案,可以使用 Github 網站提供的服務,直接儲存在網際網路上。(Github 私人倉庫是要收錢的。)

在 Eclipse 中使用 Git

得益於 Eclipse 中的 EGit 外掛,在 Eclipse 中使用 Git 非常簡單。任何一個專案,都可以使用快捷選單中的 "Team" -> "Share Project" 將檔案交給版本控制軟體管理,如下圖:

現在最流行的版本控制軟體當然是非 Git 莫屬了。Eclipse 會提示我們建立一個 Git 倉庫(Repository)。Eclipse 中的專案(Project)是一個比較小的概念,它不能等同於 Git 中的工作目錄(Working Directory),Git 中也沒有專案的概念,但是在 Git 的工作目錄中管理多個資料夾是沒有什麼問題的,而 Eclipse 中的專案就是一個資料夾,所以,在 Git 的一個工作目錄中管理多個 Project 是沒有問題的。因此,只有 Eclipse 的工作區(Workspace)才等同於 Git 中的工作目錄(Working Directory)。而 Git 的倉庫(Repository)一般是放在 Git 工作目錄中的一個.git目錄,考慮到 Eclipse 的工作區(Workspace)中本來就已經包含了很多元資料,再在裡面建立一個.git目錄,並且在裡面存放 Git 的資料容易引起混亂,因此最好是把 Git 的工作目錄和倉庫建立在 Eclipse 的 Workspace 之外。幸好,Eclipse 支援這樣的功能。如下圖,點選 "Create" 按鈕,建立一個 Git 倉庫,這裡輸入的路徑/home/youxia/git/samples其實是一個工作目錄:

從下圖可以看出,工作目錄為/home/youxia/git/samples,Git 的倉庫為/home/youxia/git/samples/.git,原本在 Workspace 中的專案 JavaIODemo 被自動移到了/home/youxia/git/samples目錄中:

可以使用 Navigator 檢視檢視專案中所有的檔案,沒有被 Git 跟蹤的檔案其圖示中顯示一個小問號。可以使用 "Ignore" 選單項讓 Git 忽略對某些檔案的跟蹤,比如原始碼編譯後產生的類檔案,如下圖:

使用 "Add to Index" 選單項讓 Git 對那些需要進行版本控制的檔案進行跟蹤,如下圖:

進行提交,如下圖:

提交時需輸入 Commit Message,並指定 Author 和 Committer,可以檢視此次提交涉及哪些檔案。如下圖:

已提交的檔案其圖示又會發生變化,如下圖:

再來看一下在一個倉庫中管理多個專案。再建立兩個專案,JaasDemo 和 SecurityDemo,點選選單項 "Share Project",在彈出的對話方塊中,不再選擇建立倉庫,而是選擇現有的倉庫,如下圖:

操作完成後,這三個專案都被同一個 Git 倉庫所管理。再有更多的專案都可以新增到這個倉庫中。我在 Github 中註冊了一個賬號,youxia 這個使用者名稱已經被佔用了,所以我只能用 youxia-cn,cn 代表中國,其實這個賬號挺好記的。然後,我又建立了一個 samples 倉庫,用來存放我部落格中寫的原始碼。以後大家需要參看我的原始碼的時候,只需要訪問 https://github.com/youxia-cn/samples 就可以了。

最後,把我本地的倉庫推送(Push)到 Github 中,如下三圖:


Clone、Pull 和 Fetch

從遠端倉庫中獲取資料的方法有多種。如果是第一次獲取遠端倉庫,可以使用git clone命令。在 Eclipse 中,需要使用 "File" -> "Import" 功能。下面換一臺電腦,這臺電腦安裝的是 Ubuntu 系統,啟動 Eclipse,點選選單 "File" -> "Import",獲取剛才存放在 Github 中的專案,在彈出的對話方塊中輸入正確的 URL 後,一路 Next,如下動圖:

可以使用 "Show in History" 和 "Show in Repositories View" 檢視倉庫的詳細資訊,如下兩圖:

從遠端倉庫獲取資料還可以使用git pull命令,其對應的 GUI 操作介面如下:

可以看到,它會讓你選擇是將遠端倉庫中的分支 Merge 到本地的當前分支還是將本地的當前分支 Rebase 到遠端倉庫中的分支。使用 Pull 功能時,分支的 Merge 和 Rebase 是自動進行的,所以如果沒有準備好的話,不要輕易使用。

安全的做法是使用git fetch命令從遠端倉庫獲取資料。Fetch 過來的分支不會自動合併,你可以切換到這些分支進行檢視,然後手工進行合併。其操作介面如下:

Checkout、Reset、Merge 和 Rebase

前面介紹過,隨著 Git 一次次的提交,會形成一個主分支,除此之外,還可以建立新的分支。通過git branch命令建立新分支,通過git checkout命令切換分支。在 Git 中,有一個HEAD指標總是指向當前正在工作的分支,如下圖:

如果切換分支,HEAD指標也會隨著移動,如下圖:

同時,還可以使用git reset命令改變HEAD指標的指向,以達到撤銷操作的目的。隨意改變HEAD指標的指向是危險的,特別是使用git reset命令的--hard選項的話,它會使我們的部分工作丟失。在《Pro Git》的第二版中專門有一節“重置揭祕”對該命令及其涉及的原理進行了論述。在 GUI 中使用 Reset 也是非常簡單的,如下圖:

而分支的合併又有兩種方式,Merge 和 Rebase。Merge 比較簡單,如下圖:

在圖中有兩個分支 origin 和 mywork,origin 做了提交 C3 和 C4,mywork 做了提交 C5 和 C6。如果將這兩個分支合併的話,就會產生提交 C7,如下圖:

但是如果使用 Rebase 就不一樣了,如果把 mywork 分支 Rebase 到 origin 上,就相當於把 C5 和 C6 中針對 C2 所做的修改在 C4 上重演一次,產生了 C5' 和 C6' 兩次提交,而原有的 C5 和 C6 會被丟棄,如下圖:

所以,Reset 和 Rebase 都是比較危險的命令,有引起資料丟失的風險。但是在 Git 中,只要是曾經 Commit 過的資料,都是可以找回來的,可以參考《Pro Git》中“維護與資料恢復”這一節(第一版位於第 9 章,第二版位於第 10 章)。另外,《Pro Git》提到,對於已經公開發布到遠端倉庫中的程式碼,不要使用 Rebase,否則會引起版本庫的混亂。

總結

GUI 介面的使用沒有什麼困難的,難的是理解 Git 中的概念,比如 Push、Pull、Clone、Fetch、Checkout、Reset、Merge、Rebase 什麼的。學習 Git 最好的辦法,當然是認真閱讀《Pro Git》這本寶典。除了使用 GUI,最好也能多敲一下命令列,這樣對 Git 會有更加深入的瞭解。

求打賞

我對這次寫的這個系列要求是非常高的:首先內容要有意義、夠充實,資訊量要足夠豐富;其次是每一個知識點要講透徹,不能模稜兩可含糊不清;最後是包含豐富的截圖,讓那些不想裝 Linux 系統的朋友們也可以領略到 Linux 桌面的風采。如果我的努力得到大家的認可,可以掃下面的二維碼打賞一下:

版權申明

該隨筆由京山遊俠在2018年11月15日釋出於部落格園,引用請註明出處,轉載或出版請聯絡博主。QQ郵箱:[email protected]