Git(分布式版本控制系統(tǒng))
Git
Git是一個開源的分布式版本控制系統(tǒng),可以有效、高速地處理從很小到非常大的項目版本管理。
Git的特點
分布式相比于集中式的最大區(qū)別在于開發(fā)者可以提交到本地,每個開發(fā)者可以通過克?。╣it clone)在本地機器上拷貝一個完整的Git倉庫。
優(yōu)點
1.適合分布式開發(fā),強調(diào)個體。
2.公共服務(wù)器壓力和數(shù)據(jù)量都不會太大。
3.速度快、靈活。
4.任意兩個開發(fā)者之間可以很容易的解決沖突。
5.離線工作。
缺點
1.學(xué)習(xí)周期相對而言比較長。
2.代碼保密性差,一旦開發(fā)者把整個庫克隆下來就可以完全公開所有代碼和版本信息。
Git的一些操作及相關(guān)概念
創(chuàng)建版本庫:git init
版本庫又名倉庫,英文名repository,你可以簡單理解成一個目錄,這個目錄里面的所有文件都可以被Git管理起來,每個文件的修改、刪除,Git都能跟蹤,以便任何時刻都可以追蹤歷史,或者在將來某個時刻可以“還原”。
- 首先,選擇一個合適的地方,創(chuàng)建一個空目錄(目錄名不要包含中文):
例如:
然后在該文件夾里右鍵單擊選擇Git Bush Here,在彈窗中輸入:
$ mkdir learngit
$ cd learngit
$ pwd
pwd命令用于顯示當(dāng)前目錄。我的倉庫位于/e/Git/the first repository/learngit

-
第二步,通過git init命令把這個目錄變成Git可以管理的倉庫:
(這是一個空倉庫,當(dāng)前目錄下多了一個.git的目錄,這個目錄是Git來跟蹤管理版本庫的,不能亂動。如果沒有看到.git目錄,那是因為這個目錄默認(rèn)是隱藏的,用ls -ah命令就可以看見。)
把文件添加到版本庫
所有的版本控制系統(tǒng),其實只能跟蹤文本文件的改動,比如TXT文件,網(wǎng)頁,所有的程序代碼等等,Git也不例外。版本控制系統(tǒng)可以告訴你每次的改動,而圖片、視頻這些二進制文件,雖然也能由版本控制系統(tǒng)管理,但沒法跟蹤文件的變化,只能把二進制文件每次改動串起來,也就是只知道圖片的占用內(nèi)存大小變了,但到底改了啥,版本控制系統(tǒng)不知道,也沒法知道。
(windows系統(tǒng)不要使用自帶文本軟件,可使用Notepad++代替)
先編寫一個readme.text文件,內(nèi)容如下:
Git is a version control system.
Git is a free software.
把這個文件放到learngit目錄下(子目錄也行),即一定要放到你的Git倉庫里面。接下來添加命令使文件添加到倉庫里面:
- 第一步,用命令
git add將文件添加到倉庫(可以同時將多個文件添加進倉庫):
$ git add readme.text
(沒有顯示其他東西就說明成功了) - 第二步,用命令
git commit將文件提交到倉庫:
$ git commit -m"wrote a readme file"
-m后面輸入的是本次提交的說明,可以輸入任意內(nèi)容,方便自己能從歷史記錄里找到自己的改動記錄。
git commit命令執(zhí)行成功后會有:1 file changed:1個文件被改動(新添加的readme. text文件);2 insertions:插入了兩行內(nèi)容(readme. text有兩行內(nèi)容)。
修改倉庫里的文件
在前面已經(jīng)添加了readme. text文件的基礎(chǔ)上,我們可以對文件進行修改,改成如下內(nèi)容:
Git is a distributed version control system.
Git is a free software.
用命令git status查看結(jié)果:

git status命令可以讓我們看到倉庫當(dāng)前的狀態(tài),這里顯示readme. text已經(jīng)被修改過了,但是這個修改還沒有提交。用命令
git diff可以查看文件具體修改的內(nèi)容:
這里顯示我們在第一行添加了
distributed。接下來就是提交修改的文件,提交修改的文件和之前提交新文件的步驟是一樣的:
- 第一步
git add
用命令git status查看倉庫當(dāng)前狀態(tài):
這里顯示將要被提交的修改包括了readme. text - 第二步
git commit
提交后,再用命令git status查看倉庫當(dāng)前狀態(tài):
這里顯示沒有需要提交的修改,工作目錄是干凈的。
查看歷史記錄
用命令git log可以查看提交日志:

這里可以看到最近的一次是
add distributed,最早的一次是wrote a readme file可以試試加上
--pretty=oneline參數(shù)使顯示的更簡潔:
(這里的一串?dāng)?shù)字和字母的組合是
commit id即版本號,例如33b2d9c···就是wrote a readme file的版本號)每提交一個新版本,Git就會把它們自動串成一條時間線。
版本回退
在Git中,用HEAD表示當(dāng)前版本,上一個版本是HEAD^,上上個版本是HEAD^^。如果版本過多可以用HEAD~number,例如往上100個版本:HEAD~100。
可以使用命令git reset使版本從add distributed回退到wrote a readme file:

可以看到版本已經(jīng)退回到了
wrote a readme file。使用命令
cat可以查看readme.text是否真的退回到了上一個版本:
使用命令
git log再次查看當(dāng)前版本庫的狀態(tài):
可以看到版本庫中只剩下第一個版本了。
現(xiàn)在可以使用
add distributed的版本號回到add distributed的版本:
這樣版本又回到了
add distributed。如果不記得版本號而且還把彈窗關(guān)了,可以使用命令
git reflog來查找之前的命令:
這樣就找到之前的版本號了。
工作區(qū)與暫存區(qū)
工作區(qū)(Working Directory)
就是能在電腦里面看到的目錄,比如這里的learngit文件夾就是一個工作區(qū)

版本庫(Repository)
工作區(qū)有一個隱藏目錄.git,這個不算工作區(qū),而是Git的版本庫。
暫存區(qū)(Temporary Area)
Git的版本庫里存了很多東西,其中最重要的就是稱為stage(或者叫index)的暫存區(qū),還有Git自動創(chuàng)建的第一個分支master,而前面用到的HEAD命令就是指向master的指針。

在之前的提交文件到倉庫的過程中:用
git add把文件添加進去,實際上就是把文件修改添加到暫存區(qū);用git commit提交更改,實際上就是把暫存區(qū)的所有內(nèi)容提交到當(dāng)前分支。因為創(chuàng)建Git版本庫時,Git自動創(chuàng)建了唯一一個master分支,所以現(xiàn)在,git commit就是往master分支上提交更改??梢院唵卫斫鉃椋枰峤坏奈募薷耐ㄍǚ诺綍捍鎱^(qū),然后,一次性提交暫存區(qū)的所有修改。
管理修改
Git管理的是修改,而不是文件。
舉個例子:
在readme.text中添加一行:
Git has a mutable index called stage.
然后添加并查看狀態(tài):

然后再修改一次
readme.text的內(nèi)容:刪除第一行的
distributed

再提交:

查看狀態(tài):

可以看到第二次的修改并沒有被提交。
提交后,用
git diff HEAD -- readme.text命令可以查看工作區(qū)和版本庫里面最新版本的區(qū)別:
如果想要第二次修改也被提交,則可以在第二次修改后
git add,和第一次修改一起git commit;或者在第一次修改被提交之后,再將第二次修改git add,然后單獨將第二次修改git commit:
撤銷修改
我們可以使用git checkout -- <file>來撤銷工作區(qū)(還沒有git add)的修改。
命令git checkout -- readme.text意思就是,把readme.text文件在工作區(qū)的修改全部撤銷,這里有兩種情況:
- 一種是
readme.text自修改后還沒有被放到暫存區(qū),現(xiàn)在,撤銷修改就回到和版本庫一模一樣的狀態(tài); - 一種是
readme.text已經(jīng)添加到暫存區(qū)后,又作了修改,現(xiàn)在,撤銷修改就回到添加到暫存區(qū)后的狀態(tài)。
總之,就是讓這個文件回到最近一次git commit或git add時的狀態(tài)。
先在readme.text里面加一句話:
oh my god!

此時并沒有
git add,我們可以使用命令git checkout -- readme.text進行撤銷:
如果不小心把這句話已經(jīng)
git add到暫存區(qū)了(但是還沒有git commit):
可以使用命令
git reset HEAD <file>把暫存區(qū)的修改重新放回工作區(qū):
然后再用
git checkout -- readme.text撤銷工作區(qū)的修改;
如果已經(jīng)將修改
git commit到版本庫里了,就使用版本回退的方法。(前提是沒有推送到遠程倉庫)
刪除文件
我們可以使用命令rm來刪除文件。
首先,先建立一個新的文件new.text并且提交:

現(xiàn)在使用命令
rm new text刪除文件:
此時只是在工作區(qū)中執(zhí)行了刪除
new.text文件的命令,但是文件依然存在于版本庫中,如果想要在版本庫中刪除new.text文件,那就用命令git rm刪掉,并且git commit:
假如是不小心誤刪了這個文件(還沒有從版本庫里刪除),我們依然可以用命令
git checkout來還原(即撤銷上一步操作)。(從來沒有被添加到版本庫就被刪除的文件,是無法恢復(fù)的?。?p>
遠程倉庫
遠程倉庫相當(dāng)于是一個服務(wù)器,你可以推送自己的東西到這個服務(wù)器上,同時也能拉取別人的推送。
創(chuàng)建遠程倉庫(在GitHub上創(chuàng)建)
- 第1步:創(chuàng)建SSH Key。在用戶主目錄下,看看有沒有.ssh目錄,如果有,再看看這個目錄下有沒有
id_rsa和id_rsa.pub這兩個文件,如果已經(jīng)有了,可直接跳到下一步。如果沒有,打開Shell(Windows下打開Git Bash),創(chuàng)建SSH Key:
$ ssh-keygen -t rsa -C "youremail@example.com"
把郵件地址換成自己的郵件地址,然后一路回車,使用默認(rèn)值即可,由于這個Key也不是用于軍事目的,所以也無需設(shè)置密碼。如果一切順利的話,可以在用戶主目錄里找到.ssh目錄,里面有id_rsa和id_rsa.pub兩個文件,這兩個就是SSH Key的秘鑰對,id_rsa是私鑰,不能泄露出去,id_rsa.pub是公鑰,可以放心地告訴任何人。 - 第2步:登陸GitHub,在主頁點擊右上角的個人頭像,選擇setting,然后在邊的列表里點擊SSH and GPG keys,再點擊New SSH key。填上任意Title,在Key文本框里粘貼
id_rsa.pub文件的內(nèi)容:
添加遠程庫
先在GitHub上新建一個倉庫

GitHub告訴我們,可以從這個倉庫克隆出新的倉庫,也可以把一個已有的本地倉庫與之關(guān)聯(lián),然后,把本地倉庫的內(nèi)容推送到GitHub倉庫。
現(xiàn)在,我們根據(jù)GitHub的提示,在本地的learngit倉庫下運行命令:
$ git remote add origin git@github.com:dragon-mystic/binglan-week1.git其中
orgin是遠程庫的意思,dragon-mystic是自己在GitHub上的賬戶名,binglan-week1是GitHub倉庫名稱。下面就可以把把本地庫的內(nèi)容推送到遠程,用
git push命令,實際上是把當(dāng)前分支master推送到遠程。由于遠程庫是空的,第一次推送master分支時,加上了-u參數(shù),Git不但會把本地的master分支內(nèi)容推送的遠程新的master分支,還會把本地的master分支和遠程的master分支關(guān)聯(lián)起來,在以后的推送或者拉取時就可以簡化命令。

這里出現(xiàn)了一個SSH警告,這是因為Git使用SSH連接,而SSH連接在第一次驗證GitHub服務(wù)器的Key時,需要你確認(rèn)GitHub的Key的指紋信息是否真的來自GitHub的服務(wù)器,輸入yes回車即可。Git會輸出一個警告,告訴你已經(jīng)把GitHub的Key添加到本機的一個信任列表里了。這個警告只會出現(xiàn)一次,后面的操作就不會有任何警告了。
此時刷新網(wǎng)頁可以看到GitHub的倉庫內(nèi)容和本地的一樣了:

從現(xiàn)在起,只要本地作了提交,就可以通過命令:
$ git push origin master把本地master分支的最新修改推送至GitHub。
從遠程庫克隆
首先先建立一個新的倉庫copy:

勾選
Initialize this repository with a README,這樣GitHub會自動為我們創(chuàng)建一個README.md文件。創(chuàng)建完畢后,可以看到README.md文件:
現(xiàn)在可以用命令
git clone來克隆倉庫:$ git clone git@github.com:dragon-mystic/copy.git
(這里克隆的是本地庫,后面同樣寫的是自己GitHub的倉庫地址)
copy會存在于本地庫的learngit目錄下,而且可以看到copy目錄下有README.md文件;
分支管理
一開始Git會自動創(chuàng)建一個分支master,Git用master指向最新的提交,再用HEAD指向master,就能確定當(dāng)前分支,以及當(dāng)前分支的提交點。每次提交master會跟著提交不斷延長,指向最新的提交。
創(chuàng)建與合并分支
創(chuàng)建新的分支之后,把HEAD的指向改變到新的分支上,繼續(xù)提交,新的分支就會根據(jù)后來的提交而移動,而原來的master就會停止在HEAD指向改變之前的最后一次的提交。
使用命令git checkout創(chuàng)建新的分支binglan:

git checkout命令加上-b參數(shù)表示創(chuàng)建并切換,相當(dāng)于以下兩條命令:
$ git branch binglan
$ git checkout binglan
Switched to branch 'binglan'
用git branch命令查看當(dāng)前分支:

*后面就是當(dāng)前分支。然后就可以在分支binglan上提交工作了。如果再想回到分支master上就使用命令git checkout就行了:
如果之前在分支上
binglan上做了任何的操作,在回到分支master之后是看不到的。使用命令
git merge可以合并分支(前提是你在分支binglan上進行了修改):
此時分支
master上的內(nèi)容就會和分支binglan上的一樣。上面顯示的Fast-foward是快進的意思,由于這次的修改你較小,所以合并速度很快。合并完成后可以使用命令
git branch -d刪除分支:
就只剩下
master分支了:
switch
這是一個更科學(xué)的命令,同樣可以用來創(chuàng)建合并分支:
創(chuàng)建并切換到新的binglan分支,可以使用:
$ git switch -c dev
直接切換到已有的master分支,可以使用:
$ git switch master
解決沖突
在兩個分支上分別做一個修改時(master分支和新分支各自都分別有新的提交),Git無法執(zhí)行“快速合并”,只能試圖把各自的修改合并,此時很有可能會發(fā)生沖突,此時Git會提示沖突,使用命令git status同樣可以查看這個沖突。此時需要手動去更改,使用命令git log --graph --pretty=oneline --abbrev-commit可以查看合并情況,最后再刪去新分支。
分支管理策略
在合并時,Git一般會使用Fast-forward的模式,但是在刪除分支之后會丟失這條分支的信息。使用命令git merge --no-ff -m "merge with no-ff" binglan可以強制禁用Fast-forward模式,Git會在merge時產(chǎn)生一個新的commit,這樣就可以在分支歷史上查看分支信息(git log)。
Git創(chuàng)建的master分支是很穩(wěn)定的,而自己創(chuàng)建的新分支是不穩(wěn)定的。所以一般都在自己創(chuàng)建的新分支上進行工作,最后再合并到master上。(在團隊合作的情況下非常實用,一人一條分支,最終合并到一起)
Bug分支
用于臨時修復(fù)Bug創(chuàng)建的一個臨時分支。當(dāng)在用自己創(chuàng)建的分支工作時突然要修復(fù)一個Bug,此時使用命令git stash可以隱藏當(dāng)前工作的分支并保存工作進度,再創(chuàng)建一個臨時分支去修復(fù)Bug。可以使用命令git stash list查看隱藏的分支,在Bug修復(fù)之后,刪去臨時分支,使用命令git stash apply恢復(fù)隱藏的分支,再使用命令git stash drop刪除隱藏分支時stash內(nèi)容(也可以使用命令git stash pop恢復(fù)并刪除)。stash可以重復(fù)使用多次,要恢復(fù)指定的stash,用命令$ git stash apply stash@{0}({}里面就是恢復(fù)的第幾次的stash)。
使用命令cherry-pick ···能復(fù)制一個特定的提交到當(dāng)前分支,···即你想要的`commit·的版本號。
Feature分支
用于開發(fā)新的東西,防止一些實驗性質(zhì)的代碼把主分支搞亂,F(xiàn)eature分支在合并時和Bug分支是一樣的,如果要強行刪除這個Feature分支,則要使用命令git branch -D <name>。
推送分支
當(dāng)從遠程倉庫克隆時,Git自動把本地的master分支和遠程的master分支對應(yīng)起來了,并且,遠程倉庫的默認(rèn)名稱是origin。可以使用命令git remote查看遠程庫的信息,或者,用git remote -v顯示更詳細(xì)的信息:

上面顯示了可以抓取和推送的origin的地址。
推送分支,就是把該分支上的所有本地提交推送到遠程庫。推送時,要指定本地分支,例如:
$ git push origin master。
- master分支是主分支,因此要時刻與遠程同步;
- 自己創(chuàng)建的主分支是開發(fā)分支,團隊所有成員都需要在上面工作,所以也需要與遠程同步;
- bug分支只用于在本地修復(fù)bug,就沒必要推到遠程了。
- feature分支是否推到遠程,取決于是否和其他人合作在上面開發(fā)。
抓取分支
一般情況下,別人從你的遠程庫clone只能看到你的master分支,但是如果別人想在你自己創(chuàng)建的分支binglan上開發(fā),就必須使用命令$ git checkout -b binglan origin/binglan創(chuàng)建遠程origin的binglan分支到本地。然后他就可以在binglan這個分支上進行修改并push。如果別人和你在這個分支上對相同的文件進行了修改,并且試圖推送,會發(fā)生沖突,此時需要用命令git pull把最新的提交從origin/binglan上抓取下來,然后在本地合并,解決沖突,再推送(在git pull時一定要先設(shè)置binglan和origin/binglan的鏈接: $ git branch --set-upstream-to=origin/binglan binglan再pull)。再將合并的沖突進行手動解決,就和分支管理的一樣。解決后再push。
結(jié)語
Git的功能真的很強大,可以實現(xiàn)多人協(xié)作開發(fā),能與別人分享自己的經(jīng)驗和作品,有關(guān)Git還要學(xué)的東西還很多。
插上一個Git常用命令總結(jié)(方便快速查找):


未完待續(xù)······







