轉自:http://www.cnblogs.com/shenhaocn/archive/2011/03/13/1982957.html
什麼是版本控制
要了解什麼是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的應用與技巧。盡請期待!
【作者】sky
【出處】http://www.cnblogs.com/sky-heaven/
【部落格園】 http://www.cnblogs.com/sky-heaven/
【知乎】 http://www.zhihu.com/people/zhang-bing-hua
【我的作品---旋轉倒立擺】 http://v.youku.com/v_show/id_XODM5NDAzNjQw.html?spm=a2hzp.8253869.0.0&from=y1.7-2
【我的作品---自平衡自動循迹車】 http://v.youku.com/v_show/id_XODM5MzYyNTIw.html?spm=a2hzp.8253869.0.0&from=y1.7-2
【大餅教你學系列】https://edu.csdn.net/course/detail/10393
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利.