git 入門

什麼是版本控制

要了解什麼是git,首先需要了解什麼是版本控制(Version Control),版本控制系統(Version Control System,簡稱VCS)是一種記錄一個或多個文件的變化的系統,這樣的系統能夠方便你今後調用找回某個特定時期(或版本)的文件。 版本控制系統廣泛地應用於程序開發等領域,它可以協助你將某個指定的文件(甚至是一整個項目)返回至某個之前記錄的狀態,查看發生了哪些變化、對變化進行比較或者是修正致命錯誤。 版本控制系統主要經歷了本地版本控制,集中式版本控制到分佈式版本控制的發展:

  • 本地版本控制(Local Version Control System)顧名思義就是本地化的版本控制系統,沒有網絡協作等較爲先進的版本控制的概念
  • 集中式版本控制意(Centralized Version Control System)爲有一臺版本控制服務器運行在那邊存放並提供一個項目中所有版本文件的服務,在很長一段時間內佔據主流,其中CVS與Subversion(SVN)爲其代表
  • 分佈式版本控制(Distributed Version Control System)克服了集中式版本控制可能因爲單點失敗造成的巨大損失的缺點,讓每一臺客戶端在每一次checkout操作後都完全鏡像整個版本控制中的項目。在分佈式版本控制系統中,任何一臺機器都可以視爲版本控制服務器。即使有一臺服務器失去服務能力,其它機器與系統可以繼續協作維持版本控制系統的正常運轉。git就是分佈式版本控制系統

git的歷史

在2005年,Linux內核開發團隊與其使用的分佈式版本控制系統BitKeeper的開發公司關係破裂,他們沒有了免費使用BitKeeper的特權。這直接催生了Linux開發社區自己開發一套分佈式版本控制系統的想法。 Linux開發社區借鑑了之前使用BitKeeper時看到的閃光點,並希望能夠在版本控制系統的速度、架構設計與各類特性支持中作出較好的改進與提升,於是,git誕生了。

基礎概念與機制

git與其它主流的VCS最大的區別就是,在項目版本更新的過程中,git記錄的並非是基於初始文件的變化數據,而是通過一系列快照(Snapshot,就像是個小型的文件系統)來保存記錄每個文件。如果有些文件在版本更新後沒有發生任何變化,那麼在新的版本中它會是一個指向最近一次更新的文件版本的鏈接。 此外,幾乎所有git的操作都是在本地進行的,所以,沒有了“延遲”,幾乎所有的操作都是瞬間完成的。例如,當你想要查看項目歷史時,不需要特地去服務器上抓取歷史記錄,直接在本地瀏覽即可。這意味着,你可以在本地對比兩個不同版本的文件的差別,可以在本地查看過去有哪些人對指定文件作出了修改與更新,可以……幾乎完全本地化的操作也讓這樣一種場景成爲了可能: 當一個人在飛機、火車上,或者是任何因素導致沒有網絡連接條件但是又必須抓緊時間對自己的項目進行修改與開發,同時又需要有版本管理系統來記錄每次他commit的歷史,這時,git提供了他所有需要的便利。

git使用SHA-1 Hash算法加密生成的40位字符串(而不是文件名)來記錄代表git中的每樣東西。格式就像這樣:

??6bafcdc09f3d6d416f6572f82082987a486d3098

git中的文件主要會處於三種狀態,它們分別是:

  • Committed: 文件或數據已經安全的存放在了git本地數據庫中
  • Modified: 文件或數據已經修改但是尚未commit到數據庫
  • Staged: 文件或數據已被標記要放入到下一次commit中

這樣的機制致使git的鏡像會由三個部分組成(假設有一個git目錄叫git-repo):

  • Git directory: 存放項目中所有元數據以及對象的地方(git-repo/.git/)
  • Working directory: 在這裏是從git項目數據庫中checkout出的一個單獨的(默認情況下是最新的)項目版本,用於對指定項目版本中的文件進行修改和編輯(git-repo/)
  • Staging area: 一般是存放在Git directory中的一個簡單的文件,裏面存放着下一次需要commit的文件的信息(在git-repo/.git/中)

安裝git

在快速瞭解了git的概念與歷史後,我們就要開始學習使用它了,自然而然的,第一步我們需要將git安裝到我們的系統中去。 衆所周知,不同的Linux發行版本有着不同的包管理模式,在大多數Linux發行版本的軟件源中,都會有現成的git包已經打好以提供yum,aptitude之類的工具直接解決依賴問題下載與安裝。 當然,你也可以手動下載最新的git源代碼包,自行編譯,不過需要注意一點的是,確保你已經解決了爲手動編譯git而需要解決的軟件依賴問題:

使用yum工具先行解決包依賴問題(適用於RHEL,CentOS,Fedora等):
# yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel
使用aptitude工具先行解決包依賴問題(適用於Debian,ubuntu等):
# aptitude install curl-devel expat-devel gettext-devel openssl-devel zlib-devel

完成這些依賴的安裝後,到這裏下載最新的git源代碼包,然後開始安裝:

$ tar -zxf git-xxx.tar.gz # xxx代表版本號
$ cd git-xxx/
$ make prefix=/usr/local all
$ sudo make prefix=/usr/local install

一旦git的安裝完成了,今後你可以使用git本身來獲取git最新的updates:

$ git clone git://git.kernel.org/pub/scm/git/git.git

git同樣能夠在Mac OS X與Windows上使用,具體的操作請參考de.google.com/p/git-osx-installer/">這裏de.google.com/p/msysgit/">這裏

其他Linux發行版本(例如archlinux,gentoo等),可參照各發行版本的官方手冊與說明使用各自的包管理工具安裝。

配置git

完成git的安裝後,不要急着使用,首先你需要對git進行一些小小的配置,它在git的應用(一般是項目開發中)是必要的。git提供了config工具(你也可以手動)來配置以下三份git配置文件:

  • /etc/gitconfig: git的系統全局配置文件,該配置文件中的配置選項對操作系統上所有使用git的用戶產生影響,使用git config –system可以針對此文件進行配置
  • ~/.gitconfig: git的用戶全局配置文件,該配置文件的配置選項對當前用戶產生影響,並且會覆蓋掉系統全局配置文件中已經存在的配置選項,使用git config –global可以針對此文件進行配置
  • .git/config: 該文件存在每個git鏡像下,其配置文件的配置選項僅對該git鏡像產生影響,它會覆蓋掉用戶全局配置文件中已經存在的配置選項

瞭解了配置git的文件位置與機制後,我們首先就來嘗試配置一下git的用戶信息:

$ git config --global user.name "Thomas"
$ git config --global user.email [email protected]

這時,你就會發現在~/.gitconfig文件中,多出了與用戶信息相關的配置(2條賦值語句) 在git的配置文件中,你可以針對用戶名、郵件地址、編輯器、diff工具等進行配置,具體的配置參數與方法使用命令

$ git help config

即可獲得。

開始git

初始化/獲取 git鏡像

要開始使用git,首先要做的就是創建或者獲取一個git鏡像,創建一個文件夾,將其初始化爲git鏡像:

$ pwd
/home/thomas/workspace/tmp
$ mkdir git-repo
$ cd git-repo/
$ git init
Initialized empty Git repository in /home/thomas/workspace/tmp/git-repo/.git/

在這裏可以看到,我建立了一個名爲git-repo的文件夾,並且將它初始化成爲git鏡像目錄,初始化的命令爲git init,?完成初始化後,會在目錄下創建一個名爲.git的子目錄,對了,這就是前面提到的Git directory。 你也可以通過git clone命令來獲取一個已存在的git鏡像:

$ git clone git://github.com/schacon/grit.git

默認情況下,clone命令執行後會根據服務器上git鏡像的目錄名創建目錄並進行git鏡像的clone,你也可以在上述命令後加上自己希望看到的目錄名(比如repo123)來將遠程的git鏡像clone到該目錄下:

$ git clone git://github.com/schacon/grit.git repo123

有了git鏡像後,我們就可以開始學習git的基本使用技巧了!

Modify -> Stage -> Commit -> Track

恭喜,現在你已經有一個git鏡像來學習、實驗或使用了。讓我從實際應用出發,一步步爲你介紹和解釋git的基本應用。

在git的世界裏,有兩類文件,分別是未追蹤(untracked)和已追蹤(tracked),已追蹤的文件是指已經放入了最新的git鏡像(snapshot)裏,已追蹤的文件又分爲三個狀態,分別是:

  • Unmodified: 文件沒有做過任何修改
  • Modified: 文件已被修改更新
  • Staged: 文件已經修改更新,準備commit的狀態

而未追蹤的文件指的就是在git的工作目錄下,所有尚未被提交放入git鏡像目錄中的文件。

在學會提交文件至git鏡像前,先介紹一個非常重要的工具,git status,它會告訴你目前git鏡像的狀態,在使用git的過程中,你將會始終依賴這個工具幫助你更出色的完成工作!

$ git status
# On branch master
#
# Initial commit
#
nothing to commit (create/copy files and use "git add" to track)

可以看出,git status給出了相當詳細的信息,第一行中首先給出的是git的分支(branch)狀態信息,branch會在將來的文章中進一步爲大家介紹,它是git的王牌特性之一。接着,git會告訴你現在還沒有東西提交到鏡像中,需要先使用命令git add來對文件進行追蹤。

所以,假設我們先在git的工作目錄中使用C語言寫一個helloworld的小程序,保存,我們得到一個文件: helloworld.c,然後,我們希望將這個文件被git鏡像追蹤(track)到,那麼我們需要:

$ git add helloworld.c

這樣,我們就將helloworld.c加入到了git鏡像中去進行版本控制,再次使用git status來查看目前的鏡像狀態:

$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached ..." to unstage)
#
#       new file:   helloworld.c
#

注意這裏它提到了changes to be committed,意思是該文件已經處於staged狀態,接下去你可以根據自己的需要將其提交(commit),或者如果你覺得這是一個誤操作,該文件不應當被提交,你可以通過git rm –cached命令來取消它的staged狀態(你會發現status信息中作出了精確的提示)。

現在,我們通過命令git commit將helloworld.c提交:

$ git commit

這時,會出現一個帶有status信息的文本給你編輯(使用什麼編輯器取決於你對git的配置),在以”#”開頭的註釋行下輸入一些文本,用於註釋此次提交,方便於其他代碼協作者的維護與理解!

你也可以通過命令參數-m來直接輸入註釋內容,加快提交速度:

$ git commit -m "comment here"

至此,你的文件helloworld.c已經處於tracked狀態!整個過程就是小標題中所說的從修改(創建)文件到最終提交的過程。

接下來,我們將會探討一些更爲有趣的git使用技巧!

git應用進階

在前一小節中,筆者舉出的只是helloworld式的git基礎應用,到這裏大家應該有一個可用的git鏡像以及一個已經被git追蹤管理的文件了吧,是不是很方便和快捷呢?這個小節中我會帶領大家瞭解更多git的工具與使用技巧。

修改已提交文件

現在,我們有一個helloworld.c在鏡像中進行版本控制了,我們發現這個文件有一個小錯誤,oh,有一個循環的條件寫錯了,趕緊修改一下這個不大不小的bug,針對文件完成修改更新後,我們可以通過git status看到:

# On branch master
# Changed but not updated:
#   (use "git add ..." to update what will be committed)
#   (use "git checkout -- ..." to discard changes in working directory)
#
#       modified:   helloworld.c
#
no changes added to commit (use "git add" and/or "git commit -a")

git status告訴我們,helloworld.c被修改過了,如果你想要提交,需要再次git add該文件,或者,你可以直接使用git commit -a跳過add的步驟,直接提交(尚未track的文件必須先git add才能進行提交)。

在提示中,還有提到說,如果你想撤銷對helloworld.c的修改,就可以使用git checkout命令來實現,這裏的情況會是:

$ git checkout -- helloworld.c

如果你這麼做了,你就會發現,你的helloworld.c又回到了之前沒有被修改過的時候的狀態。

git中的diff

在Unix/Unix-like系統中,幾乎都會有一個小巧的對比文件不同的工具叫做diff,在git中也有這麼一個工具,來詳細比較你修改後準備提交的文件與修改前的狀態的不同之處,恩,也許你猜到了,這個命令就是git diff

現在我們嘗試着再次修改一下helloworld.c,然後運行git diff:

$ git diff
diff --git a/helloworld.c b/helloworld.c
index befc634..a86316b 100644
--- a/helloworld.c
+++ b/helloworld.c
@@ -1,3 +1,4 @@
+/* new comment line */
 #include
 int main(void)
 {

通過git的diff工具,我們很容易發現,這次我在程序中新加入了一行註釋代碼。

添加新文件

恩,有了一個像樣的代碼文件後,我需要爲我的代碼寫些說明文檔,同時我也需要對這樣一篇文檔進行維護,那麼,就建立一個README.txt文件,並且將它track到git鏡像中去,看到這裏讀者們可以先自行嘗試一下:

$ echo README > README.txt
$ ls
helloworld.c  README.txt
$ git status
# On branch master
# Untracked files:
#   (use "git add ..." to include in what will be committed)
#
#       README.txt
nothing added to commit but untracked files present (use "git add" to track)

至此,就有一個新的文件已經隨時待命準備提交了,你可以清楚的看到git status非常聰明的將README.txt歸類爲了untracked files裏,現在我們將它加入git鏡像:

$ git add README.txt
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD ..." to unstage)
#
#       new file:   README.txt
#

你可以像之前那樣將README文件commit,但是這次我們將會展示的是如何unstage一個文件,在git status信息中,它告訴用戶使用git reset HEAD命令來unstage一個文件,我們嘗試一下:

$ git reset HEAD README.txt
$ git status
# On branch master
# Untracked files:
#   (use "git add ..." to include in what will be committed)
#
#       README.txt
nothing added to commit but untracked files present (use "git add" to track)

看,README.txt又回到了untracked狀態!

重命名git中的文件

假設現在我們需要修改README.txt的文件名,千萬要記得我們的文件在git的鏡像中進行版本控制管理,所以,不要魯莽的直接使用unix命令mv或者rm來對git鏡像中的文件進行普通的文件操作,當然,如果你真的一不留神那麼做了,也不要緊。

git中,使用git mv工具來對文件進行重命名:

$ git mv README.txt tutorial.txt
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD ..." to unstage)
#
#       renamed:    README.txt -> tutorial.txt
#
$ git commit -a -m "renamed a file"
[master 55ce30d] renamed a file
 1 files changed, 0 insertions(+), 0 deletions(-)
 rename README.txt => tutorial.txt (100%)

可以看到,在提交變更後,README.txt在文件系統以及git鏡像中都被成功地重命名爲了tutorial.txt。同樣的,你可以unstage來撤銷對該文件的重命名,the choice is yours!

刪除git中的文件

如果我們不再需要tutorial.txt這個文件,我們可以將其從git鏡像中刪除,git中刪除文件的命令是git rm:

$ git rm tutorial.txt
rm 'tutorial.txt'
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD ..." to unstage)
#
#       deleted:    tutorial.txt
#
$ git commit -a -m " deleted a file"
[master 7d81981]  deleted a file
 1 files changed, 0 insertions(+), 1 deletions(-)
 delete mode 100644 tutorial.txt

正如之前所提到的,這些操作都是可以恢復的,因爲git是版本控制系統,所以自然而然的就會有一套版本歷史管理機制。

查看commit歷史

工具git log提供了查看git鏡像的commit歷史:

$ git log
commit 7d819818530ce89322019ba5000723c973eb0420
Author: ghosTM55
Date:   Sun Mar 14 15:26:22 2010 +0800
 
     deleted a file
 
commit 55ce30d88fb5c81d20bdf86e2034053613fed632
Author: ghosTM55
Date:   Sun Mar 14 15:11:39 2010 +0800
 
    renamed a file
 
commit 2ed9f1f9bd1a7561cd7e57dcdbd7f2cda54668fb
Author: ghosTM55
Date:   Sun Mar 14 14:58:11 2010 +0800
 
    a little change
 
commit dde0bab46a9d9f29c50d2996a9efe20253be9f15
Author: ghosTM55
Date:   Sun Mar 14 14:28:48 2010 +0800
 
    新文件來了,舊文件改了
 
commit c06c4e5ebc3a5281a3400c31c20e95ebd43f1547
Author: ghosTM55
Date:   Sun Mar 14 13:36:02 2010 +0800
 
    第一次提交

可以看到,git詳細記錄了每次commit的信息(checksum值、提交者信息、提交時間)。

獲取命令幫助

本(系列)文只是guide,不是manual,所以不會爲讀者詳細解釋每一個git命令的使用。當讀者想要詳細瞭解某命令的使用時,學會自己閱讀git自帶的manual文件是關鍵。

例如,如果你想了解更多有關於git log的使用方法,輸入命令:

$ git log help

即可。同樣的,你也可以通過google等方法獲取更多有關git的使用技巧!

總結

本文是git入門與實踐系列的第一篇,對git進行了最爲基礎的介紹與入門引導,在以後的文章中,我會爲大家進一步講解git的應用與技巧。盡請期待!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章