Git本地版本管理
一些基本概念
分布式版本控制系統(tǒng)
Git 是一種分布式版本控制系統(tǒng) (Distributed Version Control System DVCS) 。這種系統(tǒng)下,客戶端不只是簡(jiǎn)單地拉取某個(gè)版本的文件,而是把整個(gè)記錄文件版本的數(shù)據(jù)庫(kù)(即整個(gè)代碼倉(cāng)庫(kù))都克隆到本地系統(tǒng)上。這樣以來(lái),任何一處協(xié)同工作用的服務(wù)器發(fā)生故障,事后都可以用任何一個(gè)鏡像出來(lái)的本地倉(cāng)庫(kù)恢復(fù)。因?yàn)槊恳淮蔚目寺」ぷ?#xff0c;實(shí)際上都是一次對(duì)代碼倉(cāng)庫(kù)的完整備份。
存儲(chǔ)方式
Git 中所有數(shù)據(jù)在存儲(chǔ)前都會(huì)計(jì)算校驗(yàn)和,然后以校驗(yàn)和來(lái)引用某個(gè)版本的文件,該校驗(yàn)和是根據(jù)文件的內(nèi)容或目錄結(jié)構(gòu)使用 SHA-1 哈希算法計(jì)算出來(lái)的,比如:
24b9da6552252987aa493b52f8696cd6d3b00373Git 數(shù)據(jù)庫(kù)中保存的信息都是以文件內(nèi)容的哈希值來(lái)索引,而不是文件名。
三種狀態(tài)
Git 最重要的地方是有三個(gè)區(qū):
- Git 倉(cāng)庫(kù):這個(gè)就是保存各種文件版本的數(shù)據(jù)庫(kù),可以向這個(gè)數(shù)據(jù)庫(kù)中拉取各個(gè)文件版本或把更新后的文件推入數(shù)據(jù)庫(kù)進(jìn)行記錄。這是 Git 用來(lái)保存項(xiàng)目的元數(shù)據(jù)和對(duì)象數(shù)據(jù)庫(kù)的地方,是 Git 最重要的部分,從其他計(jì)算機(jī)克隆倉(cāng)庫(kù)時(shí),拷貝的就是這里的數(shù)據(jù)。已經(jīng)推入到這個(gè)數(shù)據(jù)庫(kù)中的文件對(duì)應(yīng)的狀態(tài)是 已提交 (commited) 。
- 暫存區(qū)域:這個(gè)區(qū)域用來(lái)存儲(chǔ)對(duì)當(dāng)前已修改過(guò)并且作了版本標(biāo)記的文件,在同一段時(shí)間內(nèi)位于暫存區(qū)尚未提交的所有文件都屬于同一個(gè)當(dāng)前的版本,這些標(biāo)記使得對(duì)應(yīng)文件被包含在下次提交的快照中。這個(gè)區(qū)域是一個(gè)文件,保存了下次將提交的文件列表信息,一般位于 Git 倉(cāng)庫(kù)目錄中。在這個(gè)區(qū)域的文件狀態(tài)是 已暫存 (staged) 。
- 工作目錄:這個(gè)區(qū)域就是開(kāi)發(fā)人員寫(xiě)代碼的地方,對(duì)于已經(jīng)修改并保存的文件,都會(huì)存儲(chǔ)在這個(gè)區(qū)域,等待轉(zhuǎn)移到暫存區(qū)并提交。它是對(duì)項(xiàng)目的某個(gè)版本獨(dú)立提取出來(lái)的內(nèi)容。那些從 Git 倉(cāng)庫(kù)的壓縮數(shù)據(jù)庫(kù)中提取出來(lái)的文件,就是放在這個(gè)區(qū)域所在的磁盤(pán)上供你使用或修改。在這個(gè)區(qū)域的文件狀態(tài)是 已修改 (modified) 。
Git 工作三部曲
常用命令
配置用戶名和密碼
$ git config --global user.name "Jack Cheng" $ git config --global user.email "767833640@qq.com"如果使用了 --global 選項(xiàng),則該命令只需要提交一次,無(wú)論你以后在系統(tǒng)中執(zhí)行何種操作,Git 都會(huì)使用這種配置。如果你想針對(duì)某個(gè)特定的項(xiàng)目使用不同的用戶名稱和郵箱,可以在那個(gè)項(xiàng)目目錄下運(yùn)行沒(méi)有 --global 選項(xiàng)的命令來(lái)配置。
檢查配置信息
$ git config --list檢查具體某一項(xiàng)的配置
$ git config user.name獲取幫助
$ git help config $ git help push創(chuàng)建倉(cāng)庫(kù)
$ git init這個(gè)命令將創(chuàng)建一個(gè)名為 .git 的子目錄,這個(gè)字目錄含有你初始化的 Git 倉(cāng)庫(kù)中所有的必須文件,這些文件是 Git 倉(cāng)庫(kù)的骨干。但是這只是做了一個(gè)初始化操作,在當(dāng)?shù)匚募A的項(xiàng)目里的文件還沒(méi)有被跟蹤。使用 git add 命令來(lái)跟蹤文件,使用 git commit 命令來(lái)提交文件到本地的 Git 倉(cāng)庫(kù)中。
檢查狀態(tài)
$ git status可以查看當(dāng)前倉(cāng)庫(kù)哪些文件處于未跟蹤狀態(tài),哪些文件已經(jīng)放入暫存區(qū)等待提交。
可以看到 .DS_Store 文件位于 Untracked files 標(biāo)題下,表示這個(gè)文件是新創(chuàng)建的未被跟蹤的文件,Git 倉(cāng)庫(kù)中不存在這個(gè)文件的信息。
可以看到這個(gè)時(shí)候 .gitignore 文件位于 Changes to be commited 這個(gè)標(biāo)題下面,說(shuō)明這個(gè)文件已經(jīng)被移入暫存區(qū)了,處于已暫存的狀態(tài)。
把已修改或未跟蹤的文件放入暫存區(qū)
$ git add 文件名git add 不僅可以跟蹤新文件并放到暫存區(qū),還能把已修改的文件也放到暫存區(qū),這是一個(gè)多功能命令。放到暫存區(qū)的這些文件在下次提交時(shí)將會(huì)一并提交到 Git 倉(cāng)庫(kù)中。因此對(duì)于 git add 命令的最好翻譯是 “添加內(nèi)容到下一次的提交中”。
$ git add 文件目錄此時(shí) git add 命令將遞歸地跟蹤該目錄下的所有文件,并把目錄下的所有文件都放入暫存區(qū)。
查看已暫存的文件和當(dāng)前工作目錄中文件的差異
$ git diffgit diff 命令可以查看當(dāng)前工作目錄中已修改的文件和暫存區(qū)的文件的差異(注意只是和暫存區(qū)的差異,不是和上次提交以來(lái)的差異,因此如果你把所有已經(jīng)修改的文件都添加到暫存區(qū)后,git diff 將不會(huì)返回任何東西)
查看已暫存的文件和上一次提交后的文件的變化
$ git diff --staged 或者 $ git diff --cached提交處于暫存區(qū)的所有文件
$ git commit -m "說(shuō)明當(dāng)前做了什么,以后版本回退時(shí)可以輕易找到"注意提交的都是放在暫存區(qū)的文件,每一次的提交的版本都會(huì)在歷史記錄中記錄下來(lái),以后都可以回到這個(gè)版本。(只有 commit 以后的版本可以回退)
回到過(guò)去
$ git log使用 git log 命令查看歷史提交記錄:
$ git log --pretty=oneline為了簡(jiǎn)化查看,可以使用 git log --pretty=oneline 參數(shù):
$ git reset --hard commit_id找到要回退的版本的前面的 commit_id,然后使用 git reset --hard commit_id 命令來(lái)回退到想要的版本,只需要打出 commit_id 的前幾個(gè)字母即可,Git 會(huì)自動(dòng)查找對(duì)應(yīng)的 id :
可以看到此時(shí)項(xiàng)目的最新版本已經(jīng)回退到了 3950d 的版本。
從過(guò)去回到現(xiàn)在
$ git reflog回退以后,會(huì)發(fā)現(xiàn)之前的最新版本 9fd77 已經(jīng)不在 git log 的目錄中了,此時(shí)假如我們又想回到之前的最新的版本怎么辦?首先使用 git reflog 命令來(lái)查找提交 9fd77 時(shí)的記錄:
git reset --hard commit_id可以看到我們?cè)诨赝饲白钚乱淮翁峤坏?commit_id 是 9fd77b1 ,因此我們?cè)儆?git reset --hard 9fd77b1 來(lái)進(jìn)入到回退前的最新版本:
因此,我們也就從過(guò)去回到現(xiàn)在了。
一些 trick
忽略文件
有時(shí)候我們會(huì)有一些文件不需要納入 Git 的管理,比如上面的 .DS_Store ,此時(shí)就應(yīng)該編寫(xiě) .gitignore 文件來(lái)列出要 Git 倉(cāng)庫(kù)忽略的文件模式。該文件的格式規(guī)范如下:
以 # 開(kāi)頭的行為 Git 的注釋。
使用 / 放在文件名的開(kāi)頭可以防止遞歸地忽略所有非當(dāng)前目錄中的該文件。比如
TODO會(huì)忽略 Git 倉(cāng)庫(kù)中所有目錄下的 TODO 文件,但如果只希望 Git 忽略當(dāng)前目錄下的 TODO 文件,而不要忽略其它目錄下的 TODO 文件,則應(yīng)該寫(xiě)成這樣:
/TODO使用 / 放在文件名的末尾表明這個(gè)文件是一個(gè)目錄,Git 將會(huì)忽略這個(gè)目錄下的所有文件。
如果希望 Git 只記錄某一個(gè)特定的文件,而忽略除了這個(gè)文件以外的所有文件,可以在這個(gè)文件名前面使用 ! 取反。但是這種功能一般是用于以下情況:
# 忽略所有的 .a 文件*.a# 但是所有的 lib.a 文件不能被忽略!lib.a指定文件的格式一般要使用正則表達(dá)式:
- * 匹配 0 個(gè)或多個(gè)任意字符;
- [abc] 可以匹配任何一個(gè)在方框號(hào)中的字符(在這個(gè)例子中是要么匹配一個(gè)a,要么匹配一個(gè)b,要么匹配一個(gè)c);
- ? 只匹配一個(gè)任意字符;
- [0-9] 表示匹配在 0 到 9 范圍內(nèi)的所有數(shù)字。
- 使用兩個(gè)星號(hào) ** 表示匹配任意的中間目錄,比如 learn/**/git 可以匹配 learn/git 、learn/no/git 或者 learn/no/python/git 。
看一個(gè) .gitignore 文件的例子:
# 忽略所有以 .a 結(jié)尾的文件 *.a# 不能忽略所有 lib.a 文件 !lib.a# 僅僅忽略當(dāng)前目錄下的 TODO 文件 /TODO# 忽略 build 目錄下的所有文件 build/# 僅僅忽略 doc 一個(gè)目錄下的所有 .txt 文件 doc/*.txt# 忽略 doc 目錄下(包括子目錄)的所有 .pdf 文件 doc/**/*.pdf移除文件
最常見(jiàn)的情況是,在 .gitignore 文件中未列出對(duì)應(yīng)的文件,有時(shí)為了貪求效率,使用 git add . 把所有文件都放到暫存區(qū)域,包括把一些不希望加入 Git 版本管理的日志文件等也放進(jìn)去了,這個(gè)時(shí)候我們希望可以從暫存區(qū)域中刪除這些不希望被管理的文件,但是使這些文件仍然被存放在工作目錄上,而不被 Git 繼續(xù)跟蹤。此時(shí)可以使用 git rm --cached filename 命令:
這樣就可以把誤添加的文件從暫存區(qū)中移除,而防止下一次 commit 時(shí)加入到 Git 倉(cāng)庫(kù)中去。
還有一種情況就是,我希望刪除的文件已經(jīng) commit 或者 add 了,即已經(jīng)被跟蹤了,但我希望完全刪除這個(gè)文件,即把工作目錄中的這個(gè)文件也刪了,這時(shí)我們就可以先在本地項(xiàng)目目錄中刪除這個(gè)文件,然后再使用 git rm filename 命令把該文件從已跟蹤的文件清單中一并刪除:
這個(gè)是文件已經(jīng) add 但沒(méi)有 commit 的情況,使用 git rm 命令就直接清空了,如果文件之前有過(guò) commit ,而你又把想刪除的文件從工作目錄中刪除了:
可以看到刪除文件的操作記錄在 Changes not staged for commit 標(biāo)題下, 意味著你需要把這個(gè)刪除的操作再提交一遍,使得 Git 倉(cāng)庫(kù)知道這個(gè)文件已經(jīng)刪除了,不應(yīng)該再被跟蹤了。
移動(dòng)文件
如果要在 Git 中對(duì)某些文件進(jìn)行重命名,可以使用 git mv original_name target_name 命令:
執(zhí)行這個(gè)命令后,可以看到在工作目錄中的 test.cpp 也被重命名為 main.cpp 了,這個(gè)時(shí)候只要提交這次重命名操作就可以了。
參考資料
總結(jié)
- 上一篇: CSS之viewports剖析
- 下一篇: 【收集】前端技能知识图谱