记录每次更新到仓库 —— Git 学习笔记 10
記錄每次更新到倉庫
文章目錄
- 文件的狀態
- 三個區域
- 檢查當前文件狀態
- 跟蹤新文件
- 取消跟蹤(un-tracking)文件
- 重新跟蹤(re-tracking)文件
- 暫存已修改文件
- 忽略某些文件
- 查看已暫存和未暫存的修改
- 提交更新
- 跳過暫存區
- 刪除文件
- 移動文件
- 參考資料
咱們接著很多天以前的 取得Git倉庫 這篇文章繼續說。
文件的狀態
不管是通過哪種方法,現在我們已經有了一個倉庫,并從這個倉庫中取出了所有文件的拷貝。接下來,對這些文件作些修改,在完成了一個階段的目標之后,提交本次更新到倉庫。
需要說明的是,工作目錄下面的所有文件都不外乎這兩種狀態:已知(已跟蹤)的和未知的。已跟蹤的文件是指已經被納入版本控制的文件,未知的文件又分為兩種:未跟蹤和和已忽略(這個以后再說)。
已跟蹤的文件可分為以下幾種狀態:
初次克隆某個倉庫時,工作目錄中的所有文件都屬于已跟蹤文件,且狀態為未修改(unmodified)。在編輯過某些文件之后,Git 將這些文件標記為已修改(modified)。然后可以用"git add"命令把這些文件添加到暫存區,這時候它們的狀態就是已暫存(staged);再然后用“git commit”把這些暫存的文件提交到本地倉庫后,它們的狀態又變成了未修改(unmodified)。
三個區域
上面是圍繞著文件狀態變化來說的,也可以圍繞著工作目錄、暫存區、本地版本庫來說明。
Git 系統跟蹤的文件一般有 2 種狀態,未修改(或已提交)和已修改。未修改意味著工作目錄下的文件內容和最近一次提交的修訂內容一致,很安全地存放在版本庫中;如果工作目錄下的文件和最近一次提交的版本存在差異,則被認為是已修改的文件。
不過,在 Git 系統內部,還有一個被稱為索引(index)或暫存區(staging area)的區域,它用來存儲將要提交的信息。git add 命令用來把已修改的文件加入索引,這將導致 Git 為其生成當前版本的快照。此時這個文件的狀態就是已暫存(staged)。
檢查當前文件狀態
要確定哪些文件當前處于什么狀態,可以用 git status 命令。如果在克隆倉庫之后立即執行此命令,會看到類似這樣的輸出:
$ git status On branch master nothing to commit, working directory clean這說明你現在的工作目錄是干凈的。換句話說,所有已跟蹤文件在上次提交后都未被修改過。此外,上面的信息還表明,當前目錄下沒有任何未跟蹤的新文件,否則 Git 會在這里列出來。最后,還顯示了當前所在的分支是 master,這是默認的分支名稱(分支以后再說,這里先不用管)。
現在讓我們創建一個新文件 README,內容是什么無所謂,保存后運行 git status
$ 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)可以看到,新建的 README 文件出現在 “Untracked ?les” 下面。未跟蹤的文件意味著 Git 在之前的快照(或提交)中沒有找到這些文件;Git 不會自動將其納入跟蹤范圍,除非你明明白白地告訴它“我需要跟蹤該文件”。
跟蹤新文件
使用命令 git add 開始跟蹤一個新文件。所以,要跟蹤 README 文件,只需運行:
$ git add README此時再運行 git status 命令,會看到:
$ git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) new file: README只要在"Changes to be committed"這行下面列出的文件,就說明是已暫存狀態。如果此時提交,那么該文件此時此刻的版本將被存入倉庫。在 git add 后面可以指明要跟蹤的文件或目錄。如果是目錄,就說明要遞歸跟蹤該目錄下的所有文件及子目錄。
其實 git add 的潛臺詞就是把目標文件的快照放入暫存區域,同時未曾跟蹤過的文件標記為已跟蹤。
取消跟蹤(un-tracking)文件
假如想忽略某個已經跟蹤的文件,可以用命令
git rm --cached <file>注意,把 <file > 替換成具體的文件名。
舉例:
$ git status --ignored On branch master Changes to be committed:(use "git reset HEAD <file>..." to unstage)modified: world.cUntracked files:(use "git add <file>..." to include in what will be committed)oops可以看到,world.c 是一個已經被跟蹤的文件。
$ git rm --cached world.c rm 'world.c'$ git status --ignored On branch master Changes to be committed:(use "git reset HEAD <file>..." to unstage)deleted: world.cUntracked files:(use "git add <file>..." to include in what will be committed)oopsworld.c $ ls oops world.c當不再跟蹤 world.c 后, 工作區中的 world.c 不受影響。
重新跟蹤(re-tracking)文件
如果想跟蹤一個已經被忽略的文件,可以用
git add -f <file>例如:
$ git add -f world.c $ git status --ignored On branch master Changes to be committed:(use "git reset HEAD <file>..." to unstage)modified: world.cUntracked files:(use "git add <file>..." to include in what will be committed)oops暫存已修改文件
我們修改一個已跟蹤的文件(我這里是 world.c),再運行 git status
$ echo "hello world" >>world.c$ git status On branch master Changes not staged for commit:(use "git add <file>..." to update what will be committed)(use "git checkout -- <file>..." to discard changes in working directory)modified: world.cno changes added to commit (use "git add" and/or "git commit -a")文件 world.c 出現在“Changes not staged for commit”下面,說明已跟蹤文件的內容發生了變化,但還沒有放到暫存區。現在讓我們運行 git add 將 world.c 放到暫存區,然后再看看 git status 的輸出。
注意: git add 命令是個多功能命令,根據目標文件的狀態不同,此命令的效果也不同:可以用它開始跟蹤新文件,或者把已跟蹤的文件放到暫存區,還能用于合并時把有沖突的文件標記為已解決狀態(這個以后再說)等。
$ git status On branch master Changes to be committed:(use "git reset HEAD <file>..." to unstage)modified: world.c現在 world.c 已暫存,下次提交時其快照就會永久儲存在倉庫。假設此時,你突然想起來world.c還需要再改一下,比如加一行注釋。重新編輯保存后,準備提交。不過且慢,在提交之前再運行一遍 git status 看看。
$ echo "//this is comment" >>world.c$ git status On branch master Changes to be committed:(use "git reset HEAD <file>..." to unstage)modified: world.cChanges not staged for commit:(use "git add <file>..." to update what will be committed)(use "git checkout -- <file>..." to discard changes in working directory)modified: world.c怎么回事?world.c 文件出現了兩次!一次已暫存,一次未暫存,是不是 Git 搞錯了?
實際上 Git 只不過暫存了你運行 git add 命令時的版本,如果現在提交,那么提交的是添加注釋前的版本,而非當前工作目錄中的版本。所以,運行了 git add 之后又作了修訂的文件,需要重新運行 git add 把最新版本暫存起來:
$ git status On branch master Changes to be committed:(use "git reset HEAD <file>..." to unstage)modified: world.c忽略某些文件
對于某些文件,我們不希望把它們納入 Git 的管理,也不希望它們總出現在未跟蹤文件列表。通常它們都是些自動生成的文件,比如日志文件、編譯過程中創建的臨時文件等。我們可以創建一個名為 .gitignore 的文件,在里面列出要忽略的文件模式。來看一個實際的例子:
$ cat .gitignore *.[oa] *~*.[oa]告訴 Git 忽略所有以 .o 或 .a 結尾的文件。*~告訴 Git 忽略所有以波浪符(~)結尾的文件,許多文本編輯軟件(比如 Emacs)都用這樣的文件名保存副本。
文件 .gitignore 的格式規范如下:
? 所有空行或者以 # 開頭的行都會被 Git 忽略。
? 可以使用標準的 glob 模式匹配。
? 匹配模式可以以(/)開頭防止遞歸。
? 匹配模式可以以(/)結尾指定目錄。
? 要忽略指定模式以外的文件或目錄,可以在模式前加上驚嘆號(!)取反。
所謂的 glob 模式是指 shell 所使用的簡化了的正則表達式。
我們再看一個 .gitignore 文件的例子:
# 忽略.a文件 *.a # 但是跟蹤 lib.a !lib.a # 忽略當前目錄下的 TODO,但是不忽略子目錄下的 TODO /TODO # 忽略 build 目錄下的所有文件 build/ # 例如忽略 doc/notes.txt, 但是不忽略 doc/server/arch.txt doc/*.txt # 忽略 doc 目錄下的所有 .pdf doc/**/*.pdf注意:Git 允許在版本庫中任何目錄下有.gitignore文件。每個 .gitignore 文件都只影響該目錄及其所有子目錄。
由于本文是針對初學者的,所以說得略簡單。如果你想了解關于 Git 忽略文件的更多內容,可以參考我的博文: 忽略某些文件
查看已暫存和未暫存的修改
如果 git status 命令的輸出對于你來說過于籠統,你想知道具體修改了什么地方,可以用 git diff 命令。git diff 命令可以幫我們回答兩個問題:
盡管 git status 已經通過在相應欄下列出文件名的方式回答了這2個問題,但是 git diff 將通過文件補丁的格式(合并格式)顯示修改了哪些行。
比如我的工作目錄下有一個 README.md 文件,里面已經有一些內容了,它的狀態是未修改。現在修改它,但是不暫存。
$ echo 1234 >> README.md運行 git diff 命令
$ git diff diff --git a/README.md b/README.md index 26573a9..78ea874 100644 --- a/README.md +++ b/README.md @@ -1 +1,2 @@my_repo +1234可以清楚看到,增加了一行“1234”。要了解合并格式的 diff,可以參考我的博文 diff命令輸出格式解讀
如果運行
$ git add README.md也就是把修改提交到暫存區,這時候再次運行 git diff
$ git diff什么輸出都沒有,也就說明工作區的更新都已經暫存了。若要查看已暫存的更新,可以用 git diff --cached 命令。(Git 1.6.1 及更高版本還允許使用 git diff --staged,效果是相同的。)
$ git diff --cached diff --git a/README.md b/README.md index 26573a9..78ea874 100644 --- a/README.md +++ b/README.md @@ -1 +1,2 @@my_repo +1234$ git diff --staged diff --git a/README.md b/README.md index 26573a9..78ea874 100644 --- a/README.md +++ b/README.md @@ -1 +1,2 @@my_repo +1234你也許會問,能不能比較當前工作目錄和最近一次提交之間的差異。當然可以,用命令git diff HEAD,這里就不舉例了。
下圖列出了這三個命令的區別。
提交更新
現在的暫存區已經準備妥當可以提交了。 在此之前,請一定要確認還有什么修改過的或新建的文件還沒有 git add 過,否則提交的時候不會記錄這些還沒暫存起來的變化。 這些修改過的文件只保留在本地磁盤。所以,每次準備提交前,先用 git status 查看下,是不是都已暫存起來了,然后再運行提交命令 git commit。
$ git commit這種方式會啟動文本編輯器以便輸入本次提交的說明。默認會啟用 shell 的環境變量 $EDITOR 所指定的軟件,一般都是 vim 或 emacs。當然也可以使用 git config --global core.editor 命令設定你喜歡的編輯器。比如
$ git config --global core.editor "emacs"我是Windows操作系統,用命令 git config --list查了一下,我的配置是
core.editor='d:\PF\Notepad++\notepad++.exe' -multiInst -notabbar -nosession -noPlugin可見,我用的軟件是 notepad++.
當我運行 git commit命令后,編輯器會顯示類似下面的文本信息:
可以看到,默認的提交消息包含最后一次運行 git status 的輸出,放在注釋行里,另外開頭還有一空行,供我們輸入提交說明。退出編輯器時,Git 會丟掉注釋行,用輸入的信息生成一次提交。
另外,也可以在 git commit 命令后添加 -m 選項,將提交信息與命令放在同一行,如下所示:
$ git commit -m "initialize" [master 0b6ab8c] initialize1 file changed, 1 deletion(-)delete mode 100644 hello.c可以看到,Git 會告訴我們,當前是在哪個分支(master)提交的,本次提交的 SHA-1 校驗和是什么(0b6ab8c),以及在本次提交中,有多少文件修訂過,多少行添加和刪改過。
請記住,提交時寫入倉庫的是放在暫存區的快照。任何還未暫存的修改仍然在磁盤上,可以在以后暫存并提交。
每一次進行提交操作,都是對項目作一次快照,以后可以退回到這個狀態,或者把某兩個提交進行比較。
跳過暫存區
盡管使用暫存區可以精心準備每一次提交,但有時候顯得麻煩。 Git 提供了一個跳過使用暫存區的方式, 只要在提交的時候,給 git commit 加上 -a 選項,Git 就會自動把所有已經跟蹤過的文件暫存起來一并提交,從而跳過 git add 步驟:
例如,我修改了一個文件 change_log.md,但是沒有暫存
$ git status On branch master Changes not staged for commit:(use "git add <file>..." to update what will be committed)(use "git checkout -- <file>..." to discard changes in working directory)modified: change_log.mdno changes added to commit (use "git add" and/or "git commit -a")我直接提交:
$ git commit -a -m "commit change log skip the index" [master 32ee0ac] commit change log skip the index1 file changed, 1 insertion(+)提交成功了。
注意,這種方法僅對已經跟蹤的文件有效,如果是 untracked 的文件,是無法提交的。比如
$ touch change_log.md $ git status On branch master Untracked files:(use "git add <file>..." to include in what will be committed)change_log.mdnothing added to commit but untracked files present (use "git add" to track)這時候,我試著提交:
$ git commit -a -m "add change log" On branch master Untracked files:change_log.mdnothing added to commit but untracked files present你瞧,提交失敗了,Git 說沒有東西可提交。
刪除文件
在 Git中,刪除也是一個修改操作。我們先添加一個新文件test.txt到Git并且提交:
$ touch test.txt $ git add test.txt $ git commit -m "add test.txt" [master 92c6e9d] add test.txt1 file changed, 1 insertion(+)create mode 100644 test.txt一般情況下,我們會用rm命令刪除:
$ rm test.txt這個時候,Git 知道你刪除了該文件。因此,工作區和版本庫就不一致了,用git status命令查看一下:
$ git status On branch master Changes not staged for commit:(use "git add/rm <file>..." to update what will be committed)(use "git checkout -- <file>..." to discard changes in working directory)deleted: test.txtno changes added to commit (use "git add" and/or "git commit -a")現在你有兩個選擇:
對于1,用命令git rm刪掉,并且git commit:
$ git rm test.txt rm 'test.txt'$ git commit -m "rm test.txt" [master 6c0b39a] rm test.txt1 file changed, 0 insertions(+), 0 deletions(-)delete mode 100644 test.txt現在,文件就從版本庫中被刪除了。
對于2,可以用git checkout -- <file>把文件從版本庫里找回來。例如:
$ git checkout -- test.txt這里的git checkout其實是用版本庫里的版本來更新索引,同時覆蓋工作目錄中對應的文件,無論工作區的文件是被修改還是被刪除,都可以“一鍵還原”。
其實,如果確實要從版本庫刪除某個文件,只需要2個步驟。
git rm <file> git commitgit rm表示從工作區刪除文件,并且把這個變更暫存(就像 git add 一樣);git commit表示在版本庫實現這個變更。
需要說明的是,如果文件修改了,且修改未提交,刪除就會失敗。例如:
$ echo 11 >>oops $ git status On branch master Changes not staged for commit:(use "git add <file>..." to update what will be committed)(use "git checkout -- <file>..." to discard changes in working directory)modified: oopsno changes added to commit (use "git add" and/or "git commit -a")$ git rm oops error: the following file has local modifications:oops (use --cached to keep the file, or -f to force removal) # 以上是未暫存的情況$ git add oops$ git rm oops error: the following file has changes staged in the index:oops (use --cached to keep the file, or -f to force removal) # 以上是暫存了但是未提交的情況這時候需要加 -f 強行刪除。
$ git rm oops -f rm 'oops'$ git status On branch master Changes to be committed:(use "git reset HEAD <file>..." to unstage)deleted: oops$ ls移動文件
在 Git 中可以執行下面的命令重命名文件:
git mv <old_file> <new_file>例如:
$ git mv banana.c grape.c$ git status On branch master Changes to be committed:(use "git reset HEAD <file>..." to unstage)renamed: banana.c -> grape.c$ git commit -m xx [master 0c89153] xx1 file changed, 0 insertions(+), 0 deletions(-)rename banana.c => grape.c (100%)參考資料
【1】《精通Git(第2版)》,Scott Chacon & Ben Straub,人民郵電出版社
【2】 https://www.liaoxuefeng.com/
總結
以上是生活随笔為你收集整理的记录每次更新到仓库 —— Git 学习笔记 10的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 写一函数,输入一个四位数字,要求输出这四
- 下一篇: 状态机设计模式_设计模式-代理/状态机模