【正文】
我們先要做好準備工作,将某個項目建立版本庫,我這裡就建立一個android項目gittest,建立一個版本庫。打開git bash,進入到這個項目的根目錄下,然後執行git init指令,如下圖所示:

這樣,準備工作就做好了。
一、忽略檔案:
版本庫已經建立好了,接下來我們需要送出項目中的代碼,但是不是所有的檔案都需要加入到版本控制當中去呢?
我們需要知道,在android項目結構中,bin目錄和gen下的檔案都是自動生成的,我們不應該将這部分檔案添加到版本控制當中,否則有可能會對檔案的自動生成造成影響。那如何才能實作這樣的效果呢?
其實,git會檢查版本庫中的根目錄下是否存在一個名為.gitignore的檔案,如果存在的話,就去一行一行的讀取這個檔案中的内容,并把每一行指定的檔案或目錄排除在版本控制之外。注意,.gitignore的檔案中指定的檔案或者目錄是可以使用“*”通配符的。
【步驟】
現在,我們在gittest項目的根目錄下建立一個名為.gitignore的檔案,然後去編輯這個檔案中的内容。如下圖所示:
這樣就把bin目錄和gen下的檔案都忽略掉,進而使它們不會加入到版本控制中。
記住,.gitignore檔案的編碼方式必須為utf-8:
然後就可以使用add送出代碼:
然後執行commit指令完成送出:
注:以後每次修改忽略檔案之後,或者重新添加了檔案,都必須重新送出,檔案才會生效。
問:如果某個檔案被加入到忽略檔案中,即使被修改了内容,通過git status 和git diff也還是能夠看到的修改記錄,這是為什麼呢?是忽略檔案無效嗎?
二、檢視修改的内容:(未送出之前)
git比其他版本控制系統設計得優秀,因為git跟蹤并管理的是修改,而非檔案。
在進行一次代碼送出之後,我們後面還需要對項目不斷地進行維護,添加新功能。理想的情況是:每完成一小塊功能,就執行一次送出。git會記住每一次送出的狀态。
注:這裡能檢視到的修改内容是指送出之前的修改。如果你已經送出了,馬上再輸入這個指令,就看不到修改的内容了。
1、檢視被修改的檔案:git status
檢視檔案修改的情況的方法非常簡單,隻需在根目錄執行如下指令:
然後git會提示目前項目中沒有任何可送出的檔案,因為我們才剛剛送出過。現在我們在布局檔案中,添加一個button,添加的代碼如下:
然後再輸入git status看一下:
git status指令可以讓我們時刻掌握倉庫目前的狀态,上面的指令告訴我們,activity_main.xml被修改過了,但這還隻是沒有送出的修改。
2、檢視檔案的具體修改内容:git diff
之前的git status指令可以檢視被修改的檔案是什麼,如果要檢視具體的修改内容,需要輸入如下指令:
執行結果如下:
git diff顧名思義就是檢視difference,顯示的格式正是unix通用的diff格式。
如果隻想檢視activity_main.xml這個檔案的更改内容,可以使用如下指令:
3、撤銷未add的修改:git checkout
隻要代碼未送出,所有修改的内容都是可以撤銷的。可以執行git checkout這個指令。即執行如下指令:
執行之後,我們對activity_main.xml這個檔案在add之前所做的全部修改都被撤銷了。
重新運作git status指令檢查一下:
可以看到,目前項目沒有任何可以送出的檔案,撤銷成功。
4、撤銷未commit的修改:git reset和git checkout
不過上面這種方式隻适用于還沒有執行過add指令的檔案,如果某個檔案已經被add過了,這種方式是無效的。
此時應該采取的步驟是:先使用reset指令取消add添加(此時暫存區中的内容将被清空,之前所有的add都是無效的),再使用checkout指令将修改的内容進行撤銷。即執行如下指令:
【總結】
指令git checkout -- filename意思就是,把filename這個檔案在工作區的修改全部撤銷。
這裡有兩種情況:
一種是readme.txt自修改後還沒有被放到暫存區,現在,撤銷修改就回到和版本庫一模一樣的狀态;
一種是readme.txt已經添加到暫存區後,又作了修改,現在,撤銷修改就回到添加到暫存區後的狀态。
一句話總結,即:用暫存區中filename檔案來覆寫工作區中的filename檔案。
注:git checkout -- file指令中的“--”很重要,沒有“--”,就變成了“建立一個新分支”的指令,我們在後面的分支管理中會再次遇到git checkout指令。
5、删除檔案:
當你直接在在檔案管理器中把沒用的檔案(這裡以忽略檔案為例)删了,這個時候,git知道你删除了檔案,是以,工作區和版本庫就不一緻了,git status指令會立刻告訴你哪些檔案被删除了:
現在你有兩個選擇,一是确實要從版本庫中删除該檔案,那就用指令git rm删掉,并且commit:
另一種情況是删錯了,現在不想删除,因為版本庫裡還有呢,是以可以很輕松地把誤删的檔案恢複到最新版本:
注:git checkout其實是用版本庫裡的版本(準确來說是暫存區的版本)替換工作區的版本,無論工作區是修改還是删除,都可以“一鍵還原”。
三、檢視送出記錄:(log指令)
每當你覺得檔案修改到一定程度的時候,就可以“儲存一個快照”,這個快照在git中被稱為commit。一旦你把檔案改亂了,或者誤删了檔案,還可以從最近的一個commit恢複,然後繼續工作,而不是把幾個月的工作成果全部丢失。
當某個項目開發了幾個月之後,我們可能已經執行過上百次的送出操作了。這個時候估計你早就忘記了每次送出都修改了哪些内容。不過沒關系,git一直都幫我們記錄着呢。
我們現在将之前的修改進行送出:
然後執行如下指令檢視送出記錄:
執行的結果如下:
可以看到,每次送出都會包含送出id,送出人,送出日期,以及送出描述這四個資訊。
你看到的一大串類似“ 3628164...882e1e0”的是commit id(版本号),和svn不一樣,git的commit id不是1,2,3……遞增的數字,而是一個sha1計算出來的一個非常大的數字,用十六進制表示,而且你看到的commit id和我的肯定不一樣,以你自己的為準。為什麼commit id需要用這麼一大串數字表示呢?因為git是分布式的版本控制系統,後面我們還要好幾個人在同一個版本庫裡工作,如果大家都用1,2,3……作為版本号,那肯定就沖突了。
當送出記錄非常多的時候,我們隻想檢視其中的某條記錄,可以在該log指令的後面加上對應記錄的id,并加上-l參數。即:git log [id] -l
而如果想要檢視這條記錄送出記錄的具體修改了什麼内容,可以繼續加上-p參數。即:git log [id] -l -p
四、版本回退:
我們現在進行第二次修改,也就是說,在布局檔案中添加一個按鈕button2,然後執行git log指令,顯示效果如下:
上圖顯示,我們總共進行了三次送出。
每送出一個新版本,實際上git就會把它們自動串成一條時間線。執行如下指令進入可視化界面:
執行後彈出如下界面:
現在開始我們的版本回退工作。
首先,git必須知道目前版本是哪個版本,在git中,用head表示目前版本,上一個版本就是head^,上上一個版本就是head^^,當然往上100個版本寫100個^比較麻煩,是以寫成head~100。
【新版本回到舊版本】
現在,我們從“版本3”回退到上一個版本,即回退到“版本2”,就可以使用git reset指令:
執行效果如下:
--hard參數有啥意義?這個後面再講,暫時先放心使用。
再執行git log指令,發現版本三已經不見了:
【舊版本回到新版本】
如果現在要從“版本2”回到“版本3”,該怎麼辦呢?辦法其實還是有的。
隻要上面的指令行視窗還沒有被關掉,就可以順着往上找,隻要找到版本3的id号就行了,即輸入如下指令:
版本号沒必要寫全,寫前7位就可以了,git會自動去找。
如果你想回退到某個版本,但是電腦已經關閉了,這個時候已經找不到新版本的commit id了,該怎麼辦呢?辦法總是有的。git提供了一個指令git reflog用來記錄你的每一次指令。即輸入如下指令:
于是,我們終于找到了版本三的commit id。又可以輸入同樣的指令回到版本三了。
現在我們可以做一個總結了:
head指向的版本就是目前版本,是以,git允許我們在版本的曆史之間穿梭,使用指令git reset --hard commit_id
穿梭前,用git log可以檢視有哪些版本,以便确定要回退到哪個版本
要重返未來,用git reflog檢視指令曆史,以便确定要回到未來的哪個版本
五、工作區和暫存區的概念:
git和其他版本控制系統如svn的一個不同之處就是有暫存區的概念。
工作區(working directory):就是你在電腦裡能看到的目錄;
版本庫(repository):工作區有一個隐藏目錄“.git”,這個不算工作區,而是git的版本庫
git的版本庫裡存了很多東西,其中最重要的就是稱為stage(或者叫index)的暫存區,還有git為我們自動建立的第一個分支master,以及指向master的一個指針叫head。
注:分支和head的概念稍後再說。
我們把檔案往git版本庫裡添加的時候,是分兩步執行的:
第一步是用“git add”把檔案添加進去,實際上就是把檔案修改添加到暫存區;
第二步是用“git commit”送出更改,實際上就是把暫存區的所有内容送出到目前分支。
因為我們建立git版本庫時,git自動為我們建立了唯一一個master分支,是以,現在,commit就是往master分支上送出更改。可以簡單了解為,需要送出的檔案修改通通放到暫存區,然後,一次性送出暫存區的所有修改。一旦送出後,如果你又沒有對工作區做任何修改,那麼工作區就是“幹淨”的。即:nothing to commit (working directory clean)。
注:用“git diff head -- filename”指令可以檢視工作區和暫存區裡面最新版本的差別。
關于遠端倉庫的使用,我們将在下一章節中進行講解。