== 附录 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* 。
