Git的一个显著特点是,版本库位于工作区的根目录下。对于Git来说,版本库位于工作区根目录下的 .git 目录中,且仅此一处,在工作区的子目录下则没有任何其他跟踪文件或目录。
Git这种将版本库放在工作区根目录下的设计使得所有的版本控制操作(除了与其他远程版本库之间的互操作)都在本地即可完成,不像Subversion只有寥寥无几的几个命令脱离网络执行。而且,Git没有CVS和Subversion中存在的安全泄漏问题(只要保护好 .git 目录)。
Git将版本库(.git目录)放在工作区根目录下,那么Git的相关操作一定要在工作区根目录下执行吗?换句话说,当工作区中包含子目录,并在子目录中执行Git命令时,如何定位版本库呢?实际上,当在Git工作区的某个子目录下执行操作的时候,会在工作区目录中依次向上递归查找 .git 目录,找到的 .git 目录就是工作区对应的版本库, .git所在的目录就是工作区的根目录,文件.git/index记录了工作区文件的状态(实际上是暂存区的状态)。
另外,如果在非Git工作区执行 git 命令时会因为找不到 .git 目录而报错。
$ cd /path/to/my/workspace/ $ git status fatal: Not a git repository (or any of the parent directories): .git
如果在工作区的某个深层的子目录中,我们有什么办法知道Git版本库的位置呢?如何才能知道工作区的根目录在哪里呢?可以用Git的一个底层命令来实现,具体操作过程如下例:
1. 在工作区中建立目录a/b/c,进入到该目录中。
$ cd /path/to/my/workspace/demo/ $ mkdir -p a/b/c $ cd /path/to/my/workspace/demo/a/b/c
2. 显示版本库 .git 目录所在的位置:
$ git rev-parse --git-dir /path/to/my/workspace/demo/.git
3. 显示工作区根目录:
$ git rev-parse --show-toplevel /path/to/my/workspace/demo
4. 相对于工作区根目录的相对目录:
$ git rev-parse --show-prefix a/b/c
5. 显示从当前目录(cd)后退(up)到工作区的根的深度:
$ git rev-parse --show-cdup ../../../
传统的集中式版本控制系统的工作区和版本库都是相分离的,像Git这样把版本库目录放在工作区是不是太不安全?
从存储安全的角度上来讲,将版本库放在工作区目录下有点“把鸡蛋装在一个篮子里”的味道。如果忘记了工作区中还有版本库,当直接从工作区的根执行目录删除操作时就会连版本库一并删除,这个风险的确很高。将版本库和工作区折开似乎更加安全,但是不要忘记了之前的讨论,如果将版本库和工作区拆开,就要引入其他机制以便实现版本库对工作区的追踪。
Git克隆可以降低因为版本库和工作区混杂在一起而导致的版本库被破坏的风险。可以通过克隆操作在本机另外的磁盘/目录中建立Git克隆,并在工作区有新的提交时,手动或自动地执行向克隆版本库的推送(git push)操作。如果使用网络协议,还可以实现在其他机器上建立克隆,这样就更安全了(双机备份)。对于使用Git做版本控制的团队,每个人都是一个备份,因此团队开发中的Git版本库更安全,管理员甚至无须顾虑版本库存储的安全问题。