Git 是 linux內(nèi)核創(chuàng)始人 Linus Torvalds 為了維護(hù) linux 源碼便利而開發(fā)的一款工具。發(fā)展到今天,已經(jīng)成為全球通用的分布式版本控制系統(tǒng)。在 Git 中,每一份復(fù)制出來的庫都可以獨(dú)立使用和維護(hù),并且,任意兩個(gè)不同的庫都可以合并。
GitHub 是一個(gè)開源庫和私有軟件項(xiàng)目的托管平臺(tái),因?yàn)橹恢С?Git 作為唯一的版本庫格式進(jìn)行托管,所以叫 GitHub?,F(xiàn)在,開源代碼幾乎都是放在 GitHub 上。另外,還有從 GitHub fork 出去獨(dú)立開發(fā)出的收費(fèi)版叫 Gitlab,支持企業(yè)內(nèi)項(xiàng)目的托管平臺(tái),相信用過的人一定明白有多便利。
簡(jiǎn)介

git當(dāng)前最新版本為:2.12.2,官網(wǎng)地址
Git圖形化軟件:git是開源的命令行工具,隨著git的普及,市面上也出現(xiàn)了很多。最著名的有:TortoiseGit、Source Tree、GitUp、SmartGit等。參考
TortoiseGit 是 TortoiseSVN 的 Git 版本,Windows平臺(tái)下的Git圖形化軟件;
SourceTree是Windows和Mac系統(tǒng)下的git客戶端,支持絕大多數(shù)git常用操作,界面美觀,很方便管理多個(gè)項(xiàng)目;
GitUp 是最新出來的 Mac OS X 下的全功能開源 Git 客戶端,提供快速、安全的操作,可以直接在硬盤上與 Git 倉庫交互,不過,操作庫的是圖而不是操作命令;
SmartGit是一款古老的git圖形化軟件,支持的系統(tǒng)包括Windows、Mac OS以及Linux系統(tǒng);
當(dāng)然還有很多其他的Git圖形化軟件,基本沒玩過就不介紹了。代碼托管平臺(tái):隨著使用git的開發(fā)者越來越多,代碼托管平臺(tái)基本成了大大小小項(xiàng)目的標(biāo)配。參考
Github,很多著名的開源軟件像Apache Tomcat/Maven/ant/hadoop/、Eclipse,瀏覽器內(nèi)核webkit/v8等、當(dāng)然了還有g(shù)it。
Gitlab,跟GitHub類似,相比于GitHub,Gitlab可以免費(fèi)創(chuàng)建私有項(xiàng)目,擁有更高的安全性和靈活性,所以它更適合企業(yè)開發(fā)團(tuán)隊(duì)托管項(xiàng)目??梢哉f,Gitlab是企業(yè)版的GitHub。
Bitbucket,支持免費(fèi)創(chuàng)建私有項(xiàng)目,但同一個(gè)私有項(xiàng)目最多支持5個(gè)開發(fā)者。
OSChina、CODING、CSDN是國內(nèi)的項(xiàng)目托管平臺(tái),這幾年發(fā)展也不錯(cuò)。
Git 設(shè)計(jì)思想和原理
Git 版本控制系統(tǒng)中,其通過文件對(duì)象記錄所有文件,并通過緩存所有歷史和元數(shù)據(jù),實(shí)現(xiàn)對(duì)代碼版本的控制。
Git 中的對(duì)象類型
使用 git 命令操作過程中,你會(huì)經(jīng)常遇到長(zhǎng)度為40字符的串,像這樣:

你第一反應(yīng)是,這些不就是 commit id 嘛~是的,沒錯(cuò),但不準(zhǔn)確。其實(shí)它真正表示的是一個(gè)項(xiàng)目歷史信息的文件對(duì)象,這個(gè)值是通過對(duì)文件內(nèi)容進(jìn)行 SHA1 哈希計(jì)算得到的,就像一個(gè) md5 值唯一標(biāo)識(shí)一個(gè)文件內(nèi)容一樣,任意兩個(gè)不同的文件
SHA1 值一定不同。
每個(gè)文件對(duì)象包括三個(gè)部分:類型,大小,內(nèi)容。有四種類型對(duì)象:blob、tree、commit、tag,每一種類型的對(duì)象你都可以通過 git show xxxx 命令查看詳細(xì)信息。
- “blob”:存儲(chǔ)文件數(shù)據(jù)的類型,通常記錄一個(gè)文件的內(nèi)容;
- “tree”:存儲(chǔ)一些“tree”或 “blob”類型文件的類型(類似目錄,便管理子目錄和文件),git ls-tree xxxxxx 可以查看詳細(xì)的 tree 對(duì)象;
- “commit”:存儲(chǔ)"tree"類型文件數(shù)據(jù)的類型,同時(shí)包含一些描述信息,還標(biāo)記了項(xiàng)目某一個(gè)特定時(shí)間點(diǎn)的狀態(tài)。它包括一些關(guān)于時(shí)間點(diǎn)的元數(shù)據(jù),如時(shí)間戳、最近一次提交的作者、指向上次提交的指針等,也就是大家常說的 commit id;
- “tag”:指向“commit” 對(duì)象類型的類型,實(shí)際就是標(biāo)記了一個(gè)特殊的 commit 對(duì)象。與其他幾種類型還有一個(gè)區(qū)別,一個(gè) tag 對(duì)象還可能包含了簽名創(chuàng)建者簽名相關(guān)的信息,你可以通過 git cat-file tag xxx 來查看。
每次提交都會(huì)給每個(gè)文件創(chuàng)建 blob 類型的對(duì)象,給每個(gè)目錄創(chuàng)建 tree 類型的對(duì)象,最后創(chuàng)建一個(gè) commit 對(duì)象用于指向根 tree 對(duì)象,因此,每個(gè)一個(gè) “commit id” 就表示了一次提交的所有內(nèi)容。
因此,上面舉例的字符串實(shí)際上是指向 commit 類型的文件對(duì)象。從這些類型的定義或叫說明上也能看出,blob 類型是最基礎(chǔ)的文件對(duì)象類型,而 tag 是記錄某一個(gè)次重要節(jié)點(diǎn)的文件對(duì)象類型。
Git 如何存儲(chǔ)對(duì)象
Git 中存在兩種對(duì)象,一種是松散對(duì)象,一種是打包對(duì)象。
- 松散對(duì)象:每一個(gè)對(duì)象對(duì)應(yīng)磁盤上的一個(gè)文件,每個(gè)文件存儲(chǔ)著壓縮的數(shù)據(jù)。
例如,一個(gè) git 對(duì)象的 SHA1 值e0a0df73be6cb4e841de84c0450058ab927b60,那么,在 .git 目錄的 object 子目錄下,就會(huì)存在這樣的一個(gè)文件。 - 打包對(duì)象:Git 會(huì)把每個(gè)文件對(duì)象的每個(gè)版本都作為一個(gè)單獨(dú)的對(duì)象,如果所有的 git 對(duì)象都使用松散對(duì)象的形式存儲(chǔ),就會(huì)導(dǎo)致效率低下,所以,為了節(jié)約空間 Git 通過兩個(gè)對(duì)象指針來表示一個(gè)修改的文件對(duì)象,一個(gè)指針指向第二個(gè)文件中改變的部分,一個(gè)指針指向相似的那個(gè)文件。
SHA1
SHA1(Secure hash algorithm),即安全的hash算法,用于計(jì)算文本的校驗(yàn)和,常作為摘要算法對(duì)簽名進(jìn)行校驗(yàn)。它的特點(diǎn)是計(jì)算出的SHA1值是不可逆性切不重復(fù)的,也就是根據(jù)SHA1值無法反解出原始內(nèi)容,并且對(duì)于相同的內(nèi)容,每次計(jì)算得到的SHA1都相同。正因?yàn)檫@樣的特性,它常用于驗(yàn)證數(shù)據(jù)的完整性以及消息的驗(yàn)證。SHA1算法可以得到160位二進(jìn)制數(shù),也就是40位16進(jìn)制數(shù)。我們做一個(gè)簡(jiǎn)單的實(shí)驗(yàn)。mac下通過這個(gè)命令可以安裝一個(gè)sha1算法的工具:
brew install md5sha1sum
操作如下:
# A.txt:A:version 1
sha1sum A.txt
# result:
# 2d8954f9fbf90f6da74b728bf3dfe4ad459865fe A.txt
- 摘要加密算法
- 特性:不可逆,不重復(fù)
- 用途:驗(yàn)證數(shù)據(jù)完整性與消息驗(yàn)證
- 160位二進(jìn)制數(shù)(或40位16進(jìn)制數(shù))
Git 基本用法
git init
以當(dāng)前目錄為根目錄,初始化一個(gè)新的倉庫,實(shí)際這條命令主要?jiǎng)?chuàng)建一個(gè)名為 .git 的隱藏目錄。

git clone https://github.com/iThinkerYZ/GPUImgeDemo.git
從已有倉庫中復(fù)制/拷貝一份到本地,因此我們需要知道一個(gè)項(xiàng)目的倉庫地址,Git 支持多種協(xié)議,因此,這些 url 可以是ssh://、http(s)://,、git:// 等。一般情況,clone 下來的倉庫根目錄名就是 url 最后的文件名。例如上面就會(huì)得到名為
GPUImgeDemo 的目錄。
git status
查看當(dāng)前 Git 目錄(.git)的狀態(tài),可以列舉出所有已經(jīng)修改文件的狀態(tài)。
git branch
查看本地所有分支,*號(hào)表示所在分支,-r 參數(shù)可以指定查看遠(yuǎn)程的所有分支。
git checkout some-branch/some-tag/some-commit
切換分支,其實(shí)就是切換到某個(gè) commit 對(duì)象(根節(jié)點(diǎn))
git add some-file
創(chuàng)建指定修改文件內(nèi)容的文件對(duì)象(SHA1),同時(shí)添加文件對(duì)象到暫存區(qū)??梢?add 一個(gè)文件,也可以通過","分隔添加多個(gè)文件,還可以通過"."來匹配本地的所有修改文件。
git commit -m 'xxxxx'
提交暫存區(qū)的修改到本地倉庫,同時(shí)添加注釋內(nèi)容??梢允褂?git commit -am 'xxxxx' 進(jìn)行add和commit
git pull
拉取遠(yuǎn)程到本地,其實(shí)完整的命令是 git pull origin current-branch。不過需要注意,如果本地文件有修改,拉取的內(nèi)容可能跟本地的內(nèi)容有沖突需要處理一下。
git push
推送本地提交到遠(yuǎn)程倉庫。完整的命令是 git push origin current-branch。注意,如果遠(yuǎn)程有更新而本地沒有拉取,會(huì)阻止本地的 push 動(dòng)作并提示。
git reset
重置 HEAD 部分的修改到指定狀態(tài),通常該命令結(jié)合3種參數(shù)使用,--soft/--mixed/--hard。--hard 將會(huì)刪除本地所有修改但沒有提交的記錄。
git revert
回滾本地的代碼到指定某個(gè)提交的狀態(tài),同時(shí)將回滾內(nèi)容作為一個(gè)新的修改進(jìn)行提交。效果跟
reset相同,但是跟 reset 不同點(diǎn)在于,reset 是直接刪除某個(gè)提交記錄,但是 revert 不會(huì)。
git merge some-branch
將某個(gè)分支內(nèi)容與當(dāng)前分支合并。
git rebase
將從開始 merge 的那個(gè)狀態(tài)以來的所有提交,以補(bǔ)丁的形式一個(gè)一個(gè)重新達(dá)到目標(biāo)分支上,看起來就像一條線一樣的工作流。
git stash
暫存當(dāng)前分支的所有修改到臨時(shí)區(qū)域,保持 HEAD 為最后一次 commit 狀態(tài)。
git show
顯示某個(gè)git 對(duì)象的詳細(xì)信息
git diff
對(duì)比工作區(qū)與暫存區(qū)內(nèi)容的不同,方便對(duì)比做了哪些修改。一般,在 commit 內(nèi)容前最好檢查一下,確保沒有問題。
git tag
展示本地所有的 tag,另外,也可以通過 git tag new-tag 來新建一個(gè) tag,通過 git tag -d some-tag 來刪除本地的 tag。通過命令 git push --tag(s) 來推送本地更新的 tag 到遠(yuǎn)程倉庫。一般,我們會(huì)在發(fā)版前更新 tag 作為穩(wěn)定版本。
Git 中級(jí)用法
.gitignore
開發(fā)中,經(jīng)常需要忽略一些文件的修改,既不追蹤,也不會(huì)被加入到暫存區(qū)中,即保證 git commit、git add、git status 命令都不會(huì)處理這些文件的變化,保證高效完成版本文件管理。.gitignore文件就是用于解決這個(gè)問題。該文件需要手動(dòng)創(chuàng)建和添加(有的git系統(tǒng)會(huì)自動(dòng)創(chuàng)建并且是初始化好的),并加入現(xiàn)文件來告訴 Git 系統(tǒng)會(huì)略哪些文件。
GitHub 官方提供了各種語言對(duì)應(yīng)項(xiàng)目的通用.gitignore模板,大家可以直接復(fù)用。
點(diǎn)這里
該文件的存放位置決定該目錄及其子目錄使用的忽略文件,因此,可以針對(duì)不同目錄定制對(duì)應(yīng)的.gitignore文件,當(dāng)然了,一般做法是只在根目錄(與 .git 目錄同級(jí))保存一份。
rebase
由于 git 是分布式的版本控制系統(tǒng),因此少不了要處理不同并行分支合并的場(chǎng)景。在初級(jí)用法中簡(jiǎn)單介紹了該命令。
與 merge 的主要區(qū)別:merge 最終將合并的結(jié)果作為一次新的commit提交,當(dāng)前分支修改以及已經(jīng)提交的部分作為歷史保留,rebase 首先將當(dāng)前分支的提交以補(bǔ)丁的形式緩存,然后更新本地分支到最新,最后將緩存的補(bǔ)丁依次合到當(dāng)前分支,最終分支歷史看起來就像沒有經(jīng)過合并一樣。
當(dāng)遇到?jīng)_突的時(shí)候,rebase 命令會(huì)被暫停,等待沖突解決,解決玩沖突后,你只需要 git add 而無需 git commit,直接執(zhí)行 git rebase --continue 繼續(xù)處理;另外,任何時(shí)候,開發(fā)者都可以執(zhí)行 git rebase --abort 命令終止 rebase 的動(dòng)作,然后恢復(fù)至 rebase 開始前的狀態(tài)。
rebase 除了讓 Git 系統(tǒng)自動(dòng)完成合并外,還可以交互式的進(jìn)行。git rebase -i origin/master,輸入命令后如下圖:

圖中表示當(dāng)前分支的暫存區(qū)只有一次提交,并且格式滿足:
(action) (partial-sha) (short commit message)
pick對(duì)應(yīng)的是 git 將采用并合并這次提交,如果用 squash 表示與上一個(gè)提交合并為一次提交,如果 為 edit,則當(dāng) git 處理到此次提交之后,返回命令行讓你對(duì)提交進(jìn)行修改,比如將提交拆分為多個(gè)等。最后,如果不采用任何一個(gè) action 而是直接把某次提交刪除,那么 git 就會(huì)直接從歷史中移除該提交。
stash
git stash
git stash apply
git stash pop
git stash list
git stash pop stash${id}
git stash clear