最近公司來了不少小伙伴,一開始我只是以為他們對Git使用不熟練,我跟他們零零散散講過幾次Git的一些使用方法,讓他們回去自己上網(wǎng)找些資料看看,感覺對他們來說這些不是什么問題。直到有一天,我讓他們提交代碼的時候,他們半天都提交不上來。我過去打聽原因的時候,驚訝地發(fā)現(xiàn)他們在磁盤里面的項目都是按日期命名文件夾存放的,合并代碼是通過手工對比工具完成的。經(jīng)過交流,我發(fā)現(xiàn)他們認為Git的門檻比我想象中還要高。貌似有SVN使用經(jīng)驗的人學習Git會感覺很不適應。我想只要把Git的一些概念搞清楚,學習起來應該也不難。于是,我想結(jié)合自己粗淺的一些理解,聊聊Git。首先從Git是什么說起吧。
Git是什么
事情是這樣的,自2002年開始,林納斯·托瓦茲決定使用BitKeeper作為Linux內(nèi)核主要的版本控制系統(tǒng)用以維護代碼。到了2005年,Linux內(nèi)核開發(fā)團隊的安德魯·垂鳩寫了一個簡單程序,可以連接BitKeeper的存儲庫。這時BitKeeper著作權(quán)擁有者拉里·麥沃伊不高興了,認為這事對BitKeeper內(nèi)部使用的協(xié)議進行逆向工程,于是決定收回Linux內(nèi)核開發(fā)團隊無償使用BitKeeper的許可。這點小事肯定難不倒大神林納斯,僅僅10天之后,第一個git版本就寫出來了。看到這里大家應該都知道git是一個版本控制管理系統(tǒng)了。對,Git就是一款開源的分布式版本控制系統(tǒng)(Distributed Version Control System)。
版本控制系統(tǒng)
為什么需要版本控制?舉個栗子,某天產(chǎn)品經(jīng)理提了一個新需求,程序員阿禿經(jīng)過連續(xù)幾個晚上通宵奮戰(zhàn),終于用方案A完美實現(xiàn)了。然后高興都跑去讓產(chǎn)品經(jīng)理驗收。產(chǎn)品經(jīng)理看完后,丟給阿禿一句,這是什么狗屎?不行,給我換方案B重做。阿禿只好把方案A的代碼都刪了,按照方案B,再經(jīng)過幾個晚上的奮戰(zhàn),用方案B把需求實現(xiàn)了。阿禿又高興地跑去讓產(chǎn)品經(jīng)理驗收。這時產(chǎn)品經(jīng)理說,好像還是方案A合理一點,你給我改回方案A吧……此時阿禿是奔潰的,因為他沒有使用版本控制工具。如果使用Git做版本控制的話,只需在鍵盤上敲入幾行命令就能找回方案A的代碼,阿禿自然不用再通宵了。版本控制是指對軟件開發(fā)過程中各種程序代碼、配置文件及說明文檔等文件變更的管理,是軟件配置管理的核心思想之一。運用版本控制系統(tǒng),我們可以對代碼進行版本管理,可以隨時查看之前版本的內(nèi)容,隨時回溯到之前版本中。團隊合作的時候也可以自動合并代碼,而不需要用一個共享文件,或者是進行定期的備份。
集中式和分布式版本控制系統(tǒng)
要理解SVN和Git的使用差別為什么那么大,最直接的辦法是搞清楚集中式和分布式版本控制系統(tǒng)之間的差別。集中式版本控制系統(tǒng)有單一的集中管理服務器,保存所有文件的修訂版本,所有的文件??蛻舳说碾娔X并不會保存歷史版本,所以如果想查看歷史版本,必須聯(lián)網(wǎng)才能查看,并且如果集中管理的服務器出現(xiàn)故障,可能導致歷史版本丟失,最多只能從本地的文件恢復到最后的版本。另外網(wǎng)速直接影響提交和下載文件的速度,很多時候很影響使用體驗。
分布式版本控制系統(tǒng)沒有集中管理的服務器,每個人的電腦都有一個完整的版本庫,我們可以在本地進行修改提交,查看歷史版本。這里很多人有個疑問,我們平時工作中,經(jīng)常把代碼推到“遠程倉庫”,這個“遠程倉庫”不就是集中式版本控制系統(tǒng)里面的集中管理服務器嘛?其實,這只是分布式版本控制系統(tǒng)里面的一個節(jié)點而已,這和你自己的電腦還有你同事阿禿的電腦一樣,都是可以理解為其中一個節(jié)點。為了協(xié)作方便,我們都在這個“遠程倉庫”上面交換“修改”,所以容易給大家造成中央服務器的錯覺。
基本概念
- 工作拷貝(工作目錄):用于存放產(chǎn)品開發(fā)數(shù)據(jù)本地工作目錄。
- 暫存區(qū) (Index):用于存放待提交數(shù)據(jù)的緩存區(qū)。
- 本地倉庫:遠端庫的一個完整的拷貝,包括所有文件的修改記錄,分支等。
- 遠程倉庫:本地倉庫clone來源。
- 快照(snapshot):版本庫某個時間點所有文件集合。
- 全球版本號(commitID):Git庫的版本號是通過SHA-1算法根據(jù)庫中的所有內(nèi)容計算出一個40位的哈希值,這個哈希值是全球唯一的,基本只要前六位就可以唯一標識了。
理解修改文件在Git的流動
我們所有修改都是在工作目錄進行的,修改完以后需要先添加到暫存區(qū),然后再提交到本地倉庫。提交完以后會產(chǎn)生commitID,標識當次提交。在之后的操作中,可以通過commitID回滾到某次提交狀態(tài)。最后,我們還需要把本地的倉庫的提交記錄推送到遠程倉庫。
基本操作
初始化倉庫
倉庫的初始化有兩種方式,第一張是直接在當前目錄初始化,執(zhí)行如下命令:
git init
另外一種是從遠程倉庫克隆,執(zhí)行命令如下:
git clone 中心庫名稱地址 本地工作目錄名稱
添加文件到暫存區(qū)
實際工作中,我們在本地初始化倉庫以后,就會往工作目錄里面新增文件或者修改倉庫里面已有的文件,當我們完成我們的新增或者修改后,需要把新增或者修改的文件添加到暫存區(qū),執(zhí)行命令如下:
git add 文件名
添加所有文件可以執(zhí)行以下命令:
git add .
提交到本地倉庫
接下來,我們就需要把暫存區(qū)的文件提交到本地倉庫,執(zhí)行命令如下:
git commit -m '提交信息'
更新本地分支
在我們把本地倉庫的提交記錄push到遠程倉庫之前,最好先pull遠程倉庫對應的“追蹤分支”的更新。我們需要用到git pull 命令。git pull 命令的作用是拉取遠程主機某個分支的更新,并與本地指定分支合并。很多時候代碼沖突是需要在這時候解決的。git pull的完整使用方法如下:
git pull <遠程主機名> <遠程分支名>:<本地分支名>
其實Git本地分支和遠程分支之間可以建立一種追蹤關(guān)系(tracking)。在使用git clone初始化倉庫的時候,所有本地分支默認與遠程倉庫的同名分支建立追蹤關(guān)系。比如,本地的master分支自動追蹤origin/master分支。
注意:origin一般指原始倉庫地址的別名
另外也可以手動建立這種追蹤關(guān)系,命令如下:
git branch --track <本地分支名> <遠程主機名>/<遠程分支名>
如果當前本地分支和遠程分支建立了追蹤關(guān)系,使用git pull就可以省略遠程分支名,命令如下:
git pull origin
如果當前分支只有一個追蹤分支,那么遠程主機名也可以省略,命令如下:
git pull
本地倉庫提交記錄推送到遠程倉庫
為了實現(xiàn)團隊協(xié)作,我們的更改,最終肯定需要推送到遠程倉庫,讓團隊中的其他同學合并的。這里我們使用git push命令,完整命令如下:
git push <遠程主機名> <本地分支名>:<遠程分支名>
和git pull一樣,如果本地分支和遠程分支之間存在“追蹤關(guān)系”,我們可以省略遠程分支名,命令如下:
git push <遠程主機名> <本地分支名>
這里需要注意,如果省略的是本地分支名,就相當于把一個空的本地分支推送到遠程分支,這個操作就是刪除遠程分支。
git push <遠程主機名> :<遠程分支名>
#相當于
git push <遠程主機名> --delete <遠程分支名>
查看提交歷史
很多時候由于各種原因,我們需要回滾到某次歷史提交,這時候可以通過一下命令查看:
git log
代碼回滾
代碼回滾主要有兩種方式,git revert和git reset。
- git revet是提交回滾,即忽略指定的版本,然后提交一個新的版本。新的版本中會刪除指定的版本。注意:git revert是會產(chǎn)生一次新的提交的。
git revert < commitID >
- git reset的作用是重置到指定的版本。通常是配合以下兩種參數(shù)一起使用的: --soft 和 --hard。
默認參數(shù) --soft, 所有commit的修改都會退回到git緩沖區(qū)。
參數(shù)--hard,所有commit的修改直接丟棄。
命令如下:
#回退到上個版本
git reset --hard HEAD^
#退到/進到 指定commitID
git reset --hard < commitID >
人生總是無常的,有時候你回滾完代碼后,可能你又后悔了,你又想回滾到你回滾之前,怎么辦?git reflog可以幫到你。你用git reflog打印你的每一次操作,找到你的操作id,就可以輕松回到你回滾之前的版本了。具體命令如下:
#查看你回滾操作,找到回滾操作的commitID
git reflog
#回退到指定的回滾版本
git reset --hard < commitID >
總結(jié)
git之所以如此強大,是因為它可以通過各種命令靈活使用,應對各種復雜的場景。機械地記憶幾條命令的組合是沒辦法滿足各種使用場景的,所以有時間還是需要慢慢理解各個命令的使用細節(jié)。熟練掌握上面那幾條命令應該可以應付日常工作的大部分使用場景了,當然git還有很多其他很強大的命令,大家可以深入學習一下。