git 使用詳解(3)—— 最基本命令 + .gitignore 文件
Git 基礎
本章將介紹幾個最基本的,也是最常用的 Git 命令,以後絕大多數時間裏用到的也就是這幾個命令。讀完本章,你就能初始化一個新的代碼倉庫,做一些適當配置;開始或停止跟蹤某些文件;暫存或提交某些更新。我們還會展示如何讓 Git 忽略某些文件,或是名稱符合特定模式的文件;如何既快且容易地撤消犯下的小錯誤;如何瀏覽項目的更新歷史,查看某兩次更新之間的差異;以及如何從遠程倉庫拉數據下來或者推數據上去。
1. 在工作目錄中初始化新倉庫
要對現有的某個項目開始用 Git 管理,只需到此項目所在的目錄,執行:
$ git init
初始化後,在當前目錄下會出現一個名為 .git 的目錄,所有 Git 需要的數據和資源都存放在這個目錄中。不過目前,僅僅是按照既有的結構框架初始化好了裏邊所有的文件和目錄,但我們還沒有開始跟蹤管理項目中的任何一個文件。
如果當前目錄下有幾個文件想要納入版本控制,需要先用 git add 命令告訴 Git 開始對這些文件進行跟蹤,然後提交:
$ git add *.c
$ git add README
$ git commit -m ‘initial project version‘
現在,你已經得到了一個實際維護著若幹文件的 Git 倉庫
2. 從現有倉庫克隆
如果想對某個開源項目出一份力,可以先把該項目的 Git 倉庫復制一份出來,這就需要用到 git clone 命令。如果你熟悉其他的 VCS 比如 Subversion,你可能已經註意到這裏使用的是 clone 而不是 checkout。這是個非常重要的差別,Git 收取的是項目歷史的所有數據(每一個文件的每一個版本),服務器上有的數據 克隆 之後本地也都有了。實際上,即便服務器的磁盤發生故障,用任何一個克隆出來的客戶端都可以重建服務器上的倉庫,回到當初克隆時的狀態。
克隆倉庫的命令格式為 git clone [url]
。比如,要克隆 Ruby 語言的 Git 代碼倉庫 Grit,可以用下面的命令:
$ git clone git://github.com/schacon/grit.git
這會在 當前目錄下 創建一個名為 “grit” 的目錄,其中包含一個 .git 的目錄,用於保存下載下來的所有版本記錄,然後從中取出最新版本 的文件拷貝。如果進入這個新建的 grit 目錄,你會看到項目中的所有文件已經在裏邊了,準備好後續的開發和使用。如果希望在克隆的時候,自己定義要新建的項目目錄名稱,可以在上面的命令末尾指定新的名字
:
$ git clone git://github.com/schacon/grit.git mygrit
唯一的差別就是,現在新建的目錄成了 mygrit,其他的都和上邊的一樣。
Git 支持許多數據傳輸協議。之前的例子使用的是 git:// 協議
,不過你也可以用 http(s)://
或者user@server:/path.git 表示的 SSH 傳輸協議
。
3. 記錄每次更新到倉庫
現在我們手上已經有了一個真實項目的 Git 倉庫,並從這個倉庫中取出了所有文件的工作拷貝。接下來,對這些文件作些修改,在完成了一個階段的目標之後,提交本次更新到倉庫。
工作目錄下面的所有文件都不外乎這兩種狀態:已跟蹤或未跟蹤。已跟蹤的文件是指本來就被納入版本控制管理的文件,在上次快照中有它們的記錄,工作一段時間後,它們的狀態可能是未更新,已修改或者已放入暫存區。而所有其他文件都屬於未跟蹤文件。它們既沒有上次更新時的快照,也不在當前的暫存區域。初次克隆某個倉庫時,工作目錄中的所有文件都屬於已跟蹤文件,且狀態為 未修改。
在編輯過某些文件之後,Git 將這些文件標為已修改。我們逐步把這些修改過的文件放到暫存區域,直到最後一次性提交所有這些暫存起來的文件,如此重復。
3.1 檢查當前文件狀態
要確定 哪些文件 當前 處於 什麽狀態,可以用 git status 命令。如果在克隆倉庫之後立即執行此命令,會看到類似這樣的輸出:
$ git status
# On branch master nothing to commit (working directory clean)
這說明你
- 現在的工作目錄 沒有任何文件在上次提交後更改過。
- 此外,上面的信息還表明,當前目錄下沒有出現任何處於未跟蹤的新文件,否則 Git 會在這裏列出來。
- 最後,該命令還顯示了當前所在的分支是 master,這是默認的分支名稱,實際是可以修改的。
現在讓我們用 vim 編輯一個新文件 README,保存退出後運行 git status 會看到該文件出現在未跟蹤文件列表中:
$ vim README
$ git status
# On branch master
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
# # README nothing added to commit but untracked files present (use "git add" to track)
就是在“Untracked files”這行下面。Git 不會自動將之納入跟蹤範圍,除非你明明白白地告訴它“我需要跟蹤該文件”,因而不用擔心把臨時文件什麽的也歸入版本管理。不過現在的例子中,我們確實想要跟蹤管理 README 這個文件。
3.2 跟蹤新文件
使用命令 git add
開始跟蹤一個新文件。所以,要跟蹤 README 文件,運行:
$ git add README
此時再運行 git status 命令,會看到 README 文件已被跟蹤,並處於暫存狀態:
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
# # new file: README #
只要在 “Changes to be committed”
這行下面的,就說明是已暫存狀態
。如果此時提交,那麽該文件此時此刻的版本將被留存在歷史記錄中。你可能會想起之前我們使用 git init 後就運行了 git add 命令,開始跟蹤當前目錄下的文件。在 git add 後面可以指明要跟蹤的 文件 或 目錄 路徑。如果是目錄的話,就說明要遞歸跟蹤該目錄下的所有文件。
3.3 暫存已修改文件
現在我們修改下之前已跟蹤過的文件 benchmarks.rb,然後再次運行 status 命令,會看到這樣的狀態報告:
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
# # new file: README
# # Changed but not updated:
# (use "git add <file>..." to update what will be committed)
# # modified: benchmarks.rb #
文件 benchmarks.rb 出現在 “Changed but not updated”
這行下面,說明已跟蹤文件的內容發生了變化,但還沒有放到 暫存區。要暫存這次更新,需要運行 git add 命令(這是個多功能命令,根據目標文件的狀態不同,此命令的效果也不同:可以用它開始跟蹤 新文件
,或者把 已跟蹤的文件放到暫存區
,還能用於合並時把 有沖突的文件標記為已解決狀態等)。現在讓我們運行 git add 將 benchmarks.rb 放到暫存區,然後再看看 git status 的輸出:
$ git add benchmarks.rb
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# new file: README
# modified: benchmarks.rb #
現在兩個文件都已暫存,下次提交時就會一並記錄到倉庫。假設此時,你想要在 benchmarks.rb 裏再加條註釋,重新編輯存盤後,準備好提交。不過且慢,再運行 git status 看看:
$ vim benchmarks.rb
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
# # new file: README
# modified: benchmarks.rb
# # Changed but not updated:
# (use "git add <file>..." to update what will be committed)
# # modified:
benchmarks.rb #
怎麽回事?benchmarks.rb 文件出現了兩次!一次算未暫存,一次算已暫存,這怎麽可能呢?好吧,實際上 Git 只不過暫存了你運行 git add 命令時的版本,如果現在提交,那麽提交的是添加註釋前的版本,而非當前工作目錄中的版本。所以,運行了 git add 之後又作了修訂的文件,需要重新運行 git add 把最新版本重新暫存起來:
$ git add benchmarks.rb
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# new file: README
# modified: benchmarks.rb
#
忽略某些文件
一般我們總會有些文件無需納入 Git 的管理,也不希望它們總出現在未跟蹤文件列表。通常都是些自動生成的文件,比如日誌文件,或者編譯過程中創建的臨時文件等。我們可以在當前工程下創建一個名為 .gitignore
的文件,列出要忽略的文件模式。來看一個實際的例子:
$ cat .gitignore
*.[oa]
*~
第一行告訴 Git 忽略所有以 .o 或 .a 結尾的文件。一般這類對象文件和存檔文件都是編譯過程中出現的,我們用不著跟蹤它們的版本。第二行告訴 Git 忽略所有以波浪符(~)結尾的文件,許多文本編輯軟件(比如 Emacs)都用這樣的文件名保存副本。此外,你可能還需要忽略 log,tmp 或者 pid 目錄,以及自動生成的文檔等等。要養成一開始就設置好 .gitignore 文件的習慣,以免將來誤提交這類無用的文件。
文件 .gitignore 的格式規範如下:
所有`空行`或者以`註釋符號 # 開頭的行`都會被 Git 忽略。
可以使用標準的 glob 模式匹配。
* 匹配模式最後跟反斜杠(/)說明要忽略的是目錄。
* 要忽略指定模式以外的文件或目錄,可以在模式前加上驚嘆號(!)取反。
所謂的 glob 模式是指 shell 所使用的簡化了的正則表達式。
星號(*)匹配零個或多個任意字符;
[abc] 匹配任何一個列在方括號中的字符(這個例子要麽匹配一個 a,要麽匹配一個 b,要麽匹配一個 c);
問號(?)只匹配一個任意字符;
如果在方括號中使用短劃線分隔兩個字符,表示所有在這兩個字符範圍內的都可以匹配(比如 [0-9] 表示匹配所有 0 到 9 的數字)。
我們再看一個 .gitignore 文件的例子:
# 此為註釋 – 將被 Git 忽略
*.a # 忽略所有 .a 結尾的文件
!lib.a # 但 lib.a 除外
/TODO # 僅僅忽略項目根目錄下的 TODO 文件,不包括 subdir/TODO
build/ # 忽略 build/ 目錄下的所有文件
doc/*.txt # 會忽略 doc/notes.txt 但不包括 doc/server/arch.txt
git 使用詳解(3)—— 最基本命令 + .gitignore 文件