1. 程式人生 > >git 使用詳解(4)—— commit -a -m/diff --staged/rm/mv

git 使用詳解(4)—— commit -a -m/diff --staged/rm/mv

art client -s 做的 res use 擴展名 ems 也會

查看已暫存和未暫存的更新

實際上 git status的顯示比較簡單,僅僅是 列出了(修改過的、新創建的、已經暫存但未提交的)文件,如果要查看具體修改了什麽地方,可以用git diff 命令。稍後我們會詳細介紹 git diff,不過現在,它已經能回答我們的兩個問題了:當前做的哪些更新還沒有暫存?有哪些更新已經暫存起來準備好了下次提交?git diff 會使用文件補丁的格式顯示具體添加和刪除的行。

假如再次修改 README 文件後暫存,然後編輯 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
#

要查看 尚未暫存 的文件更新了哪些部分,不加參數 直接輸入git diff

$ git diff
diff --git a/benchmarks.rb b/benchmarks.rb
index 3cb747f..da65585 100644
--- a/benchmarks.rb
+++ b/benchmarks.rb
@@ -36,6 +36,10 @@ def main
           @commit.parents[0].parents[0].parents[0]
         end

+        run_code(x, ‘commits 1‘) do
+          git.commits.size
+        end
+
         run_code(x, ‘commits 2‘) do
           log = git.commits(‘master‘, 15)
           log.size

此命令比較的是 工作目錄中 當前文件暫存區域快照 之間的差異,也就是修改之後還沒有暫存起來的變化內容。

若要看 已經暫存起來 的文件上次提交時的快照 之間的差異,可以用 git diff --cached 命令。(Git 1.6.1 及更高版本還允許使用git diff --staged,效果是相同的,但更好記些。)來看看實際的效果:

$ git diff --cached
diff --git a/README b/README
new file mode 100644
index 0000000..03902a1
--- /dev/null
+++ b/README2
@@ -0,0 +1,5 @@
+grit
+ by Tom Preston-Werner, Chris Wanstrath
+ http://github.com/mojombo/grit
+
+Grit is a Ruby library for extracting information from a Git repository

請註意,單單 git diff 不過是顯示還沒有暫存起來的改動,而不是這次工作和上次提交之間的差異。所以有時候你一下子暫存了所有更新過的文件後,運行git diff 後卻什麽也沒有,就是這個原因。

像之前說的,暫存 benchmarks.rb 後再編輯,運行 git status 會看到暫存前後的兩個版本:

$ git add benchmarks.rb
$ echo ‘# test line‘ >> benchmarks.rb
$ git status
# On branch master
#
# Changes to be committed:
#
#   modified:   benchmarks.rb
#
# Changed but not updated:
#
#   modified:   benchmarks.rb
#

現在運行 git diff 看暫存前後的變化:

$ git diff
diff --git a/benchmarks.rb b/benchmarks.rb
index e445e28..86b2f7c 100644
--- a/benchmarks.rb
+++ b/benchmarks.rb
@@ -127,3 +127,4 @@ end
 main()

 ##pp Grit::GitRuby.cache_client.stats
+# test line

然後用 git diff --cached 查看已經暫存起來的變化:

$ git diff --cached
diff --git a/benchmarks.rb b/benchmarks.rb
index 3cb747f..e445e28 100644
--- a/benchmarks.rb
+++ b/benchmarks.rb
@@ -36,6 +36,10 @@ def main
          @commit.parents[0].parents[0].parents[0]
        end

+        run_code(x, ‘commits 1‘) do
+          git.commits.size
+        end
+
        run_code(x, ‘commits 2‘) do
          log = git.commits(‘master‘, 15)
          log.size

提交更新

現在的暫存區域已經準備妥當可以提交了。在此之前,請一定要確認還有什麽修改過的或新建的文件還沒有 git add 過,否則提交的時候不會記錄這些還沒暫存起來的變化。所以,每次準備提交前,先用git status 看下,是不是都已暫存起來了,然後再運行提交命令 git commit:

$ git commit
這種方式會啟動文本編輯器以便輸入本次提交的說明。(默認會啟用 shell 的環境變量 $EDITOR 所指定的軟件,一般都是 vim 或 emacs。當然也可以按照第一章介紹的方式,使用git config --global core.editor 命令設定你喜歡的編輯軟件。)

編輯器會顯示類似下面的文本信息(本例選用 Vim 的屏顯方式展示):

# Please enter the commit message for your changes. Lines starting
# with ‘#‘ will be ignored, and an empty message aborts the commit.
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       new file:   README
#       modified:   benchmarks.rb
~
~
~
".git/COMMIT_EDITMSG" 10L, 283C

可以看到,默認的提交消息包含最後一次運行 git status 的輸出,放在註釋行裏,另外開頭還有一空行,供你輸入提交說明。你完全可以去掉這些註釋行,不過留著也沒關系,多少能幫你回想起這次更新的內容有哪些。(如果覺得這還不夠,可以用-v 選項將修改差異的每一行都包含到註釋中來。)退出編輯器時,Git 會丟掉註釋行,將說明內容和本次更新提交到倉庫。

另外也可以用 -m 參數後跟提交說明的方式,在一行命令中提交更新:

$ git commit -m "Story 182: Fix benchmarks for speed"
[master]: created 463dc4f: "Fix benchmarks for speed"
 2 files changed, 3 insertions(+), 0 deletions(-)
 create mode 100644 README

好,現在你已經創建了第一個提交!可以看到,提交後它會告訴你,

  1. 當前是在哪個分支(master)提交的,
  2. 本次提交的完整 SHA-1 校驗和是什麽(463dc4f),
  3. 以及在本次提交中,有多少文件修訂過,多少行添改和刪改過。

記住,提交時記錄的是放在暫存區域的快照,任何還未暫存的仍然保持已修改狀態,可以在下次提交時納入版本管理。每一次運行提交操作,都是對你項目作一次快照,以後可以回到這個狀態,或者進行比較。

跳過使用暫存區域

盡管使用暫存區域的方式可以精心準備要提交的細節,但有時候這麽做略顯繁瑣。Git 提供了一個跳過使用暫存區域的方式,只要在提交的時候,給 git commit 加上 -a 選項,Git 就會自動把所有已經跟蹤過的文件暫存起來一並提交,從而跳過git add 步驟:

  $ git status
  # On branch master
  #
  # Changed but not updated:
  #
  # modified:   benchmarks.rb
  #
  $ git commit -a -m ‘added new benchmarks‘
  [master 83e38c7] added new benchmarks
   1 files changed, 5 insertions(+), 0 deletions(-)

看到了嗎?提交之前不再需要 git add 文件 benchmarks.rb 了。

移除文件

要從 Git 中移除某個文件,就必須要從已跟蹤文件清單中移除(確切地說,是從暫存區域移除),然後提交。可以用git rm命令完成此項工作,並同時從工作目錄中刪除指定的文件,這樣以後就不會出現在未跟蹤文件清單中了。

如果只是簡單地從工作目錄中手工刪除文件,運行 git status 時就會在 “Changed but not updated” 部分(也就是_未暫存_清單)看到:

$ rm grit.gemspec
$ git status
# On branch master
#
# Changed but not updated:
#   (use "git add/rm <file>..." to update what will be committed)
#
#       deleted:    grit.gemspec
#

然後再運行 git rm 記錄此次移除文件的操作:

$ git rm grit.gemspec
rm ‘grit.gemspec‘
$ git status
# On branch master
#
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       deleted:    grit.gemspec
#

最後提交的時候,該文件就不再納入版本管理了。如果刪除之前修改過並且已經放到暫存區域的話,則必須要用強制刪除選項 -f(譯註:即 force 的首字母),以防誤刪除文件後丟失修改的內容。

另外一種情況是,我們想把文件從 Git 倉庫中刪除(亦即從暫存區域移除),但仍然希望保留在當前工作目錄中。換句話說,僅是從跟蹤清單中刪除。比如一些大型日誌文件或者一堆.a 編譯文件,不小心納入倉庫後,要移除跟蹤但不刪除文件,以便稍後在 .gitignore 文件中補上,用--cached 選項即可:

$ git rm --cached readme.txt

後面可以列出文件或者目錄的名字,也可以使用 glob 模式。比方說:

$ git rm log/*.log
註意到星號 * 之前的反斜杠 \,因為 Git 有它自己的文件模式擴展匹配方式,所以我們不用 shell 來幫忙展開(譯註:實際上不加反斜杠也可以運行,只不過按照 shell 擴展的話,僅僅刪除指定目錄下的文件而不會遞歸匹配。上面的例子本來就指定了目錄,所以效果等同,但下面的例子就會用遞歸方式匹配,所以必須加反斜杠。)。此命令刪除所有log/ 目錄下擴展名為 .log 的文件。類似的比如:

$ git rm \*~

會遞歸刪除當前目錄及其子目錄中所有 ~ 結尾的文件。

移動文件

不像其他的 VCS 系統,Git 並不跟蹤文件移動操作。如果在 Git 中重命名了某個文件,倉庫中存儲的元數據並不會體現出這是一次改名操作。不過 Git 非常聰明,它會推斷出究竟發生了什麽,至於具體是如何做到的,我們稍後再談。

既然如此,當你看到 Git 的 mv 命令時一定會困惑不已。要在 Git 中對文件改名,可以這麽做:

$ git mv file_from file_to

它會恰如預期般正常工作。實際上,即便此時查看狀態信息,也會明白無誤地看到關於重命名操作的說明:

$ git mv README.txt README
$ git status
# On branch master
# Your branch is ahead of ‘origin/master‘ by 1 commit.
#
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       renamed:    README.txt -> README
#

其實,運行 git mv 就相當於運行了下面三條命令:

$ mv README.txt README
$ git rm README.txt
$ git add README

如此分開操作,Git 也會意識到這是一次改名,所以不管何種方式都一樣。當然,直接用 git mv 輕便得多,不過有時候用其他工具批處理改名的話,要記得在提交前刪除老的文件名,再添加新的文件名。

git 使用詳解(4)—— commit -a -m/diff --staged/rm/mv