這是我在學(xué)習(xí)Git的過(guò)程中所做的讀書(shū)筆記的相關(guān)總結(jié),希望能對(duì)剛剛接觸Git或Github的小伙伴們帶來(lái)一點(diǎn)點(diǎn)幫助,歡迎在我的博客下或者本文下給予意見(jiàn)和幫助!
Git是當(dāng)代最流行的版本控制系統(tǒng),這是我在閱讀了廖雪峰的Git基礎(chǔ)教程后所作的筆記和總結(jié),希望能對(duì)你有幫助。
Git概述
Git是一個(gè)分布式版本控制系統(tǒng)。就是基于它,著名的GitHub網(wǎng)站才能為開(kāi)源項(xiàng)目免費(fèi)提供Git存儲(chǔ),即Git的遠(yuǎn)程倉(cāng)庫(kù)服務(wù)。Git是完全免費(fèi)的,GitHub對(duì)于開(kāi)源倉(cāng)庫(kù)也是免費(fèi)的。其他的免費(fèi)的版本控制系統(tǒng)(Version Control System,即VCS)還有CSV,SVN等,它們都是集中式的,速度慢,而且還必須聯(lián)網(wǎng)才能使用。
Git的產(chǎn)生原因是由于維護(hù)Linux項(xiàng)目需要一個(gè)VCS的支持。起初BitKeeper(屬于BitMover公司)被授予Linux社區(qū)免費(fèi)使用,而后來(lái)有人因試圖破解BitKeeper而使BitMover公司撤回了對(duì)Linux社區(qū)的授權(quán),Linus就趁機(jī)寫(xiě)了自己的Git來(lái)取代BitKeeper的版本控制功能。
那么集中式VCS和分布式VCS各自都有什么特點(diǎn)呢?
集中式是指版本庫(kù)集中放在中央服務(wù)器中,每次工作都需要從中央服務(wù)器中取得最新的版本,在本機(jī)上進(jìn)行修改,然后推送到遠(yuǎn)程的中央服務(wù)器上。中央服務(wù)器就好比是一個(gè)圖書(shū)館。必須聯(lián)網(wǎng)才能工作。
分布式是指并沒(méi)有中央服務(wù)器,每個(gè)人的電腦上都是一個(gè)完整的版本庫(kù),只互相推送各自的修改。因?yàn)閮扇穗娔X通常不在一個(gè)局域網(wǎng)內(nèi),兩臺(tái)電腦互相訪問(wèn)不了或者沒(méi)有開(kāi)機(jī)等等,導(dǎo)致在兩人之間的電腦上無(wú)法推送版本庫(kù)的修改,所以通常也有一臺(tái)充當(dāng)“中央服務(wù)器”的電腦,方便“交換”大家的修改。
常見(jiàn)的版本控制系統(tǒng)有CVS,它是免費(fèi)和開(kāi)源的、集中式版本控制系統(tǒng)。由于CVS自身設(shè)計(jì)問(wèn)題,會(huì)造成提交文件不完整,版本庫(kù)莫名其妙損壞的情況。同樣開(kāi)源免費(fèi)的SVN就修正了CVS的一些穩(wěn)定性問(wèn)題,是目前用的最多的集中式版本庫(kù)控制系統(tǒng)。
收費(fèi)的集中式版本控制系統(tǒng)有IBM的ClearCase、微軟的VSS(集成在Visual Studio中)等。分布式版本控制系統(tǒng)有Git、BitKeeper、Mercurial、Bazaar等。
安裝Git
Linux系統(tǒng)(我的是Ubuntu14.04)可以直接使用命令 sudo apt-get install git 來(lái)安裝。這里是在默認(rèn)的軟件倉(cāng)庫(kù)中安裝,版本比較低,如果需要安裝較新版本的Git,輸入以下命令
$ sudo add-apt-repository ppa:git-core/ppa
$ sudo apt-get update
$ sudo apt-get install git
注意,在老版本的debian或者ubuntu linux,要用 sudo apt-get install git-core安裝,因?yàn)橛袀€(gè)軟件(GNU Interactive Tools)也叫GIT,所以git只能叫g(shù)it-core,但現(xiàn)在Git名氣實(shí)在太大,后來(lái)就把GNU Interactive Tools改名為gnuit了,git-core正式改為git。
如果要通過(guò)Git的源碼安裝,就要走經(jīng)典的 ./config 、 make 、 sudo make install 三部曲了。
除了CLI的Git,還有一些圖形化的Git工具,比如gitg,安裝命令如下
$ sudo apt-get install gitg
安裝完成后要配置自己的個(gè)人信息,在你的shell或git bash中輸入以下命令,配置自己的用戶名和郵箱
$ git config --global user.name "Your Name"
$ git config --global user.email "email@example.com"
其中--global參數(shù)代表該配置對(duì)所有本機(jī)的Git倉(cāng)庫(kù)都生效,這些配置都被保存在用戶目錄下的.gitconfig文件中,如果不加--global參數(shù),則必須要在Git倉(cāng)庫(kù)目錄中配置,該配置僅在該Git倉(cāng)庫(kù)中有效,配置文件在.git/config中。
配置Git使用的默認(rèn)文本編輯器,使用
$ git config --global core.editor "subl -w" # 配置Sublime
$ git config --global core.editor "vim" # 配置vim
注意subl程序要在PATH路徑下,加-w參數(shù)是為了讓Sublime在文件被保存后再返回。
個(gè)性化Git配置
讓Git顯示顏色
$ git config --global color.ui true
配置別名alias
$ git config --global alias.st status
$ git config --global alias.co checkout
$ git config --global alias.ci commit
$ git config --global alias.br branch
$ git config --global alias.unstage 'reset HEAD'
$ git config --global alias.last 'log -1' # 顯示最后一次提交
$ git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
其中--global參數(shù)是全局參數(shù),也就是說(shuō)這些配置在這臺(tái)電腦的所有Git倉(cāng)庫(kù)下都可用。
Git基本操作
git init
$ mkdir learngit
$ cd learngit
$ pwd
$ git init # 把當(dāng)前目錄變成Git可以管理的Git倉(cāng)庫(kù)
.git目錄是git來(lái)跟蹤管理版本庫(kù)的,也可以在非空目錄下建立git倉(cāng)庫(kù)。
也可以在一個(gè)Git倉(cāng)庫(kù)中再次使用init命令,會(huì)重新初始化已存在的Git倉(cāng)庫(kù)。
如果你使用Windows系統(tǒng),確保倉(cāng)庫(kù)路徑名不包含中文。
其實(shí),所有的版本控制系統(tǒng),只能跟蹤文本文件的改動(dòng),比如TXT文件、網(wǎng)頁(yè)、程序代碼等等。
圖片視頻等二進(jìn)制文件,雖然也能由版本控制系統(tǒng)管理,但無(wú)法跟蹤文件的變化,只能把二進(jìn)制文件每次的改動(dòng)串起來(lái),比如只能知道圖片從100KB改成了120KB,但到底改了啥,VCS無(wú)法知道。
git add & git commit
使用下列命令來(lái)將readme.txt文件添加進(jìn)暫存區(qū),并提交為一個(gè)版本commit。
$ git add readme.txt
$ git commit -m "wrote a readme file"
-m參數(shù)后緊跟本次提交的說(shuō)明信息,你可以多次add,然后用一次commit提交很多文件,如
$ git add file1.txt
$ git add file2.txt file3.txt
$ git commit -m "add 3 files."
git add -n .只顯示將要添加的文件,而并不實(shí)際添加到index,也可以用git add --dry-run .。git add . -v將會(huì)顯示詳實(shí)信息。git add . -i交互式地添加文件。git add -A添加工作區(qū)中所有的文件到index。
有關(guān)git add -A、git add .和git add -u的區(qū)別和在Git不同版本中的表現(xiàn),參見(jiàn)下圖:


git commit -a可以自動(dòng)暫存被修改或刪除的已跟蹤文件,對(duì)于Git未跟蹤的文件則不會(huì)被提交。
git commit -c可以在之前某個(gè)commit信息的基礎(chǔ)上再編輯,作為這次commit的提交信息。
git默認(rèn)不允許提交空提交,即和父commit完全一樣的commit不被允許,但是可以加上--allow-empty參數(shù)來(lái)強(qiáng)制提交。
如果你不想寫(xiě)提交信息,使用--allow-empty-message參數(shù),強(qiáng)烈不建議!
如果需要修改上一次commit的信息,可以使用以下命令
$ git commit --amend
該命令會(huì)刪除上一次commit,然后用這次commit替換。
git diff
使用下列命令
$ git diff file 可以查看file文件的修改 或者
$ git diff -- file # '--' 可以省略,如果當(dāng)前文件不存在,則必須加上'--'
$ git diff HEAD [--] readme.txt 查看工作區(qū)和版本庫(kù)里面最新版本的區(qū)別
$ git diff test 查看當(dāng)前工作區(qū)和test分支的差別
$ git status 查看倉(cāng)庫(kù)當(dāng)前的狀態(tài)
$ git diff --stat 不查看具體詳細(xì)差別,而是查看統(tǒng)計(jì)哪些文件被改動(dòng),有多少行被改動(dòng)
不加參數(shù)的git diff會(huì)比較當(dāng)前工作目錄中Git所跟蹤的尚未暫存的文件和上一次commit版本間的差異(如果已經(jīng)staged,又進(jìn)行修改,則比較當(dāng)前工作目錄和index中的差別),如果要查看已經(jīng)暫存的文件(如果新文件已經(jīng)被add進(jìn)index,則也會(huì)被比較)和上一次commit版本間的差異,使用git diff --cached命令。使用git diff HEAD來(lái)查看你當(dāng)前的工作目錄與上一次commit版本之間的所有差別。
git diff --cached(--staged同義詞) [] # 比較當(dāng)前index和commit間的差異,默認(rèn)commit是HEAD,即上一次提交,如果HEAD不存在(如初始化后未進(jìn)行任何commit的Git倉(cāng)庫(kù)),則顯示所有index中的內(nèi)容。
git diff比較分支之間的差別
$ git diff master..test # 比較分支master和test之間的差異(test相對(duì)于master的增量)
$ git diff master...test # 比較master和test的LCA(最近公共祖先)和test的差異(test相對(duì)于LCA的增量)
# 即如果A是B的父分支,則git diff A...B會(huì)顯示出B分支自創(chuàng)建后的改變(因?yàn)長(zhǎng)CA是A,即B相對(duì)于A的增量),而git diff B...A會(huì)顯示空,因?yàn)锳相對(duì)于A的增量為0\.
git reset
Reset current HEAD to the specified state.
git reset [-q] [] [--] ...
重置\指定的文件在index中的映像為它們?cè)赲中的樣子(不影響工作區(qū)或當(dāng)前分支),這意味著git reset與git add相反。然后使用git checkout來(lái)將其從index改變到工作區(qū).或者git checkout指定\來(lái)直接一次將某個(gè)commit中的文件內(nèi)容更新到index和工作區(qū)。
git reset [] []
這種形式的命令將當(dāng)前分支HEAD指向\,根據(jù)\來(lái)更新index或者工作區(qū)。\的默認(rèn)值是--mixed。\可以是以下值之一:
- --soft
不改變index和working tree。所有改變都處于'Changes to be commited'狀態(tài)。
- --mixed
更新index,但不更新working tree,所有改變都處于'not marked for commit'狀態(tài)。
- --hard
更新index和working tree,所有從\以后的已跟蹤文件的修改都將被舍棄。
- --merge
重置index,更新工作區(qū)中從\到HEAD之間不同的文件
- --keep
與--merge類似。
git checkout
git checkout [-p|--patch] [] [--] ...
當(dāng)\或者--patch給定時(shí),git checkout不會(huì)切換分支。它從index或者(通常是一個(gè)commit)指定的提交來(lái)更新工作區(qū)中\(zhòng)指定的文件。\參數(shù)能夠被用來(lái)指定一個(gè)特定的tree-ish(也就是一個(gè)commit、tag或者tree),以便在更新工作區(qū)之前先更新index為該\的樣子。
每一個(gè)commit都會(huì)對(duì)應(yīng)一個(gè)commit id(版本號(hào)),它是由SHA1計(jì)算出來(lái)的一個(gè)非常大的數(shù)字,用來(lái)標(biāo)識(shí)這次commit。它不僅單純根據(jù)當(dāng)前版本的文件內(nèi)容,還包含了這次提交時(shí)的一切元數(shù)據(jù)(meta data),如提交時(shí)間等。
版本回退,用HEAD表示當(dāng)前版本 上一個(gè)版本是HEAD,上上版本是HEAD^
往上100個(gè)版本寫(xiě)成HEAD~100。
$ git reset --hard HEAD^
$ git reset --hard cce56e9
如果上次的提交有錯(cuò)誤,想要撤銷??梢允褂?/p>
$ git revert HEAD # 創(chuàng)建一個(gè)取消上次提交的commit
$ git revert HEAD^ # 創(chuàng)建一個(gè)取消上上次提交的commit,上次提交(HEAD)的修改仍會(huì)保留,如果在HEAD^^之后的commit和HEAD^^,雙方修改了同一個(gè)文件,則會(huì)造成沖突,需要解決沖突
或者修改提交來(lái)修復(fù)錯(cuò)誤,即利用--amend參數(shù)。
git rm
從工作區(qū)和暫存區(qū)中刪除文件
$ git rm --cached file # 僅從index中刪除文件
$ git rm file # 從working tree和index中都刪除,只能通過(guò)之前的commit恢復(fù)
$ rm file # 僅從working tree刪除,可以通過(guò)git checkout -- file恢復(fù)
如果要?jiǎng)h除的文件,與HEAD相比做了修改,則要使用--cached保留本地文件,或用-f強(qiáng)制刪除。
git log
Show commits logs.
git log [] [] [[\--] ...]
默認(rèn)不加任何參數(shù),git log會(huì)按提交時(shí)間從晚到早(從新到舊)列出所有的更新,會(huì)顯示一個(gè)SHA-1校驗(yàn)和,作者名字和郵件地址,提交時(shí)間,最后一個(gè)縮進(jìn)段落顯示提交說(shuō)明。
-p展開(kāi)顯示每次提交和之前上一次提交的內(nèi)容差異,用-2僅顯示最近兩次更新。
$ git log -p -2
有些時(shí)候,行層面的對(duì)比滿足不了要求,需要單詞層面的對(duì)比,使用--word-diff選項(xiàng)。
$ git log -U1 --word-diff
對(duì)比顯示在行間,新增加的單詞被[+ +]括起來(lái),被刪除的單詞被[- -]括起來(lái)。使用-U1來(lái)將上下文行數(shù)從默認(rèn)的3行改為1行。
$ git log --stat
僅顯示簡(jiǎn)要的增改行數(shù)統(tǒng)計(jì)。
$ git log --pretty=oneline
pretty選項(xiàng)指定格式顯示歷史,如oneline、short、full、fuller、format:等。
--pretty=oneline 每個(gè)提交用一行顯示 更好看
format選項(xiàng)可以自定制要顯示的記錄格式,便于后續(xù)編程提取分析
$ git log --pretty=format:"%h - %an, %ar : %s"
常用的格式占位符寫(xiě)法和意義見(jiàn):git-log format常用選項(xiàng)
作者和提交者有何區(qū)別呢?
作者指的是實(shí)際做出修改的人,提交者指的是最后將此工作成果提交到倉(cāng)庫(kù)的人。比如,當(dāng)你為某個(gè)項(xiàng)目發(fā)布補(bǔ)丁,然后某個(gè)核心成員將你的補(bǔ)丁并入項(xiàng)目時(shí),你就是作者,而那個(gè)核心成員就是提交者。
--graph選項(xiàng)添加了一些ASCII字符串來(lái)形象地展現(xiàn)分支、合并歷史等。
其它選項(xiàng):
1. --stat和--shortstat,顯示統(tǒng)計(jì)信息。
2. --name-only和--name-status,前者僅顯示已修改的文件清單,而后者還顯示是M(修改)、A(添加)還是D(刪除)。
3. --abbrev-commit,僅顯示SHA-1的前幾個(gè)字符,而非完整的40個(gè)字符。
4. --relative-date,使用較短的相對(duì)時(shí)間顯示(如,“2 weeks ago”)。
5. -p,按補(bǔ)丁格式顯示每個(gè)更新之間的差異。
限制git log的輸出長(zhǎng)度:
$ git log - # 展示最近的n條記錄
$ git log --since=2.weeks # 最近兩周內(nèi)的提交
$ git log --since="2008-01-15" # 從2008-01-15以后的提交
$ git log --since="2 years 1 day 3 minutes ago"
$ git log --author snk # 顯示作者snk的提交 --committer類似
$ git log --grep search_text # 搜索commit message中的關(guān)鍵字
$ git log --all-match # 如果要得到同時(shí)滿足2個(gè)搜索條件的提交,需要用--all-match選項(xiàng),否則,滿足任意一個(gè)條件的提交都會(huì)被匹配出來(lái)
$ git log -Sfunction_name # 找出添加或刪除了某些字符串的提交
$ git log -- # 只關(guān)心某些文件或目錄的歷史提交
$ git log --no-merges # 非合并的提交
$ git log --no-color # 不顯示顏色
與--since選項(xiàng)類似的還有--after、--until、--before等。
git reflog
$ git reflog
當(dāng)你本地倉(cāng)庫(kù)中的分支(branch)或者其他引用被更新時(shí),它會(huì)記錄你的操作。它在幫助其他Git命令確定一個(gè)舊引用時(shí)十分有用。
使用git log -g也可以查看所有的歷史操作記錄。
工作區(qū) && 暫存區(qū)
工作區(qū)(working directory):在電腦里能看到的目錄
版本庫(kù)(repository):.git文件夾來(lái)維護(hù)git的版本倉(cāng)庫(kù),存放了很多東西,最重要的是暫存區(qū)(stage、index),還有Git自動(dòng)創(chuàng)建的第一個(gè)分支 master 以及 指向 master 的一個(gè)指針 HEAD。
git add就是把文件修改添加到暫存區(qū),
git commit把暫存區(qū)的所有內(nèi)容提交到當(dāng)前分支。
每次修改,如果不add到暫存區(qū),那就不會(huì)加入到commit中。
撤銷修改,丟棄工作區(qū)的改動(dòng)
$ git checkout -- readme.txt
兩種情況:
readme.txt自從修改后還沒(méi)有被放到暫存區(qū),此時(shí)撤銷修改就回到和版本庫(kù)一模一樣的狀態(tài);
readme.txt已經(jīng)添加到暫存區(qū),又做了修改,此時(shí)撤銷修改就回到添加到暫存區(qū)時(shí)的狀態(tài)。
$ git reset HEAD file
可以把送到暫存區(qū)的修改撤銷掉(unstaged),重新放回工作區(qū)。
刪除文件
$ git rm file # 來(lái)提交刪除到暫存區(qū) 或者 直接使用 git add file
$ git commit -m "remove sth."
誤刪恢復(fù):
$ git checkout -- file
遠(yuǎn)程倉(cāng)庫(kù)
GitHub配置
github網(wǎng)站是用來(lái)提供Git倉(cāng)庫(kù)托管服務(wù)的,那么github網(wǎng)站上的倉(cāng)庫(kù)就相當(dāng)于是一個(gè)遠(yuǎn)程倉(cāng)庫(kù)。
本地Git倉(cāng)庫(kù)與GitHub倉(cāng)庫(kù)之間的傳輸是通過(guò)SSH加密的。SSH是
Secure Shell的縮寫(xiě),即安全外殼協(xié)議,它是建立在應(yīng)用層和傳輸層基礎(chǔ)上的安全協(xié)議。
GitHub驗(yàn)證的驗(yàn)證方式有兩種:
基于口令的安全驗(yàn)證 容易受到中間人攻擊
基于密鑰的安全驗(yàn)證 登錄過(guò)程較慢
SSH配置:
1.創(chuàng)建SSH Key。用戶主目錄的.ssh目錄下生成id_rsa和id_rsa.pub文件,id_rsa是私鑰(不能泄露) id_rsa.pub是公鑰(可以放心地告訴任何人),如果沒(méi)有.ssh目錄,需要通過(guò)以下命令來(lái)創(chuàng)建SSH Key。
$ ssh-keygen -t rsa -C "郵件地址"
2.登陸github, 在右上角的頭像處,點(diǎn)擊下拉菜單中的Settings,選擇左側(cè)的SSH and GPG Keys里面設(shè)置SSH公鑰,點(diǎn)擊new SSH key,在文本域中填入你的id_rsa.pub文件中的內(nèi)容,填一個(gè)有標(biāo)志性的title,然后點(diǎn)擊Add SSH Key即可。
Github允許添加多個(gè)key,因此可以用若干臺(tái)電腦(公司、家里等)來(lái)往Github推送。
在Github上免費(fèi)托管的Git倉(cāng)庫(kù),都是公開(kāi)的,但只有自己可以修改。
如果不想讓別人看到Git庫(kù),你可以:
1.付費(fèi)使用GitHub的私有倉(cāng)庫(kù)。
2.自己搭建Git服務(wù)器。
SSH警告:
當(dāng)?shù)谝淮问褂肎it的clone或者push命令連接GitHub時(shí),會(huì)得到一個(gè)警告。
這是因?yàn)镚it使用SSH連接,而SSH連接在第一次驗(yàn)證GitHub服務(wù)器的Key時(shí),需要你確認(rèn)GitHub的Key的指紋信息是否真的來(lái)自GitHub的服務(wù)器,輸入yes回車(chē)即可。
如果擔(dān)心有人冒充GitHub服務(wù)器,輸入yes前可以對(duì)照 https://help.github.com/articles/what-are-github-s-ssh-key-fingerprints/ 中的GitHub的RSA Key的指紋信息是否與SSH連接給出的一致。
相關(guān)Git命令
添加遠(yuǎn)程庫(kù)
$ git remote add [remote-shortname(如origin)] [url(如ssh或https)]
git默認(rèn)使用origin來(lái)標(biāo)識(shí)克隆的原始倉(cāng)庫(kù)。
查看所有遠(yuǎn)程倉(cāng)庫(kù)
$ git remote [-v] # --verbose 顯示詳實(shí)信息
從遠(yuǎn)程倉(cāng)庫(kù)拉取數(shù)據(jù)
$ git fetch [remote-short-name]
從遠(yuǎn)程倉(cāng)庫(kù)remote-short-name中拉取所有你在本地倉(cāng)庫(kù)中還沒(méi)有的數(shù)據(jù),運(yùn)行完成后,你就可以在本地訪問(wèn)該遠(yuǎn)程倉(cāng)庫(kù)中的所有分支,如remote-short-name/master,你可以合并該分支,也可以切換到這個(gè)分支一探究竟。
注意,fetch命令只是將遠(yuǎn)程倉(cāng)庫(kù)的數(shù)據(jù)拉取到本地倉(cāng)庫(kù),并不自動(dòng)合并到當(dāng)前工作分支。當(dāng)你確實(shí)準(zhǔn)備好了,請(qǐng)手工合并。
$ git pull
如果已經(jīng)設(shè)置了某個(gè)分支用于跟蹤某個(gè)遠(yuǎn)端倉(cāng)庫(kù)的分支,可以使用該命令自動(dòng)抓取數(shù)據(jù)下來(lái),然后將遠(yuǎn)端分支自動(dòng)合并到當(dāng)前工作分支,實(shí)際上git clone本質(zhì)上就是自動(dòng)創(chuàng)建了本地的master分支用于跟蹤遠(yuǎn)程倉(cāng)庫(kù)中的master分支。
推送數(shù)據(jù)到遠(yuǎn)程倉(cāng)庫(kù)
$ git push -u [remote-name] [branch-name]
把本地的branch-name分支,推送到remote-name的服務(wù)器上。如果不指定remote-name和branch-name,克隆得到的倉(cāng)庫(kù)會(huì)自動(dòng)使用默認(rèn)的master和origin名字。
如果在你推送數(shù)據(jù)之前,已經(jīng)有別人推送了若干更新,那么你的推送操作就會(huì)被駁回,你必須先把他們的更新拉取到本地,合并到自己的項(xiàng)目中,然后才可以再次推送。
由于遠(yuǎn)程庫(kù)是空的,第一次推送master分支時(shí),加上了-u參數(shù),Git不但會(huì)把本地master分支內(nèi)容推送到遠(yuǎn)程新的master分支,還會(huì)把本地的master分支和遠(yuǎn)程的master分支關(guān)聯(lián)起來(lái),為以后的推送或者拉取時(shí)就可以簡(jiǎn)化命令。以后,只要本地有了新的commit,就可以通過(guò)命令:
$ git push origin master
把本地master分支的最新修改推送至GitHub。
從遠(yuǎn)程庫(kù)克隆
從GitHub網(wǎng)站上首先創(chuàng)建一個(gè)遠(yuǎn)程庫(kù),再利用命令git clone克隆到本地庫(kù)。
$ git clone git@github.com:sonack/RemoteRepo.git
如果有多個(gè)人協(xié)作開(kāi)發(fā),那么每個(gè)人各自從遠(yuǎn)程克隆一份就可以了。
Git支持多種協(xié)議:默認(rèn)的git://使用ssh,但也可以使用https等其他協(xié)議。但是https 速度慢,并且每次需要輸入口令,比較麻煩,但在某些只開(kāi)放http端口的公司內(nèi)部就只能使用https.
分支管理
主分支一般為master分支,開(kāi)發(fā)分支一般為dev分支。
嚴(yán)格來(lái)說(shuō),HEAD指向master,master指向提交commit。
命令小結(jié):
查看分支:
$ git branch
創(chuàng)建分支:
$ git branch
切換分支:
$ git checkout
創(chuàng)建+切換分支:
$ git checkout -b
合并某分支到當(dāng)前分支:
$ git merge
刪除分支:
$ git branch -d
合并方式有fast-forward,即快速合并(直接把master指向dev的當(dāng)前commit,速度非???,時(shí)間復(fù)雜性是O(1)級(jí)別)。
解決沖突
git無(wú)法執(zhí)行快速合并,只能試圖把各自的修改合并起來(lái),但這種合并就可能會(huì)有沖突。
$ git merge feature1
提示沖突 也可以用git status查看沖突的文件,手動(dòng)解決沖突后
$ git add file
$ git commit -m "conflict fixed"
$ git branch -d feature1
git使用 <<<<<<<、=======、>>>>>>>標(biāo)記出不同分支的內(nèi)容。
用帶參數(shù)的git log命令也可以看到分支的合并情況:
$ git log --graph --pretty=oneline --abbrev-commit
分支管理策略
通常,合并分支時(shí),如果可能,Git會(huì)用fast forward模式,但這種模式下,刪除分支后,會(huì)丟掉分支信息。
如果強(qiáng)制禁用fast forward模式,那么Git就會(huì)在merge時(shí)生成一個(gè)新的commit,這樣,從分支歷史上就可以看出分支信息。
$ git merge --no-ff -m "merge with no-ff" dev
因?yàn)檫@種合并要?jiǎng)?chuàng)建一個(gè)新的commit,所以加上-m參數(shù),把commit描述寫(xiě)進(jìn)去。
分支策略:
原則:
master分支應(yīng)該是非常穩(wěn)定的,也就是僅用來(lái)發(fā)布新版本,平時(shí)不在上面干活;
在dev分支上干活,dev分支是不穩(wěn)定的,到某個(gè)時(shí)候,再把dev分支合并到master分支上。
每個(gè)人都在各自的dev分支上干活,每個(gè)人都有自己的分支,時(shí)不時(shí)地往dev分支上合并。
BUG分支:
工作還沒(méi)完成,不能commit,必須要先解決bug.
或者可以用stash功能,把當(dāng)前工作現(xiàn)場(chǎng)"儲(chǔ)藏"起來(lái),等以后恢復(fù)現(xiàn)場(chǎng)后繼續(xù)工作。
在dev分支上沒(méi)有被git管理的文件是不能被stash的(只有修改和暫存區(qū)等能被管理)
$ git stash
恢復(fù)
$ git stash apply 恢復(fù)但不刪除stash內(nèi)容
$ git stash drop 刪除stash內(nèi)容
或者用一條語(yǔ)句
$ git stash pop 恢復(fù)的同時(shí)把stash內(nèi)容也刪除
恢復(fù)指定的stash
$ git stash apply stash@{0}
多人協(xié)作
當(dāng)從遠(yuǎn)程倉(cāng)庫(kù)克隆時(shí),實(shí)際上Git自動(dòng)地把本地的master分支和遠(yuǎn)程的master分支對(duì)應(yīng)起來(lái)了,并且遠(yuǎn)程倉(cāng)庫(kù)的默認(rèn)名稱為origin。
查看遠(yuǎn)程庫(kù)的信息
$ git remote
或者用git remote -v顯示更詳細(xì)的信息。
其可以顯示有權(quán)抓取(fetch)和推送(push)的origin的地址,如果沒(méi)有推送權(quán)限,就看不到push的地址。
推送分支
推送分支,就是把該分支上的所有本地提交推送到遠(yuǎn)程庫(kù),推送時(shí),要指定本地分支,這樣Git就會(huì)把該分支推送到遠(yuǎn)程庫(kù)對(duì)應(yīng)的遠(yuǎn)程分支上。
$ git push origin master
$ git push origin dev
或者用
$ git push --set-upstream origin dev
需要推送的分支:
master是主分支,因此要時(shí)刻與遠(yuǎn)程同步;
dev是開(kāi)發(fā)分支,團(tuán)隊(duì)所有成員都需要在上面工作,所以也需要與遠(yuǎn)程同步;
bug分支只用于在本地修復(fù)bug,沒(méi)必要推送到遠(yuǎn)程;
feature分支是否推到遠(yuǎn)程,取決于是否需要合作開(kāi)發(fā)。
抓取分支
克隆別人的庫(kù)只能看到master分支,要在dev分支上開(kāi)發(fā),必須創(chuàng)建遠(yuǎn)程origin的dev分支到本地,用下面的命令創(chuàng)建本地dev分支
$ git checkout -b dev origin/dev
解決沖突
拉取遠(yuǎn)程更新并合并
$ git pull
如果失敗,則可能因?yàn)闆](méi)有指定本地dev分支和遠(yuǎn)程origin/dev分支的鏈接,使用:
$ git branch --set-upstream-to origin/dev dev
或者用--track選項(xiàng),然后再次git pull。
手動(dòng)解決沖突后,再提交(push)
$ git add conflictFile
$ git commit -m "fix the conflict on dev branch"
$ git push
多人協(xié)作的工作模式
試圖用
git push origin推送自己的修改;如果推送失敗,則因?yàn)檫h(yuǎn)程分支比你的本地更新,需要先用
git pull試圖合并;如果合并有沖突,則解決沖突,并在本地提交;
沒(méi)有沖突或者解決掉沖突后,再用
git push origin推送分支。
標(biāo)簽管理
標(biāo)簽是版本庫(kù)的一個(gè)快照,本質(zhì)上是指向某個(gè)commit的指針(和分支類似,但分支可以移動(dòng),標(biāo)簽不能移動(dòng))。
創(chuàng)建標(biāo)簽
$ git branch
$ git checkout master # 切換到需要打標(biāo)簽的分支上
$ git tag v1.0
git tag 默認(rèn)是將標(biāo)簽打在最新提交的commit上的,可以使用下面的命令指定commit
$ git tag
查看所有標(biāo)簽
$ git tag
注意標(biāo)簽不是按照時(shí)間順序列出的,而是按照字母序排序的。
查看標(biāo)簽信息
$ git show
創(chuàng)建帶有說(shuō)明的標(biāo)簽,用-a指定標(biāo)簽名,-m指定說(shuō)明文字,創(chuàng)建用私鑰簽名的一個(gè)標(biāo)簽,用-s簽名采用PGP簽名,因此,必須首先安裝gpg(GnuPG),如果沒(méi)有找到gpg,或者沒(méi)有g(shù)pg密鑰對(duì),就會(huì)報(bào)錯(cuò)。
刪除標(biāo)簽
$ git tag -d v0.1
推送標(biāo)簽到遠(yuǎn)程
$ git push origin
一次性推送全部尚未推送到遠(yuǎn)程的本地標(biāo)簽
$ git push origin --tags
刪除遠(yuǎn)程標(biāo)簽
先從本地刪除,
git tag -d v0.9然后從遠(yuǎn)程刪除,刪除命令也是push,即
git push origin:refs/tags/v0.9
GitHub
在fork開(kāi)源倉(cāng)庫(kù)后即擁有其讀寫(xiě)權(quán)限(自己的倉(cāng)庫(kù)),可以通過(guò)推送pull request給官方倉(cāng)庫(kù)貢獻(xiàn)代碼。
雜項(xiàng)
忽略特殊文件
git工作區(qū)的根目錄下創(chuàng)建一個(gè)特殊的文件.gitignore文件,詳情可以參考我的另一篇博文.gitignore文件解析或者參考官方文檔,這里是一些常用的.gitignore文件的寫(xiě)法。
忽略文件的原則:
忽略操作系統(tǒng)自動(dòng)生成的文件,比如縮略圖等;
忽略編譯生成的中間文件,可執(zhí)行文件等。
忽略帶有自己敏感信息的配置文件,比如存放口令的配置文件等。
然后可以把.gitignore文件放到版本庫(kù)里,并且可以對(duì).gitignore文件做版本管理。
搭建Git服務(wù)器
1.安裝git
$ sudo apt-get install git
2.創(chuàng)建一個(gè)git用戶,用來(lái)運(yùn)行g(shù)it服務(wù)
$ sudo adduser git
3.創(chuàng)建證書(shū)登陸
收集所有需要登陸的用戶的公鑰(id_ras.pub文件),把所有公鑰導(dǎo)入到/home/git/.ssh/authorized_keys文件里,一行一個(gè)。
4.初始化Git倉(cāng)庫(kù)
先選定一個(gè)目錄作為Git倉(cāng)庫(kù),假定是/srv/sample.git。
在/srv目錄下輸入
$ sudo git init --bare sample.git
Git就會(huì)創(chuàng)建一個(gè)裸倉(cāng)庫(kù),沒(méi)有工作區(qū)(bare意為空的,赤裸的)。
因?yàn)榉?wù)器上的Git倉(cāng)庫(kù)純粹是為了共享,所以不讓用戶直接登陸到服務(wù)器上去改工作區(qū),并且服務(wù)器上的Git倉(cāng)庫(kù)通常都以.git結(jié)尾。然后把owner改為git用戶
$ sudo chown -R git:git sample.git
5.禁用shell登陸
6.克隆遠(yuǎn)程倉(cāng)庫(kù)
$ git clone git@server:/srv/sample.git
管理公鑰:
如果團(tuán)隊(duì)人員很多,可以用Gitosis;
管理權(quán)限:
Git不支持權(quán)限控制,但支持鉤子(hook)機(jī)制,所以可以在服務(wù)器端編寫(xiě)一系列腳本來(lái)控制提交等操作,達(dá)到權(quán)限控制的目的。Gitolite就是這種工具。
最后附上一張GitCheatSheet,愿君學(xué)有所成!