== 附錄 A: Git的缺點 ==

有一些Git的問題，我已經藏在毯子下面了。有些可以通過腳本或回調方法輕易地解決，
有些需要重組或重定義項目，少數剩下的煩惱，還只能等待。或者更好地，投入進來幫
忙。

=== SHA1 的弱點 ===

隨着時間的推移，密碼學家發現越來越多的SHA1的弱點。已經發現對對資源雄厚的組織
哈希衝撞是可能的。在幾年內，或許甚至一個一般的PC也將有足夠計算能力悄悄摧毀一
個Git倉庫。

希望在進一步研究摧毀SHA1之前，Git能遷移到一個更好的哈希算法。

=== 微軟 Windows ===

Git在微軟Windows上可能有些繁瑣：

- http://cygwin.com/[Cygwin] ，, 一個Windows下的類Linux的環境，包含一個 http://cygwin.com/packages/git/[ 一個Git在Windows下的移植].

- http://code.google.com/p/msysgit/[基于MSys的Git] 是另一個，要求最小運行時支持，不過一些命令不能馬上工作。
  
=== 不相關的檔案 ===

如果你的項目非常大，包含很多不相關的檔案，而且正在不斷改變，Git可能比其他系統
更不管用，因為獨立的檔案是不被跟蹤的。Git跟蹤整個項目的變更，這通常才是有益的。

一個方案是將你的項目拆成小塊，每個都由相關檔案組成。如果你仍然希望在同一個資
源庫裡保存所有內容的話，可以使用 *git submodule* 。

=== 誰在編輯什麼？ ===

一些版本控制系統在編輯前強迫你顯示地用某個方法標記一個檔案。儘管這種要求很煩
人，尤其是需要和中心伺服器通訊時，不過它還是有以下兩個好處的：

  1. 比較速度快，因為只有被標記的檔案需要檢查。

  2. 可以知道誰在這個檔案上工作，通過查詢在中心伺服器誰把這個檔案標記為編輯狀
     態。

使用適當的腳本，你也可以使Git達到同樣的效果。這要求程序員協同工作，當他編輯一
個檔案的時候還要運行特定的腳本。

=== 檔案歷史 ===

因為Git記錄的是項目範圍的變更，重造單一檔案的變更歷史比其他跟蹤單一檔案的版本
控制系統要稍微麻煩些。

好在麻煩還不大，也是值得的，因為Git其他的操作難以置信地高效。例如，`git
checkout`比`cp -a`都快，而且項目範圍的delta壓縮也比基于檔案的delta集合的做法
好多了。

=== 初始克隆 ===

The initial cost is worth paying in the long run, as most future operations will then be fast and offline. However, in some situations, it may be preferable to create a shallow clone with the `--depth` option. This is much faster, but the resulting clone has reduced functionality.

當一個項目歷史很長後，與在其他版本系統裡的檢出代碼相比，創建一個克隆的開銷會
大的多。

長遠來看，開始付出的代價還是值得付出的，因為大多將來的操作將由此變得很快，並
可以離線完成。然而，在一些情況下，使用`--depth`創建一個淺克隆比較划算些。這種
克隆初始化的更快，但得到克隆的功能有所削減。

=== 不穩定的項目 ===

變更的大小決定寫入的速度快慢是Git的設計。一般人做了小的改動就會提交新版本。這
裡一行臭蟲修改，那裡一個新功能，修改掉的註釋等等。但如果你的檔案在相鄰版本之
間存在極大的差異，那每次提交時，你的歷史記錄會以整個項目的大小增長。









任何版本控制系統對此都束手無策，但標準的Git用戶將遭受更多，因為一般來說，歷史
記錄也會被克隆。

應該檢查一下變更巨大的原因。或許檔案格式需要改變一下。小修改應該僅僅導致幾個
檔案的細小改動。

或許，資料庫或備份/打包方案才是正選，而不是版本控制系統。例如，版本控制就不適
宜用來管理網絡攝像頭周期性拍下的照片。

如果這些檔案實在需要不斷更改，他們實在需要版本控制，一個可能的辦法是以中心的
方式使用Git。可以創建淺克隆，這樣檢出的較少，也沒有項目的歷史記錄。當然，很多
Git工具就不能用了，並且修復必須以補丁的形式提交。這也許還不錯，因為似乎沒人需
要大幅度變化的不穩定檔案歷史。

另一個例子是基于韌體的項目，使用巨大的二進制檔案形式。用戶對韌體檔案的變化歷
史沒有興趣，更新的壓縮比很低，因此韌體修訂將使倉庫無謂的變大。

這種情況，源碼應該保存在一個Git倉庫裡，二進制檔案應該單獨保存。為了簡化問題，
應該發佈一個腳本，使用Git克隆源碼，對韌體只做同步或Git淺克隆。

=== 全局計數器 ===

一些中心版本控制系統維護一個正整數，當一個新提交被接受的時候這個整數就增長。Git則是通過哈希值來記錄所有變更，這在大多數情況下都工作的不錯。

但一些人喜歡使用整數的方法。幸運的是，很容易就可以寫個腳本，這樣每次更新，中心Git倉庫就增大這個整數，或使用tag的方式，把最新提交的哈希值與這個整數關聯起來。

每個克隆都可以維護這麼個計數器，但這或許沒什麼用，因為只有中心倉庫以及它的計數器對每個人才有意義。

=== 空子目錄 ===

空子目錄不可加入管理。可以通過創建一個空檔案以繞過這個問題。

Git的當前實現，而不是它的設計，是造成這個缺陷的原因。如果運氣好，一旦Git得到
更多關注，更多用戶要求這個功能，這個功能就會被實現。

=== 初始提交 ===

傳統的計算機系統從0計數，而不是1。不幸的是，關於提交，Git並不遵從這一約定。很
多命令在初始提交之前都不友好。另外，一些極少數的情況必須作特別地處理。例如重
訂一個使用不同初始提交的分支。

Git將從定義零提交中受益：一旦一個倉庫被創建起來，HEAD將被設為包含20個零位元組
的字元串。這個特別的提交代表一棵空的樹，沒有父節點，早于所有Git倉庫。

然後運行git log，比如，通知用戶至今還沒有提交過變更，而不是報告致命錯誤並退出。
這與其他工具類似。

每個初始提交都隱式地成為這個零提交的後代。

不幸的是還有更糟糕的情況。如果把幾個具有不同初始提交的分支合併到一起，之後的
重新修訂不可避免的需要人員的介入。

=== 介面怪癖 ===

對提交A和提交B，表達式“A..B”和“A...B”的含義，取決於命令期望兩個終點還是一
個範圍。參見 *git help diff* 和 *git help rev-parse* 。
