PS:本文所有$
符號(hào)之后為在終端中執(zhí)行的命令。
版本控制系統(tǒng)
版本控制
版本控制(Version Control)的作用是追蹤文件的變化。為什么需要版本控制?簡(jiǎn)單說(shuō),就是當(dāng)你出錯(cuò)了,可以很容易地回到?jīng)]出錯(cuò)時(shí)的狀態(tài)。
你可能已經(jīng)在不知不覺(jué)中,布置了自己的版本控制系統(tǒng)。比如,創(chuàng)建了類似下面這樣的文件名:
- 論文_0510.doc
- 論文_0514.doc
- 論文_0521.doc
- 論文_修改版.doc
- 論文_最終不修改版.doc
這就是軟件中為什么有"Save As"命令的原因。它使得你可以在不破壞源文件的基礎(chǔ)上,得到一個(gè)類似的新文件。文件的多版本保存是一個(gè)常見(jiàn)問(wèn)題,通常的解決辦法是這樣的:
- 做一個(gè)文件備份(比如Document.old.txt)。
- 在文件名中加入版本號(hào)或日期(比如Document_V1.txt,DocumentMarch2007.txt)。
- 在多人編輯的環(huán)境下,共享一個(gè)文件目錄,并且要求每個(gè)人編輯完以后,在文件上做出標(biāo)識(shí)。
什么是版本控制系統(tǒng)(VCS)?
大型的、頻繁修改的、多人編寫的軟件項(xiàng)目,需要一個(gè)版本控制系統(tǒng)(簡(jiǎn)稱VCS,行話叫做"文件數(shù)據(jù)庫(kù)"),追蹤文件的變化,避免出現(xiàn)混亂。
一次典型的使用過(guò)程是這樣的:
愛(ài)麗絲add一個(gè)文件(list.txt)進(jìn)入repo。然后,她又把這個(gè)文件check out,做了一次編輯(在文件中加入milk這個(gè)單詞)。接著,她將修改后的文件check in,并附有一條checking message("加入了新的條目")。第二天早上,鮑勃update了他本地的working set,看到了list.txt的最新修訂版,其中包含了單詞"milk"。如果他使用changelog或diff,都可以發(fā)現(xiàn)前一天愛(ài)麗絲加入"milk"這個(gè)詞。
網(wǎng)上有許多VCS軟件可供選擇,并且都有詳細(xì)的教程或手冊(cè),比如SVN、CVS、RCS、Git、Perforce等等。
版本庫(kù)
版本庫(kù)又名倉(cāng)庫(kù),英文名repository,你可以簡(jiǎn)單理解成一個(gè)目錄,這個(gè)目錄里面的所有文件都可以被版本控制系統(tǒng)管理起來(lái),每個(gè)文件的修改、刪除,都能跟蹤,以便任何時(shí)刻都可以追蹤歷史,或者在將來(lái)某個(gè)時(shí)刻可以“還原”。
SVN
在Mac環(huán)境下,由于Mac自帶了SVN的服務(wù)器端和客戶端功能,所以我們可以在不裝任何第三方軟件的前提下使用SVN功能,不過(guò)還需做一下簡(jiǎn)單的配置。
為什么使用SVN
- 進(jìn)行權(quán)限管理,針對(duì)不同的人,開(kāi)放不同的權(quán)限。比如Alex是進(jìn)行A項(xiàng)目的,Bob進(jìn)行B項(xiàng)目的,那么SVN可以有效的管理每個(gè)人看到的項(xiàng)目,Alex不可能獲得Bob的項(xiàng)目,同樣Bob也不可能獲得Alex的項(xiàng)目。
- 對(duì)于代碼進(jìn)行追蹤,代碼不會(huì)遺失。不如今天代碼修改亂了,需要恢復(fù)到某一天的,那么我們只需要選擇一下恢復(fù)的日期即可進(jìn)行恢復(fù)。
搭建SVN服務(wù)器
1. 創(chuàng)建代碼倉(cāng)庫(kù),存儲(chǔ)客戶端上傳的代碼
先在~/Desktop
目錄(這個(gè)目錄可以是任意非中文路徑)新建一個(gè)svn目錄,以后可以在svn目錄下創(chuàng)建多個(gè)倉(cāng)庫(kù)目錄。
打開(kāi)終端,切換到該目錄cd ~/Desktop/svn
,創(chuàng)建一個(gè)learnsvn
倉(cāng)庫(kù),輸入命令:svnadmin create ./learnsvn
,執(zhí)行成功后,會(huì)發(fā)現(xiàn)在該目錄下多了一個(gè)LimitFree目錄。
2. 配置SVN的用戶權(quán)限
主要是修改./learnsvn/conf目錄下的三個(gè)文件
-
打開(kāi)svnserve.conf,將下列配置項(xiàng)前面的#和空格都去掉
# anon-access = read # auth-access = write # password-db = passwd # authz-db = authz
anon-access = read代表匿名訪問(wèn)的時(shí)候是只讀的,若改為anon-access = none代表禁止匿名訪問(wèn),需要帳號(hào)密碼才能訪問(wèn)
-
打開(kāi)passwd,在[users]下面添加帳號(hào)和密碼
[users] # harry = harryssecret # sally = sallyssecret chaosky = 123 student = 123456
帳號(hào)是chaosky,密碼是123
-
打開(kāi)authz,配置用戶組和權(quán)限
我們可以將在passwd里添加的用戶分配到不同的用戶組里,以后的話,就可以對(duì)不同用戶組設(shè)置不同的權(quán)限,沒(méi)有必要對(duì)每個(gè)用戶進(jìn)行單獨(dú)設(shè)置權(quán)限。
在[groups]下面添加組名和用戶名,多個(gè)用戶之間用逗號(hào)(,)隔開(kāi)
[groups] topgroup=chaosky,student
說(shuō)明chaosky和student都是屬于topgroup這個(gè)組的,接下來(lái)再進(jìn)行權(quán)限配置。
使用[/]代表svn服務(wù)器中的所有資源庫(kù)
[/] @topgroup = rw
上面的配置說(shuō)明topgroup這個(gè)組中的所有用戶對(duì)所有資源庫(kù)都有讀寫(rw)權(quán)限,組名前面要用@
如果是用戶名,不用加@,比如chaosky這個(gè)用戶有讀寫權(quán)限
[/] chaosky = rw
3. 啟動(dòng)SVN服務(wù)器
在終端輸入命令:svnserve -d -r ~/Desktop/svn
或svnserve -d -r ~/Desktop/svn/learnsvn
沒(méi)有任何提示就說(shuō)明啟動(dòng)成功了
4. 關(guān)閉SVN服務(wù)器
打開(kāi)活動(dòng)監(jiān)視器,輸入svnserve,強(qiáng)制退出進(jìn)程。
使用SVN客戶端功能
SVN客戶端有兩種使用方式,命令行和GUI界面軟件(CornerStone)
命令行工具
usage: svn <subcommand> [options] [args]
Subversion command-line client.
Type 'svn help <subcommand>' for help on a specific subcommand.
Type 'svn --version' to see the program version and RA modules
or 'svn --version --quiet' to see just the version number.
Most subcommands take file and/or directory arguments, recursing
on the directories. If no arguments are supplied to such a
command, it recurses on the current directory (inclusive) by default.
Available subcommands:
add
auth
blame (praise, annotate, ann)
cat
changelist (cl)
checkout (co)
cleanup
commit (ci)
copy (cp)
delete (del, remove, rm)
diff (di)
export
help (?, h)
import
info
list (ls)
lock
log
merge
mergeinfo
mkdir
move (mv, rename, ren)
patch
propdel (pdel, pd)
propedit (pedit, pe)
propget (pget, pg)
proplist (plist, pl)
propset (pset, ps)
relocate
resolve
resolved
revert
status (stat, st)
switch (sw)
unlock
update (up)
upgrade
Subversion is a tool for version control.
For additional information, see http://subversion.apache.org/
CornerStone
添加代碼倉(cāng)庫(kù)
填寫SVN倉(cāng)庫(kù)信息
基本操作
checkout(檢出)
add(添加文件)
delete(刪除文件)
modify (修改文件)
commit(提交)
update(更新)
resolve conflict(解決沖突)
revert(恢復(fù)初始狀態(tài))
Git
安裝Git
直接從AppStore安裝Xcode,Xcode集成了Git,不過(guò)默認(rèn)沒(méi)有安裝,你需要運(yùn)行命令xcode-select --install
安裝“Command Line Tools”,點(diǎn)“Install”就可以完成安裝了。
創(chuàng)建版本庫(kù)
-
選擇一個(gè)合適的地方,創(chuàng)建一個(gè)空目錄:
$ mkdir learngit $ cd learngit
-
通過(guò)
git init
命令把這個(gè)目錄變成Git可以管理的倉(cāng)庫(kù):$ git init Initialized empty Git repository in /Users/Chaosky/Desktop/learngit/.git/
瞬間Git就把倉(cāng)庫(kù)建好了,而且告訴你是一個(gè)空的倉(cāng)庫(kù)(empty Git repository),細(xì)心的讀者可以發(fā)現(xiàn)當(dāng)前目錄下多了一個(gè).git的目錄,這個(gè)目錄是Git來(lái)跟蹤管理版本庫(kù)的,沒(méi)事千萬(wàn)不要手動(dòng)修改這個(gè)目錄里面的文件,不然改亂了,就把Git倉(cāng)庫(kù)給破壞了。
把文件添加到版本庫(kù)
-
編寫一個(gè)README.md文件,內(nèi)容如下:
Git is a version control system. Git is free software.
一定要放到learngit目錄下(子目錄也行),因?yàn)檫@是一個(gè)Git倉(cāng)庫(kù),放到其他地方Git再厲害也找不到這個(gè)文件。
-
用命令
git add
告訴Git,把文件添加到倉(cāng)庫(kù):$ git add readme.txt
執(zhí)行上面的命令,沒(méi)有任何顯示,這就對(duì)了,Unix的哲學(xué)是“沒(méi)有消息就是好消息”,說(shuō)明添加成功。
-
用命令
git commit
告訴Git,把文件提交到倉(cāng)庫(kù):$ git commit -m "wrote a readme file" [master (root-commit) cb926e7] wrote a readme file 1 file changed, 2 insertions(+) create mode 100644 readme.txt
簡(jiǎn)單解釋一下git commit命令,-m后面輸入的是本次提交的說(shuō)明,可以輸入任意內(nèi)容,當(dāng)然最好是有意義的,這樣你就能從歷史記錄里方便地找到改動(dòng)記錄。
git commit命令執(zhí)行成功后會(huì)告訴你,1個(gè)文件被改動(dòng)(我們新添加的readme.txt文件),插入了兩行內(nèi)容(readme.txt有兩行內(nèi)容)。
為什么Git添加文件需要add,commit一共兩步呢?因?yàn)閏ommit可以一次提交很多文件,所以你可以多次add不同的文件,比如:
$ git add file1.txt $ git add file2.txt file3.txt $ git commit -m "add 3 files."
工作區(qū)和暫存區(qū)
-
工作區(qū)(Working Directory)
就是你在電腦里能看到的目錄。
-
版本庫(kù)(Repository)
Git的版本庫(kù)里存了很多東西,其中最重要的就是稱為stage(或者叫index)的暫存區(qū),還有Git為我們自動(dòng)創(chuàng)建的第一個(gè)分支master,以及指向master的一個(gè)指針叫HEAD。
前面講了我們把文件往Git版本庫(kù)里添加的時(shí)候,是分兩步執(zhí)行的:
第一步是用
git add
把文件添加進(jìn)去,實(shí)際上就是把文件修改添加到暫存區(qū);版本庫(kù)狀態(tài)第二步是用
git commit
提交更改,實(shí)際上就是把暫存區(qū)的所有內(nèi)容提交到當(dāng)前分支。版本庫(kù)狀態(tài)你可以簡(jiǎn)單理解為,需要提交的文件修改通通放到暫存區(qū),然后,一次性提交暫存區(qū)的所有修改。
?
版本庫(kù)管理
-
git status
查看倉(cāng)庫(kù)當(dāng)前的狀態(tài),要隨時(shí)掌握工作區(qū)的狀態(tài),使用git status命令。
-
git diff
如果git status告訴你有文件被修改過(guò),用git diff可以查看修改內(nèi)容。
-
git log
顯示從最近到最遠(yuǎn)的提交日志。在Git中,用HEAD表示當(dāng)前版本,也就是最新的提交,上一個(gè)版本就是HEAD^ ,上上一個(gè)版本就是HEAD^^ ,當(dāng)然往上100個(gè)版本寫100個(gè)^比較容易數(shù)不過(guò)來(lái),所以寫成HEAD~100。
-
git reset --hard commit_id
在版本的歷史之間進(jìn)行切換,
commit_id
為提交版本的id。 -
git reflog
用來(lái)記錄你的每一次命令
-
撤銷修改
場(chǎng)景1:當(dāng)你改亂了工作區(qū)某個(gè)文件的內(nèi)容,想直接丟棄工作區(qū)的修改時(shí),用命令
git checkout -- README.md
。場(chǎng)景2:當(dāng)你不但改亂了工作區(qū)某個(gè)文件的內(nèi)容,還添加到了暫存區(qū)時(shí),想丟棄修改,分兩步,第一步用命令
git reset HEAD README.md
,就回到了場(chǎng)景1,第二步按場(chǎng)景1操作。 -
git rm
用于刪除一個(gè)文件。如果一個(gè)文件已經(jīng)被提交到版本庫(kù),那么你永遠(yuǎn)不用擔(dān)心誤刪,但是要小心,你只能恢復(fù)文件到最新版本,你會(huì)丟失最近一次提交后你修改的內(nèi)容。
遠(yuǎn)程倉(cāng)庫(kù)
分布式版本控制系統(tǒng)通常也有一臺(tái)充當(dāng)“中央服務(wù)器”的電腦,而充當(dāng)"中央服務(wù)器"角色的倉(cāng)庫(kù)就是遠(yuǎn)程倉(cāng)庫(kù),但這個(gè)服務(wù)器的作用僅僅是用來(lái)方便“交換”大家的修改,沒(méi)有它大家也一樣干活,只是交換修改不方便而已。
如果有自己的私有倉(cāng)庫(kù)地址,則無(wú)需執(zhí)行下面幾個(gè)操作。
-
注冊(cè)遠(yuǎn)程倉(cāng)庫(kù)賬號(hào)
-
Git@OSC:開(kāi)源中國(guó)Git托管平臺(tái)
-
Github:世界最大的Git項(xiàng)目托管平臺(tái)
-
Coding:國(guó)內(nèi)新興的Git托管平臺(tái)
-
-
添加公鑰到Git托管平臺(tái)
-
生成公鑰
SSH Keys:SSH key 可以讓你在你的電腦和 Git托管平臺(tái)之間建立安全的加密連接。
你可以按如下命令來(lái)生成sshkey:
$ ssh-keygen -t rsa -C "xxxxx@xxxxx.com"
其中
xxxxx@xxxxx.com
需要填寫郵箱信息生成SSH key時(shí),如果不清楚需要輸入的信息,可以全部輸入Enter鍵。
-
查看你的public key,并把他添加到Git托管平臺(tái)
$ cat ~/.ssh/id_rsa.pub
具體添加的位置,查看具體的托管平臺(tái)。一般來(lái)說(shuō),在個(gè)人資料中可以找到
SSH-KEYS
類似的字樣就是添加公鑰的地方。 -
測(cè)試是否添加成功
測(cè)試Git@OSC輸入命令:
$ ssh -T git@git.oschina.net Welcome to Git@OSC, yourname!
測(cè)試Github輸入命令:
$ ssh -T git@github.com Hi chaoskyme! Youve successfully authenticated, but GitHub does not provide shell access.
生成SSH key只需要生成一次,不同的網(wǎng)站再將公鑰拷貝到網(wǎng)站上即可。
-
-
在Git托管平臺(tái)上創(chuàng)建項(xiàng)目
-
添加遠(yuǎn)程倉(cāng)庫(kù)
關(guān)聯(lián)一個(gè)遠(yuǎn)程倉(cāng)庫(kù)命令:
$ git remote add origin git@server-name:path/repo-name.git
其中
origin
表示遠(yuǎn)程倉(cāng)庫(kù)的別名,默認(rèn)為origin
git@server-name:path/repo-name.git
表示項(xiàng)目在Git托管平臺(tái)上的ssh 地址。關(guān)聯(lián)遠(yuǎn)程倉(cāng)庫(kù)只需要執(zhí)行上面的命令一次即可。
關(guān)聯(lián)后,第一次推送master分支的所有內(nèi)容命令:
$ git push -u origin master
此后,每次本地提交后,只要有必要,推送最新修改就可以使用命令:
$ git push origin master
分布式版本系統(tǒng)的最大好處之一是在本地工作完全不需要考慮遠(yuǎn)程庫(kù)的存在,也就是有沒(méi)有聯(lián)網(wǎng)都可以正常工作,而SVN在沒(méi)有聯(lián)網(wǎng)的時(shí)候是拒絕干活的!當(dāng)有網(wǎng)絡(luò)的時(shí)候,再把本地提交推送一下就完成了同步,真是太方便了!
-
克隆遠(yuǎn)程倉(cāng)庫(kù)
$ git clone git@server-name:path/repo-name.git <repo-name>
-
從遠(yuǎn)程分支獲取最新版本到本地,有2個(gè)命令
-
git fetch:相當(dāng)于是從遠(yuǎn)程獲取最新版本到本地,不會(huì)自動(dòng)merge
$ git fetch origin master $ git log -p master..origin/master $ git merge origin/master
以上命令的含義:
首先從遠(yuǎn)程的origin的master主分支下載最新的版本到origin/master分支上;
然后比較本地的master分支和origin/master分支的差別;
最后進(jìn)行合并。
-
git pull:相當(dāng)于是從遠(yuǎn)程獲取最新版本并merge到本地
$ git pull origin master
上述命令其實(shí)相當(dāng)于git fetch 和 git merge
在實(shí)際使用中,git fetch更安全一些
因?yàn)樵趍erge前,我們可以查看更新情況,然后再?zèng)Q定是否合并
-
分支管理
Git鼓勵(lì)大量使用分支:
查看分支:git branch
創(chuàng)建分支:git branch <name>
切換分支:git checkout <name>
創(chuàng)建+切換分支:git checkout -b <name>
合并某分支到當(dāng)前分支:git merge <name>
刪除分支:git branch -d <name>
當(dāng)Git無(wú)法自動(dòng)合并分支時(shí),就必須首先解決沖突。解決沖突后,再提交,合并完成。
用git log --graph
命令可以看到分支合并圖。
推送分支,就是把該分支上的所有本地提交推送到遠(yuǎn)程庫(kù)。推送時(shí),要指定本地分支,這樣,Git就會(huì)把該分支推送到遠(yuǎn)程庫(kù)對(duì)應(yīng)的遠(yuǎn)程分支上:
$ git push origin master
標(biāo)簽管理
git tag <name>
用于新建一個(gè)標(biāo)簽,默認(rèn)為HEAD,也可以指定一個(gè)commit id;
git tag -a <tagname> -m "blablabla..."
可以指定標(biāo)簽信息;
git tag -s <tagname> -m "blablabla..."
可以用PGP簽名標(biāo)簽;
git tag
可以查看所有標(biāo)簽
git push origin <tagname>
可以推送一個(gè)本地標(biāo)簽;
git push origin —tags
可以推送全部未推送過(guò)的本地標(biāo)簽;
git tag -d <tagname>
可以刪除一個(gè)本地標(biāo)簽;
git push origin :refs/tags/<tagname>
可以刪除一個(gè)遠(yuǎn)程標(biāo)簽。
Git常用命令速查表

參考文章
- http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000
- 參考書籍:《Git權(quán)威指南》
- http://backlogtool.com/git-guide/cn/
SVN vs Git (集中式 vs 分布式)
先說(shuō)集中式版本控制系統(tǒng),版本庫(kù)是集中存放在中央服務(wù)器的,而干活的時(shí)候,用的都是自己的電腦,所以要先從中央服務(wù)器取得最新的版本,然后開(kāi)始干活,干完活了,再把自己的活推送給中央服務(wù)器。中央服務(wù)器就好比是一個(gè)圖書館,你要改一本書,必須先從圖書館借出來(lái),然后回到家自己改,改完了,再放回圖書館。
集中式版本控制系統(tǒng)最大的毛病就是必須聯(lián)網(wǎng)才能工作。
那分布式版本控制系統(tǒng)與集中式版本控制系統(tǒng)有何不同呢?首先,分布式版本控制系統(tǒng)根本沒(méi)有“中央服務(wù)器”,每個(gè)人的電腦上都是一個(gè)完整的版本庫(kù),這樣,你工作的時(shí)候,就不需要聯(lián)網(wǎng)了,因?yàn)榘姹編?kù)就在你自己的電腦上。既然每個(gè)人電腦上都有一個(gè)完整的版本庫(kù),那多個(gè)人如何協(xié)作呢?比方說(shuō)你在自己電腦上改了文件A,你的同事也在他的電腦上改了文件A,這時(shí),你們倆之間只需把各自的修改推送給對(duì)方,就可以互相看到對(duì)方的修改了。
和集中式版本控制系統(tǒng)相比,分布式版本控制系統(tǒng)的安全性要高很多,因?yàn)槊總€(gè)人電腦里都有完整的版本庫(kù),某一個(gè)人的電腦壞掉了不要緊,隨便從其他人那里復(fù)制一個(gè)就可以了。而集中式版本控制系統(tǒng)的中央服務(wù)器要是出了問(wèn)題,所有人都沒(méi)法干活了。
在實(shí)際使用分布式版本控制系統(tǒng)的時(shí)候,其實(shí)很少在兩人之間的電腦上推送版本庫(kù)的修改,因?yàn)榭赡苣銈儌z不在一個(gè)局域網(wǎng)內(nèi),兩臺(tái)電腦互相訪問(wèn)不了,也可能今天你的同事病了,他的電腦壓根沒(méi)有開(kāi)機(jī)。因此,分布式版本控制系統(tǒng)通常也有一臺(tái)充當(dāng)“中央服務(wù)器”的電腦,但這個(gè)服務(wù)器的作用僅僅是用來(lái)方便“交換”大家的修改,沒(méi)有它大家也一樣干活,只是交換修改不方便而已。