# 用 diff 來檢查改動
項目的開發是由無數個微小的改動組成的。了解項目開發過程的關鍵就是要搞清楚每一個改動。
當然你可以使用 “git status” 命令或更簡單的 “git log” 命令來打印出項目的狀態和歷史記錄,但是這些命令僅僅只能為你提供一個非常簡單的信息概要,想要顯示一個詳細的修改信息就必須使用另外一個命令。
## 讀懂 Diffs
在版本控制系統中用來顯示兩個版本之間差別的操作我們稱之為 “diff”,或者 “patch”。現在就讓我們來詳細地學習一下這個操作吧!首先要學習如何讀懂 diff 信息。

### 比較文件 a/b
這個 diff 操作會對兩個對象進行相互比較。比如對象 A 和對象 B 。在大多數情況下 A 和 B 會是項目中的同一個文件,但它們是基于不同的版本。當然 diff 操作也可以比較兩個完全沒有關聯的文件,并顯示出它們之間的差別,但是這種操作并不會被經常使用到。
為了清楚地顯示比較信息, diff 操作總是會把要比較的文件定義成 “A” 和 “B”。
### 文件的元數據 (Metadata)
這所說的文件元數據是非常技術性的,在實踐中你可能永遠不需要搞明白它。最開始的兩串數字表示兩個文件的 hashes(簡單點說就是它們的 “ID”)。不僅僅是整個項目,Git 還會把每一個文件當作對象來保存。這個 hash ID 就代表了一個文件對象的特定版本。最后的一串數字代表了一個文件的模式(100644 代表它是一個普通的文件,100755 表示一個可執行文件,120000 僅僅是一符號鏈接)。
### 標記 a/b
繼續向下觀察這些輸出信息,A 與 B 的真正差別會被顯示在這里。為了區分它們,A 和 B 都被賦予了它們特有的符號:對于版本 A,它的符號是一個減號(“-”);而對于版本 B ,它會使用一個加號(“+”)。
### 區塊(Chunk)
diff 操作不會顯示完整的文件內容。如果兩個版本僅僅存在兩行代碼的差別,你也不會想要去逐行地審視這個擁有上萬行代碼的文件吧。因此,Git 在這里只會標記出那些實際上修改的部分,在這里一段連續的改動被稱之為區塊(chunk 或者 hunk)。除了包括實際更改的代碼行,一個區塊還包括一個特定的 “上下文環境”,例如那些改變之前和之后的差別,能讓你更容易地明白在特定的上下文環境中這個改變的具體含義。
### 區塊標頭(Chunk Header)
每個這樣的區塊都有一個標頭,它被顯示在兩個 “@@” 符號中。在這里 Git 會告訴你哪些行存在差異。在我們的例子里這些行被標記成為第一個改動區塊:
* 來自文件 A (標記為 “-”),從第34行開始之后的6行代碼。
* 來自文件 B (標記為 “+”),從第34行開始之后的8行代碼。
在那個 “@@” 結束符號之后的信息是用來表明上下文環境的,例如 Git 會嘗試著為這個區塊賦予一個方法名稱或是其他的上下文信息。然而 Git 不能支持所有的文件內容,這很大程度上都要取決于項目所使用的開發語言。
### 改動
在每一個被改動過的代碼行之前都會前置一個 “+” 或是 “-” 符號。就像前面所講到的,這些符號可以幫助你準確了解版本 A 和 版本 B 。例如前置了 “-” 符號的行就代表來自版本 A,反之帶有符號 “+” 的行就代表來自于版本 B。
大多數情況下,在 Git 中都使用 A 和 B 這樣的方式,你可以認為 A/- 代表老的內容,而 B/+ 代表新的內容。
現在就讓我們來看一下我們的例子:
* 改動 #1 包括兩行 “+” ,而在相對應的版本 A 中卻不存在這些行(沒有任何被前置 “-” 的行),這就表示這兩行是新被添加的。
* 改動 #2 則恰恰相反。在版本 A 中,可以看到有兩行被前置上了符號 “-”。然而版本 B 卻不存在對應的行(沒有 “+” 行),這就表明這兩行被刪除了。
* 在改動 #3 中,這些代碼行發生了一些改動,前置上符號 “-” 的兩行被修改了,新的改動就是在它的下面被標記了符號 “+” 的內容。
現在我們知道了如何讀懂 diff 的輸出信息了,來做一些練習吧!
## 檢查本地改動
在之前的章節里,我們經常會使用 “git status” 命令來查看在本地副本(working copy)中有哪些文件被改動了。如果要想清楚地了解這些改動的細節,我們就必須使用 “ git diff” 命令:
```
$ git diff
diff --git a/about.html b/about.html
index d09ab79..0c20c33 100644
--- a/about.html
+++ b/about.html
@@ -19,7 +19,7 @@
</div>
<div id="headerContainer">
- <h1>About</h1>
+ <h1>About This Project</h1>
</div>
<div id="contentContainer">
diff --git a/imprint.html b/imprint.html
index 1932d95..d34d56a 100644
--- a/imprint.html
+++ b/imprint.html
@@ -19,7 +19,7 @@
</div>
<div id="headerContainer">
- <h1>Imprint</h1>
+ <h1>Imprint / Disclaimer</h1>
</div>
<div id="contentContainer">
```
在不帶任何參數的情況下,“git diff” 會為我們給所有在本地副本中還未被打包(unstaged)的變化做個比較,并顯示出來。
如果你僅僅是想要查看那些對于已被打包的改動的比較結果,你可以選擇使用 “git diff --staged” 命令。
## 檢查已提交的改動
你已經學習過了 “git log” 命令,它會打印出那些最新提交的概要。但是它僅僅顯示一些最基礎的信息(hash,作者,時間,注釋)。如果你想要查看那些改動的細節,你就可以加上 “-p” 參數來得到一個更詳細的修改信息。
## 比較分支和版本
最后,你可能想要知道如何比較兩個分支,或是兩個特定項目版本。來讓我們看看在 “contact-form” 分支的哪些改動并不存在于 “master” 上:
```
$ git diff master..contact-form
```
相反,這些比較信息僅僅是在分支層面上的,你也可以比較任意的兩個項目版本之間的內容:
```
$ git diff 0023cdd..fcd6199
```
- Learn Version Control with Git 中文版
- 前言
- Part 1 - 基礎知識
- 什么是版本控制?
- 為什么要使用版本控制系統?
- 準備工作
- 版本控制的基本工作流程
- 從一個未被納入版本控制的項目開始
- 從一個已被納入版本控制的項目開始
- 工作在你的項目上
- Part 2 - 分支與合并
- 分支可以改變你的生命
- 在分支上工作
- 暫時保存更改
- 切換一個本地分支
- 合并改動
- 分支的工作流程
- Part 3 - 遠程倉庫
- 關于遠程倉庫
- 連接一個遠程倉庫
- 查看遠程數據
- 整合遠程的改動
- 發布一個本地分支
- 刪除分支
- Part 4 - 高級應用
- 撤銷操作
- 用 diff 來檢查改動
- 處理合并沖突
- Rebase 代替合并
- 子模塊
- git-flow 的工作流程
- 使用 SSH 公鑰驗證
- Part 5 - 工具與服務
- 桌面應用程序
- 比較和整合工具
- 代碼托管服務
- 更多學習資源
- 附錄
- 版本控制的最佳實踐
- 命令 101
- 從 Subversion 過渡到 Git
- 為什么選擇 Git