基礎
一、取得項目的 Git 倉庫
兩種取得 Git 項目倉庫的方法。第一種是在現存的目錄下,通過導入所有文件來創建新的 Git 倉庫。第二種是從已有的 Git 倉庫克隆出一個新的鏡像倉庫來。
1、從當前目錄初始化
要對現有的某個項目開始用 Git 管理,只需到此項目所在的目錄,執行:
初始化后,在當前目錄下會出現一個名為 .git 的目錄,所有 Git 需要的數據和資源都存放在這個目錄中。
如果當前目錄下有幾個文件想要納入版本控制,需要先用 git add 命令告訴 Git 開始對這些文件進行跟蹤,然后提交:
現在,你已經得到了一個實際維護着若干文件的 Git 倉庫。
2、從現有倉庫克隆
克隆倉庫的命令格式為git clone [url]。比如,要克隆 Ruby 語言的 Git 代碼倉庫 Grit,可以用下面的命令:
這會在當前目錄下創建一個名為 “grit” 的目錄,其中內含一個.git 的目錄,並從同步后的倉庫中拉出所有的數據,取出最新版本的文件拷貝。如果進入這個新建的grit 目錄,你會看到項目中的所有文件已經在里邊了,准備好后續的開發和使用。如果希望在克隆的時候,自己定義要新建的項目目錄名稱,可以在上面的命令最后指定:
Git 支持許多數據傳輸協議。之前的例子使用的是git:// 協議,不過你也可以用http(s):// 或者user@server:/path.git 表示的 SSH 傳輸協議。
二、記錄每次更新到倉庫
工作目錄(work directory)下面的所有文件都不外乎這兩種狀態:已跟蹤或未跟蹤。
已跟蹤的文件是指本來就被納入版本控制管理的文件,在上次快照中有它們的記錄,工作一段時間后,它們的狀態可能是未更新,已修改(modified)或者已放入暫存區(staged)。而所有其他文件都屬於未跟蹤文件。它們既沒有上次更新時的快照,也不在當前的暫存區域。初次克隆某個倉庫時,工作目錄中的所有文件都屬於已跟蹤文件,且狀態為未修改。
1、檢查當前文件狀態
可以用 git status 命令。如果在克隆倉庫之后立即執行此命令,會看到類似這樣的輸出:
現在讓我們用 vim 編輯一個新文件 README,保存退出后運行git status 會看到該文件出現在未跟蹤文件列表中:
2、跟蹤新文件
使用命令git add 開始跟蹤一個新文件。所以,要跟蹤 README 文件,運行:
此時再運行git status 命令,會看到 README 文件已被跟蹤,並處於暫存狀態:
只要在 “Changes to be committed” 這行下面的,就說明是已暫存狀態。如果此時提交,那么該文件此時此刻的版本將被留存在歷史記錄中。
git add 后可以接要跟蹤的文件或目錄的路徑。如果是目錄的話,就說明要遞歸跟蹤所有該目錄下的文件。
3、暫存已修改文件
現在我們修改下之前已跟蹤過的文件benchmarks.rb,然后再次運行status 命令,會看到這樣的狀態報告:
文件 benchmarks.rb 出現在 “Changed but not updated” 這行下面,說明已跟蹤文件的內容發生了變化,但還沒有放到暫存區。
要暫存這次更新,需要運行git add 命令(這是個多功能命令,根據目標文件的狀態不同,此命令的效果也不同:可以用它開始跟蹤新文件,或者把已跟蹤的文件放到暫存區,還能用於合並時把有沖突的文件標記為已解決狀態等)
現在兩個文件都已暫存,下次提交時就會一並記錄到倉庫。假設此時,你想要在 benchmarks.rb 里再加條注釋,重新編輯存盤后,准備好提交。benchmarks.rb 文件出現了兩次!一次算未暫存,一次算已暫存,這怎么可能呢?好吧,實際上 Git只不過暫存了你運行 git add 命令時的版本,如果現在提交,那么提交的是添加注釋前的版本,而非當前工作目錄中的版本。所以,運行了git add 之后又作了修訂的文件,需要重新運行git add 把最新版本重新暫存起來。
4、忽略某些文件
我們可以創建一個名為 .gitignore 的文件,列出要忽略的文件模式,來看一個簡單的例子:
第一行告訴 Git 忽略所有以 .o 或 .a 結尾的文件。一般這類對象文件和存檔文件都是編譯過程中出現的,我們用不着跟蹤它們的版本。
第二行告訴 Git 忽略所有以波浪符(~)結尾的文件,許多文本編輯軟件(比如 Emacs)都用這樣的文件名保存副本。
文件 .gitignore 的格式規范如下:
•所有空行或者以注釋符號 # 開頭的行都會被 Git 忽略。
•可以使用標准的 glob 模式匹配。
•匹配模式最后跟反斜杠(/)說明要忽略的是目錄。
•要忽略指定模式以外的文件或目錄,可以在模式前加上驚嘆號(!)取反。
glob 模式是指 shell 所使用的簡化了的正則表達式。星號(*)匹配零個或多個任意字符;[abc] 匹配任何一個列在方括號中的字符(這個例子要么匹配一個 a,要么匹配一個 b,要么匹配一個 c);問號(?)只匹配一個任意字符;如果在方括號中使用短划線分隔兩個字符,表示所有在這兩個字符范圍內的都可以匹配(比如[0-9] 表示匹配所有 0 到 9 的數字)。再看一個 .gitignore 文件的例子:
5、查看已暫存和未暫存的更新
實際上git status 的顯示比較簡單,僅僅是列出了修改過的文件,如果要查看具體修改了什么地方,可以用git diff 命令。git diff 會使用文件補丁的格式顯示具體添加和刪除的行。
假如再次修改 README 文件后暫存,然后編輯 benchmarks.rb 文件后先別暫存,運行status 命令,會看到:
要查看尚未暫存的文件更新了哪些部分,不加參數直接輸入git diff:
此命令比較的是工作目錄中當前文件和暫存區域快照之間的差異,也就是修改之后還沒有暫存起來的變化內容。
若要看已經暫存起來的文件和上次提交時的快照之間的差異,可以用git diff --cached 命令。(Git 1.6.1及更高版本還允許使用git diff --staged,效果是相同的,但更好記些。)來看看實際的效果:
請注意,單單git diff 不過是顯示還沒有暫存起來的改動,而不是這次工作和上次提交之間的差異。
6、提交更新
每次准備提交前,先用git status 看下,是不是都已暫存起來了,然后再運行提交命令git commit:
這種方式會啟動文本編輯器以便輸入本次提交的說明。編輯器會顯示類似下面的文本信息(本例選用 Vim 的屏顯方式展示):
可以看到,默認的提交消息包含最后一次運行git status 的輸出,放在注釋行里,另外開頭還有一空行,供你輸入提交說明。你完全可以去掉這些注釋行,不過留着也沒關系,多少能幫你回想起這次更新的內容有哪些。(如果覺得這還不夠,可以用-v 選項將修改差異的每一行都包含到注釋中來。)退出編輯器時,Git 會丟掉注釋行,將說明內容和本次更新提交到倉庫。
也可以使用 -m 參數后跟提交說明的方式,在一行命令中提交更新:
現在你已經創建了第一個提交!可以看到,提交后它會告訴你,當前是在哪個分支(master)提交的,本次提交的完整 SHA-1 校驗和是什么(463dc4f),以及在本次提交中,有多少文件修訂過,多少行添改和刪改過。
提交時記錄的是放在暫存區域的快照,任何還未暫存的仍然保持已修改狀態,可以在下次提交時納入
版本管理。每一次運行提交操作,都是對你項目作一次快照,以后可以回到這個狀態,或者進行比較。
7、跳過使用暫存區域
給git commit 加上-a 選項,Git 就會自動把所有已經跟蹤過的文件暫存起來一並提交,從而跳過git add 步驟:
8、移除文件
要從 Git 中移除某個文件,就必須要從已跟蹤文件清單中移除(確切地說,是從暫存區域移除),然后提交。可以用git rm 命令完成此項工作,並連帶從工作目錄中刪除指定的文件,這樣以后就不會出現在未跟蹤文件清單中了。
如果只是簡單地從工作目錄中手工刪除文件,運行git status 時就會在 “Changed but not updated” 部分(也就是_未暫存_清單)看到:
然后再運行git rm 記錄此次移除文件的操作:
如果刪除之前修改過並且已經放到暫存區域的話,則必須要用強制刪除選項-f(譯注:即 force 的首字母),以防誤刪除文件后丟失修改的內容。
另外一種情況是,我們想把文件從 Git 倉庫中刪除(亦即從暫存區域移除),但仍然希望保留在當前工作目錄中。換句話說,僅是從跟蹤清單中刪除。比如一些大型日志文件或者一堆.a 編譯文件,不小心納入倉庫后,要移除跟蹤但不刪除文件,以便稍后在.gitignore 文件中補上,用--cached 選項即可:
后面可以列出文件或者目錄的名字,也可以使用 glob 模式。比方說:
注意到星號* 之前的反斜杠\,因為 Git 有它自己的文件模式擴展匹配方式,所以我們不用 shell 來幫忙展開。
9、移動文件
不像其他的 VCS 系統,Git 並不跟蹤文件移動操作。
當你看到 Git 的mv 命令時一定會困惑不已。要在 Git 中對文件改名,可以這么做:
它會恰如預期般正常工作。實際上,即便此時查看狀態信息,也會明白無誤地看到關於重命名操作的說明:
其實,運行git mv 就相當於運行了下面三條命令: