最近開始學習使用版本控制工具 git .學習方式主要通過閱讀 git 網站上的 Pro git 和動手實踐,使用的系統為 Ubuntu16.04LTS,以及 Windows 8.1. 本文主要關注 git 進行本地文件追蹤的文件狀態變化、如何進行文件的修改和提交等關於本地文件操作的部分,即使用 git 進行本地倉庫管理和使用的操作和方法。
注:本文主要記錄作者閱讀 Pro git 的前兩節的筆記。部分內容為對應內容的直接翻譯。
內容目錄
3.1 git status
3.2 git add
3.3 git commit
3.4 git rm
3.5 git log
3.6 git diff
4.git 設置
git 的三種工作域
git 目錄:git directory,是 git 存放數據和信息的地方,亦即倉庫( repository ),保存項目所有版本和相關信息的位置。用戶在進行克隆( clone )操作是就是對 git 目錄(倉庫)的操作;
工作目錄:working directory,是對應項目的某個版本的文件集合,對應從 git 目錄中解壓出來的供用戶進行操作和修改的數據和信息;
暫存區域 :staging area,為記錄下一次提交時需要保存的文件列表信息的文件;
git 管理的文件的三種狀態
git 管理的文件存在以下三種文件狀態:
committed:已提交狀態,表示數據文件已經被保存至本地數據倉庫中。
modified:修改狀態,表示文件已被修改,但是尚未被提交(保存)。
staged:暫存狀態,表示是被標記了的被修改文件,在下次提交時會將所有標記過的修改保存。
對應上述的三種文件狀態可知,若文件已經存在於 git 目錄(倉庫)中,則文件為已提交狀態。若文件已被修改並記錄至暫存區域,則文件處於暫存狀態,用戶提交時會提交處於此狀態的修改。若文件僅僅只是被修改但未被標記為 staged,則為修改狀態,且在下次提交時並不會保存其相關信息( 必須先進入暫存狀態提交時才會保存 )。
文件的狀態變化
在工作目錄( working directory )中,存在兩種狀態的文件,tracked 和 untracked。tracked 文件是那些存在於上一次提交中的文件,即已經在 git 存在過記錄的文件,這些文件可能又被修改過,也可能和上次提交時狀態一致;Untracked文件則是工作目錄下其他所有的文件,如上次提交后在目錄中新建的文件等 。當第一次將倉庫克隆至目錄時,該目錄所有文件均為 tracked 且均為未被修改的文件。
當前工作目錄中可能存在的文件的狀態變化圖( 來自 git pro ):
可以通過命令 git status 來獲取當前目錄下文件的狀態,其顯示的結果主要通過以下幾種標志狀態描述:
Untracked files: 標志處於 untracked 狀態的文件,git 不會主動將 Untracked 狀態的文件轉換為 staged 狀態,需要用戶通過 git add 命令顯示的轉化,避免提交不希望上傳的文件;
Changes to be committed : 標志處於 staged 狀態的文件,當進行提交時,上述文件的提交會被記錄;
Changes not staged for commit: 標志那些被修改但並不處於 staged 狀態的 tracked 文件,需要使用 git add 命令將其轉換為 staged 狀態;
一般情況下,使用命令 git add filename 將 filename 指定的文件或目錄加入staged狀態(從被修改的 tracked 文件或從 Untracked 文件),使用命令 git reset HEAD filename 可以將 filename 文件從 staged 狀態中恢復至一般修改狀態,使用命令 git commit 進行提交操作。
注意:提交的文件是處於 Changes to be committed 狀態的文件,提交的內容為使用 git add 命令加入 staged 狀態時的文件修改內容。即在使用 git add 命令后對相同文件的二次修改不會被提交,除非再次使用 git add 將修改后的文件加入 staged 狀態。體現在 git status 命令中,若使用命令 git add a.c 之后再次對 a.c 文件進行了修改,則上述文件會同時出現在 Changes to be committed 和 Changes not staged for commit 描述中( 即存在同名條目 ),但具體的文件內容是不同的,而提交時只會提交處於 Changes to be committed 狀態的條目,即之后的修改不會被提交。用戶可通過 git status -s/--short 得到各文件狀態的簡要描述,參見這里。
獲取 git 目錄(倉庫)
獲取一個 git 倉庫的方式主要有兩種:
(1)將一個新的本地目錄轉化為 git 倉庫。進入該目錄,輸入命令 git init ,git 會在當前目錄下建立一個.git 目錄,其中包含了所有必須的倉庫的信息。該命令只是完成初始化過程,並沒有產生提交,故而該倉庫可以視為空。
(2)從其他地方克隆(clone)一個 git 倉庫。使用命令 git clone 會將目標倉庫的所有服務器上存放的文件( 包括各個版本和修改歷史 )克隆至本地,同樣存放在 .git 目錄中,這一點與其他版本控制軟件的 checkout (只獲取特定需要的版本的項目)命令不同。
git clone <url> //獲取url指向的倉庫的內容
當用戶使用 git clone https://github.com/project_name/project_name 命令獲取一個 git 倉庫時,git 會執行以下過程
a.在本地建立一個project_name目錄,並在其中初始化一個.git目錄;
b.獲取將該倉庫的所有文件,並將最近版本的工作文件解壓放置至創建的 project_name 文件夾中供用戶操作。
用戶可在該指令后面加上目的文件夾名作為參數,如git clone https://github.com/xxx/xxx dir_name,則 git 會將該倉庫文件放置至 dir_name 目錄下。除了上述的 https 協議外,git 還支持 git:// 和 ssh 協議,具體可以查看官方文檔。
注意:無論是使用 Linux 環境下的命令行還是通過 Windows 環境下的 Git bash,git 命令一般需要在 git 倉庫目錄中發揮作用,否則會出現報錯 "fatal: not a git repository( or any of the parent directories ): .git"。故而當本地不存在 git 倉庫時,可以選擇 git clone 遠端倉庫,或通過 git init 初始化一個本地目錄對應的倉庫,並進入此目錄,進行后續的 git 命令操作。
刪除 git 倉庫
從上面獲取倉庫的原理可以看到, 對 git 倉庫的管理主要通過 .git 目錄實現,刪除 git 倉庫的操作可以通過刪除 .git 目錄操作完成。
(1) 在 Linux 命令行或者 Windows 的 Git bash 環境下,在 git 倉庫目錄中使用命令 ls -a 會顯示當前目錄下所有文件和目錄,此時會顯示存在 .git 目錄;
(2) 通過命令 rm -rf .git/ 刪除當前文件夾下的 .git 目錄;
(3) 此時當前目錄即從一個 git 倉庫變為一個普通目錄,在 Git bash 環境中可以看到路徑名后面不再顯示分支名稱了;
通過 git status 查看當前目錄下各個文件的狀態。git status 還會給出各種狀態下文件可以使用的操作指令。
git status //查看當前文件夾下各個文件的狀態 git status -s //查看各文件狀態,使用字母簡單表示文件狀態
一個 git 倉庫下文件的狀態主要有 (對應上文的介紹看):
Untracked files : 對應並未被 git 追蹤記錄的文件,當通過 git init 初始化一個目錄時,是初始化了一個空的 git 目錄,所有該目錄下的文件均處於未被 git 追蹤記錄的狀態。新建文件的狀態也屬於此類;
changes not staged for commit : 僅限於已經被 git 追蹤記錄( tracked )的文件。若這些文件發生了修改,但還沒有被通過 git add 加入需要進行提交的狀態( staged ),則處於此狀態;
changes to be committed : 僅限於已經被 git 追蹤記錄( tracked )的文件。當這些文件發生了修改,且已經通過 git add 加入需要進行提交的狀態,則處於此狀態。通過 git commit 提交的修改即為處於該狀態的文件的修改;
筆者進行實踐時新建 test 目錄,其中僅包含一個 hello.cpp 文件,在通過 git init 初始化后,即生成一個空的 git repository,git status 的結果如下圖,可以看到此時的 hello.cpp 處於 Untracked 狀態。
通過 git add 添加文件至待提交的狀態( changes to be committed )。git add 主要有兩個功能: a.將未被 git 追蹤記錄( untracked )的文件"加入" git 倉庫的記錄中; b.將處於 changes not staged for commit 狀態下的文件的修改添加至需要進行提交的狀態( staged )。這兩個功能均會將文件變為 changes to be committed 狀態。
git add file-list //將 file-list 指定的文件添加至 changes to be committed 狀態 git add . //將當前目錄下所有的文件添加至 changes to be committed 狀態
用戶可通過 git add 命令將當前目錄下處於 untracked 狀態下的文件"添加"至 git 倉庫中。在筆者的實踐中,即通過 git add hello.cpp 將 hello.cpp 加入 changes to be committed 狀態,也可使用 git add . 命令將當前目錄下所有文件變為 changes to be committed 狀態。
通過指令 git commit 提交所有處於 staged 狀態的文件。注意使用上述命令只會提交使用 git add 命令標記為 staged 狀態的文件。
通過指令 git commit 提交時 Git 會通過默認編輯器顯示一個編輯界面,用戶需編輯提交信息(commit message),用於標識該次提交。其中 # 開始的行表示注釋,用戶編輯結束退出后,Git會使用該提交信息創建新的提交(即生成新的快照)。默認的顯示內容包括最近一次 git status 命令顯示的結果(注釋),使用提交時加入參數 -v 則會將 git diff 指令的結果也包含在顯示內容中,用戶可以通過取消注釋或編輯新內容來修改提交信息( Ubuntu 系統下運行結果 )。
用戶也可以使用 git commit -m "commit message" 命令來直接指定提交信息,可用於提交流程更簡潔的情況。
git commit -m "test" //使用提交信息 "test" 提交所有 staged 的修改 git commit --allow-empty //允許無內容的提交 git commit -am "test" //直接將所有被修改的文件提交,相當於先 git add 再 commit
注意:git commit 保存的數據僅保存在本地倉庫中,若需要同步至遠端倉庫,需要使用 git 支持的遠程倉庫操作。同時,第一次使用 git commit 進行提交時需要設置好用戶的用戶名和郵箱,可以查看后文的 git 設置部分。
在 git 中,刪除一個文件包括取消文件的 tracked 狀態,之后再進行提交,可通過命令 git rm 完成上述操作。更具體描述可以參考這里。
git rm a.c 會將文件a.c 刪除,並將刪除這個"修改"標記為 staged 狀態。當使用 git commit 命令之后,a.c 文件就會從工作目錄中消失,並不再為 tracked 狀態。這樣可以保證不會在之后的操作中將該文件視為 untracked 文件再次進行處理。
注意:常規的刪除操作如 rm,會使得刪除的文件處於 Changes not staged for commit 狀態,而 git rm 的刪除操作使得被刪除文件處於 Changed to be commited 狀態。對於后者,用戶提交之后,被刪除的文件之后不再被 git 記錄,而前者由於並不會被提交,會一直保持該狀態。
對於已經修改並被加入staged狀態的文件來說,通過 git rm 刪除該文件需要使用 -f 參數,以避免刪除 git 尚未記錄的文件和其他誤操作。
使用參數 git rm --cached xxx 可以使得文件不再被 git 記錄,但繼續存在於工作目錄下,作用與 .gitignore 文件類似。
對於本地創建的或自其他倉庫克隆的具有多次提交記錄的項目,可以通過 git log 命令查看歷史的提交記錄。
默認情況, git log 會根據提交順序的逆序排列(即最近的提交最先顯示), git log 會顯示提交順序及其對應的SHA-1哈希值,以及作者、郵箱、提交日期和提交信息等內容。
git log 有一些常用的參數可以用於更精確的顯示需要的內容。
-p //在 log 條目中加入每次提交的修改信息 -n //僅顯示最近的n個提交條目 --stat //顯示每次提交被修改的文件的信息 --pretty=options //options可以為online、short等,也可以自行指定輸出的格式信息,可以參考這里 --graph //輸出字符樹的形式顯示提交記錄
通過指令 git status 可以得知當前各個文件所處的狀態(是否發生改變等),通過指令 git diff可以得知某一文件發生的怎樣的改變。
git diff //查看那些再次修改但尚未被staged的文件修改情況,如 git add a.c 命令之后,再次對 a.c 所做的(而又未被staged)的修改 git diff --stage //查看當前staged狀態下的文件較之原始(未修改狀態下,也就是上一次提交時)的文件的修改情況 git diff commit1 commit2 //比較兩次提交之間的差別
git diff 會將當前工作目錄下的文件與處於staged狀態的文件進行比較,並將差異結果顯示出來。可以視為顯示自上一次 git add 后進行的修改情況。
git diff --stage會將當前處於staged狀態的文件與上一次提交的結果進行比較,並將結果顯示出來。可以視為顯示自上一次 git commit 后進行的修改情況。
注意:指令 git diff 只會顯示還未被staged的修改,即之前已經通過 git add 命令加入staged狀態的修改是不被顯示的。使用參數 --staged或--cached顯示當前已經處於staged狀態的修改,即與上一次提交進行比較的結果。
撤銷與修改操作
(1)針對提交過程:若發現存在部分文件未正確提交(未加入 staged 狀態)或提交信息有疏漏,可以先將需要補充提交的文件加入 staged 狀態,再使用 git commit --amend 命令,則本次提交會取代上一次的提交,在此過程中,也可以修改提交信息;
(2)針對 staged 狀態的文件:使用命令 git reset HEAD filename 可以將 filename 文件從 staged 狀態中恢復至一般修改狀態;
(3)針對已經修改的文件:若想要將已經修改的文件恢復至未修改的狀態,可以使用 git checkout --filename,則會將對應文件從之前的提交記錄中恢復,而簡單的丟棄對其的修改;
事實上,通過 git status 命令獲得當前工作目錄中文件的狀態信息時,針對每種文件狀態會有相應的 git 操作提示。用戶可以直接使用 git status 命令查看特定的文件類型如何進行操作。
其他
(1)跳過 staged area 狀態:在命令 git commit 中加入 -a 參數,git 會直接將所有 tracked 文件提交,而不再需要使用 git add 將其轉換為 staged 狀態。
(2)可創建一個 .gitignore 文件,來設置不需要 Git 進行顯示和提交的文件(處理時直接忽略),最簡單的 .gitignore 文件的寫入就是每個文件/文件夾占一行,所有被包含在其中的內容都被 git 所忽略。具體的寫法可參考這里。
git 通過其攜帶的工具 git config 來對修改配置變量從而對應用進行個性化設置,個性化設置的變量可能會被存儲在三個不同的位置,各自有着不同的作用域( Ubuntu 環境下目錄結構 )。
(1) /etc/gitconfig,全局的 git 變量設置。其中的設置會應用到系統所有用戶和 git 倉庫。通過 git config 的 --system 參數進行設置。
(2) ~/.gitconfig或~/.config/git/config,用戶個人的 git 變量設置,該設置應用於該用戶的所有操作。通過 --global 參數進行設置。
(3) git目錄中的 config 文件(下文的.config目錄中),記錄對該 git 目錄的一些配置變量。
每一層設置的配置變量的值會覆蓋上一層的設置值,故而 git 目錄中的 config 文件中特定設置的效果會掩蓋 /etc/gitconfig 中的對應的設置效果。
設置個人信息
設置個人有關的信息,包括用戶名和 email,在進行提交之前,必須進行用戶名和郵箱名的設置。這是與單個用戶相關的設置,故而使用參數 --global。
git config --global user.name "xxx"
git config --global user.email email_address
設置默認編輯器
git config --global core.editor vim //在 Ubuntu 環境下設置編輯器為 vim
查看設置
可以通過以下命令對 git 的配置參數進行查看
git config --list //查看當前已經設置的所有變量值,會從以上三個文件中讀取,故而特定變量可能出現多次,其最后出現的值為 git 實際使用的值 git config key_name //查看Git當前使用的特定變量的值,如 git config user.name
git 幫助
用戶可以通過命令行方式獲得幫助,包括如下命令,可以通過幫助信息和網絡資源理解 git 相關命令的功能。
git help <action> //如通過 git help config 來過得對config操作的相關幫助 man git-行為名 //如通過 man git-config 來獲得幫助
git command -h //獲得簡略的幫助提示,如 git config -h
參考和學習資源: