GIT & REPO & GERRIT (二)

GIT

想了很久,也不知道該如何下筆,那就從基本的概念說起吧。(下面如果沒有特別說明,那麼都是指在Unix下面使用GIT。)

Snapshot
GIT所設想的一個工作場景是這樣的:
  • 在寫代碼的過程中,我們會不斷對我們正在做的項目進行完整的備份,這樣,就算改錯了什麼東西,我們可以很容易的從某個備份點重新開始。
  • 然後,我們還需要能比較我們當前開發的內容和備份內容的差別(diff),這樣,我們就可以方便把代碼差異打包(patch)發給別人進行審覈(review)。
於是GIT就是這麼一個工具,讓這個流程自動化,並且提供了其他相關的強大功能。當然GIT實際上並不是每次對項目進行完整的備份,它有自己的另外一套更好機制來達到相同效果,而在GIT中每一次保存一個改動(commit)的時候,它的理念就是保存一個項目的當前的狀態,稱爲快照(snapshot)。而我們可以通過任何一個snapshot很方便的取回(或部分取回,比如只是某個文件)項目當時的狀態。

這是GIT的核心概念,要想運用好GIT,理解這個概念是非常重要的。

Repository
要使用GIT管理一個項目的時候,就需要一個倉庫(repository)用於存放GIT對項目管理所必須要保存的各種文件,使用 git init 命令創建一個新的倉庫。GIT會在當前目錄下創建一個.git文件夾,用作倉庫。然後,當你使用GIT記錄每一次代碼改動的時候,GIT就會把需要的信息都放到這個文件夾下面。

在使用GIT的時候,一般是還要配置一個用戶名和郵件地址,這不是註冊GIT賬戶,而是在你commit a change的時候,要有個作者的信息。通常來說,加一個全局的信息就可以了:
git config --global --add user.name Edward
git config --global --add user.email [email protected]
或者你可以選擇直接編輯~/.gitconfig,這個文件看起來是這樣的:
[user]
    email = [email protected]
    name = Edward

Commit
每當你完成一個改動(change)的時候,就可以commit一下,記錄當前項目的情況(snapshot)。每一個commit包含如下信息:
  • commit-id(sha-id):這是一個通過sha-1算法算出來的一個id,它不只作爲每個commit的唯一識別碼,也可以用來驗證保存的代碼是否損壞。所以在GIT在管理代碼的時候,如果發生代碼損壞,可以很有效的檢測到。
  • author:作者
  • date: 日期時間
  • log messge:一段作者對代碼改動的文字描述。
  • change-id:如果是和repo、gerrit一起使用的話,repo會加上這個信息,以便在整個代碼系統中識別同一個改動的多個版本。
用代碼管理軟件管理代碼的時候,有個理念就是:每次改動提交以後,整個項目都應該是可以工作的。所以,每次commit最好都能是這樣的的改動,雖然這不是必須的,但是這樣對項目整體質量的提高很有好處。

在GIT使用中,一個change開發的常見工作流程大概是這樣的:
  1. 新建一個工作分支(topic branch)
  2. 作一些代碼改動
  3. 查看當前狀態(很常用!):git status 查看當前branch以及那些文件有改動;git diff 查看目前爲止的詳細的改動情況。
  4. git add xxx 將這些改動暫時歸檔。在很多時候,一個change包含的東西並不少,我們在做到一半的時候通常也需要暫時保存一些東西。使用git add會將指定的文件的現有改動暫時保存下來(這個暫時歸檔的地方,GIT稱它爲staging area,可以認爲是一個臨時的snapshot。順便說一下HEAD,在GIT中,HEAD總是指向項目當前狀態最近的一次正式的snapshot。)。git add . 會將所有改動暫時歸檔。
  5. git reset xxx 將某個文件從staging area中移出來。git reset 不帶參數的時候,就是將staging area中所有的文件移出。
  6. 查看staging area中的詳細改動:git diff --cached
  7. 繼續寫代碼,git add xxx 將新的改動歸檔。
  8. 當你發現你的改動非常不合理,想要取消這些改動的時候:git checkout xxx 將某個文件恢復到修改之前(最後一次snapshot)。git checkout . 會恢復所有的文件到修改之前的狀態,很方便的功能,但使用的時候一定注意,不要讓自己的心血付諸流水。
  9. 重複上面的步驟,直到你認爲你的改動已經可以作爲一個有效的change,那你就可以執行 git commit 來將當前的改動真正的保存下來。記得在commit message裏面寫上適當的描述信息,這樣在查看代碼歷史的時候,就能方便的知道每個change都幹了些什麼。
  10. 有時候,你commit以後,你還發現還有需要修改的地方(特別是讓別人review的話,commit之後需要多次改動也是很常見的事情),那麼你就重複上面的步驟,不過在最後commit的時候加上 --amend 參數,這樣,它就會將目前的修改內容添加到最近的一次commit。如果忘記/誤用了 --amend 參數的時候怎麼辦呢?只要在編輯commit message的時候把內容全部清空,保存退出,GIT就會放棄這次commit。
  11. 根據情況,將這個改動合併(merge)回原來的主分支
經過上面的流程(某些步驟會不斷的重複),那麼一個有效且高質量的change就完成了。通過上面的這些步驟我們可以看出,在使用GIT來管理代碼的時候,我們可以很容易的在任何時候保存我們想要保存的項目狀態,並且可以很容易的取消某些文件的改動。這樣,我們修改代碼的時候,可以更隨心所欲的進行修改,只要我們採取了適當的行動,我們就不怕半途丟失了我們的成果。當然,你必須要對上面每一個步驟都很熟悉,纔能有隨心所欲的感覺。

Tag
在git中,每一個commit都是一個項目當時的snapshot,tag的作用就是給commit打上標籤。比如你當項目進行到某一點,你覺得可以發佈(release)一下,那你就可以在這個位置做一個標記,打一個tag,一個發佈點就被明確的標示出來了,這樣可以方便的對項目的情況進行管理。我通常把它理解爲某個commit的別名。GIT對項目的版本管理通常就是在這裏體現的。由於tag通常是用於項目發佈管理的,所以通常是項目管理人員來使用它。

查看tag情況:git tag
新建一個tag:git tag <tagname> <commitid>
刪除一個tag:git tag -d <tagname>
查看幫助:git tag -h

Branch
GIT最方便的莫過於本地分支(branch)的使用了。就開發來講,你需要嘗試你的各種想法,就發佈項目來說,不同的branch可以讓你有效的管理各個版本軟件的發佈以及維護。這裏只說說開發。

查看branch
git branch命令就可以查看本地當前的所有branch。常用的參數有:
-r 查看遠程(remote)的branch
-a 查看(本地+遠程)所有branch
-v 查看branch的時候顯示每個branch的最後一個commit信息

跳轉到一個branch
你任何時候只能在某一個branch上面,或者某一個特定的snapshot。
git checkout branchname 跳轉到某一個branch
git checkout sha1/tag 跳轉到某個指定的snapshot,這是你不在任何一個branch上面。

新建一個branch
git branch newbranch 從項目當前所在的commit創建一個branch
git checkout sha1/tag -b newbranch 從某一個指定的snapshot創建一個新的branch,並跳轉到新建的branch
git checkout remote_branch -b newbranch 以某個遠程branch最新的一個snapshot爲基礎創建一個新的branch,注意這不會影響遠程branch,因爲他的實質和上面其實是一樣的。

那麼我們該如何使用branch呢?首先,你要知道GIT是個分佈式的代碼管理工具,在你沒有和遠程代碼倉庫交流的時候,你的任何改動都是本地的,不用擔心影響到遠程代碼倉庫。而你只要不刻意去破壞你本地的倉庫,那麼,就大膽的使用branch吧,做各種嘗試。任何時候你有一個新的想法,在本地建一個branch盡情的去嘗試,很快你就會喜歡上這東西的。

如果是個多人協作項目的話,通常你的工作並不只是改動一個地方,那麼當你完成了某一個change正在等待review的時候,你就可以新起一個branch,接着就開始你的另一個change了。

Merge
有了分支你就可以盡情的做各種嘗試,隨心所欲的寫代碼。但我們通常是有一個主幹分支,然後我們把每個成熟的改動的合併(merge)到我們的主幹,這樣,項目才真正有效的在前進。這個工作流程就完美的解決了多人協作開發項目的問題:因爲每個人都是在自己的本地工作區進行修改,互不影響,在完成後將自己的成果放進主倉庫(某個remote repository)就可以了,最壞的情況就是可能會有些代碼衝突,但代碼衝突通常並不是什麼很難解決的問題:畢竟在分配任務的時候就會有大致進行安排,所以一般是不會有什麼無法解決的衝突。

說到merge的話,很多時候有人就會和rebase搞混。雖然兩個命令的功能都是把兩個branch合併起來,但是還是有很大差別的。

rebase主要用於如下情形:在多人協作的項目中,當你完成了一個改動以後,你發現別人已經在遠端主代碼倉庫添加了很多改動了,這時候很可能會有代碼衝突,或者已經有代碼衝突,那這時候,你就需要把你當前的工作branch更新到最新的狀態,然後解決代碼衝突,然後再提交你的change。這時候,你就:
  1. 從遠端獲取最新的代碼
  2. git rebase xxx 更新你當前的branch到最新狀態,然後把你的代碼改動放在最上面
  3. 向遠端提交代碼
而merge的話,就只是簡單的將兩個branch合併,如果出現GIT無法處理的衝突的時候,那麼就先採取上面的步驟,然後在merge。在Android的工作環境中,我們通常是不需要使用merge這個操作的,這個操作是在gerrit裏面完成review以後,點merge按鈕來完成的。

查看歷史
最常用的查看項目歷史(實際上是某個分支的歷史)的命令就是git log,常見用法如下:
  • git log 查看項目從當前位置(最近一個snapshot)之前的歷史記錄。可以這麼來理解:當你在某個branch上面的時候,這個snapshot就是當前分支的最新的一個comit,當你不在一個branch上面的時候,就是當前情況下最新的那個commit。
  • git log shaid/tag 同上,不過指定了snapshot的位置
  • git log file_name 同上上,不過查看的是特定文件相關的改動記錄
  • git log branch 查看特定branch的歷史記錄
  • git log branch file_name 同上,不過查看的是特定文件相關的改動記錄
  • git log --no-merges 由於GIT在進行merge的時候,會自動生成一個merge的commit,但其實這個commit本身是沒有內容的,--no-merges這個參數的作用就是在查看log的時候忽略這種commit。
這個命令可以滿足大部分需要查詢歷史記錄的情況,但有時候,你需要一個更強大的工具,那就是GITK。在當前branch下面,使用gitk命令,就可以使用gitk查看當前項目狀態之前的歷史記錄。它是一個有界面的工具,基本上是一目瞭然的,所以我也不過多的介紹,花幾分鐘去試試它吧。

Remote
GIT既然是分佈式代碼管理工具,那麼就必然涉及到遠程的交互了。GIT和遠端的交互可以通過常見的HTTP、HTTPS,在比較正式的項目中,通常是基於SSH的GIT協議。

以github.com爲例,上面支持3種方式:
  • HTTP:只是從服務器上下載代碼
  • HTTPS:需要登錄,可以下載和上傳代碼,但上傳代碼的時候需要每次登錄
  • SSH:配置好以後,GIT會自動採取SSH驗證關於SSH的配置,這是github上面關於如何配置SSH的幫助:https://help.github.com/categories/56/articles
在Android系統的管理中,由於和服務器的交互都是封裝在repo這個工具裏面,所以,通常是不需要用到remote操作的。所以只簡單說一下:
git remote 查看當前已添加的遠程服務器
git remote -v 同上,不過顯示更詳細的信息
git remote -h 查看幫助

其他
.gitignore
在開發一個項目的時候,有時候總會有些項目無關的文件,比如bin文件夾下面的內容,一般是不需要用GIT管理起來的。這時候,你就把這些文件的信息寫到.gitignore裏面,然後,把.gitignore的改動使用GIT管理起來,這樣,GIT在查詢狀態的時候,就會忽略在.gitignore裏面提到的文件。
color & alias
GIT可以給各個命令的輸出結果加上適當的顏色以提高視覺識別度,只需要簡單的配置即可。如果你嫌有些GIT命令太長,每次打完太麻煩,沒關係,有辦法,添加別名。
因此我通常會在我的/etc/gitconfig文件中加入如下的內容:
[color]
    ui = auto
[alias]
    st = status
    cm = commit
    cma = commit --amend
    br = branch -v
    cp = cherry-pick
    co = checkout
    df = diff
    dfc = diff --cached
如何使用alias:以第一個爲例,當我想用git status的時候,我打git st就可以了。

小結
GIT的功能很豐富,上面說的這些不過是一些常用的功能而已,要想把每個細節都說清楚的話,還遠遠不夠。想要用好GIT,還需要在實際運用中進行實踐和進一步學習。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章