创建储存库
本节部分内容参考自 git-recipes,在原文基础上有一定修改。
git init
git init
命令创建一个新的 Git 储存库。它可以在一个已经有文件的储存库中使用,用来将已存在但还没有版本控制的项目转换成一个 Git 储存库,或者在一个空文件夹里使用,创建一个空的新储存库。
运行 git init
命令会在你项目的根目录下创建一个新的 .git
目录,其中包含了你项目必需的所有元数据。除了 .git
目录之外,已经存在的文件不会被改变。
详细用法
点击展开
git init
将当前的目录转换成一个 Git 储存库。它在当前的目录下增加了一个 .git
目录,于是就可以开始记录项目版本了。
git init <directory>
在指定目录创建一个空的 Git 储存库。运行这个命令会在当前目录下创建一个名为 directory
,只包含 .git
子目录的空目录。
git init --bare <directory>.git
初始化一个裸的 Git 储存库(无工作树)。这个目录会创建一个名为 <directory>.git
的目录,其中包含了一个储存库的元信息。裸的储存库一般用作服务器上的共享储存库。关于裸的储存库,后文会详细解释。
git clone
git clone
命令拷贝整个 Git 仓库。这个命令获取到的副本是一个完备的Git仓库——它包含自己的历史,管理自己的文件,并且环境和原仓库完全隔离。
为了方便起见,Git 在 clone 时会自动创建一个名为 origin
的远程连接,指向原有仓库。这让和中央仓库之间的交互更加简单。
如果项目在远程仓库已经设置完毕,git clone
是用户获取开发副本最常见的方式。和 git init
相似,clone 通常也是一次性的操作——只要开发者获得了一份工作副本,所有版本控制操作和协作管理都是在本地仓库中完成的。
详细用法
点击展开
git clone <repo>
将位于 repo
的仓库克隆到本地机器。原仓库可以在本地文件系统中,或是通过 HTTP 或 SSH 连接的远程机器。
git clone <repo> <directory>
将位于 repo
的仓库克隆到本地机器上的 directory
目录。
谁是本体?
当我们用 git init
创建储存库的时候,Git 只是在当前目录下创建了一个 .git
目录。而如果我们手动把这个目录删掉,它就又从储存库变回原本平平无奇的文件夹了。整个过程中,Git 没有对原本的文件做出任何破坏性的改变。
看来所有的秘密都藏在这个 .git
目录中了。Git 到底对这个目录用了什么魔法?
当我们在开发时,99.999% 的时间都是在和我们自己的代码打交道,.git
文件夹对我们而言是一个黑箱。所以,有的时候,我们可能会产生一种错觉,认为我们能看到的代码是本体,而 .git
只是 Git 提供的附属品而已。
但事实并非如此。从我们敲下 git init
的那一刻开始,世界在 Git 的眼中就发生了改变。在 Git 看来,那个不起眼的 .git
才是储存库的本体,其他的一切都是它的附属品。
没错,就和一些漫画中的人物一样,「眼镜才是本体」。
储存库和工作树
什么是工作树?
在 Git 眼中,真正的储存库只是那一个 .git
文件夹。而在外面天天被我们盯着看的东西,在 Git 的世界里叫做「工作树 (worktree)」。
一个 Git 储存库可以有一个或多个工作树,甚至可以没有工作树。我们用 git init
和 git clone
建立的,都是一个储存库和一个工作树的组合,这样建立的工作树称为「主工作树」。
用 git worktree list
命令,可以查看当前 Git 储存库中的所有工作树。
$ git worktree list
E:/git-remake-guide 5c64c4d [创建储存库]
Git 的文件系统
在 Git 中,文件以两种形式存放:在储存库中,按照 Git 的格式将每一个版本储存为一个个 object
,并按照更改历史、提交信息等等建立索引;在工作树中,按照一般的操作系统可识别的文件系统的方式存放。由于在储存库中,文件存在多个版本,而且并不是按照目录结构存放的,所以,对储存库中的文件不能直接编辑,而是要通过 Git 命令提取到工作树之后再编辑。
从储存库中取出文件,将其置入工作树中的操作,称为「签出(checkout)」。没错,就是熟悉的 git checkout
命令。
而与之对应的,将工作树中的文件写入储存库的操作,称为「签入」。签入操作没有一个单独的命令对应,而是通过 git add
git commit
等一系列命令来完成。
一般情况下,开发的流程是这样的:先从储存库中签出文件,然后在工作树中修改文件,最后进行签入,把工作树中的文件写入储存库。
所以,Git 的储存库不仅包含着工作树中全部的内容,也包含着工作树全部的历史。就算把工作树删掉,依然可以从储存库中签出一个工作树的版本出来。
裸仓库
工作树的存在,是为了方便对储存库内容进行编辑。有的时候,我们只需要 Git 储存库,而不需要工作树。比如,像 GitHub 这样的托管服务上,只需要知道用户的储存库,而不用管理一个工作树。
像这样没有工作树,只有储存库的情况,称为「裸仓库」。
用 git init --bare <directory>.git
命令,可以创建一个裸仓库。这个命令会在当前文件夹下建立一个名为 directory.git
的文件夹,其中的文件结构和一般的 .git
如出一辙。
Git 约定裸仓库的名称以 .git
结尾。这就是为什么我们看到的 GitHub 上的储存库链接的结尾都是 XXX.git
;实际上,这就是一个裸仓库的文件夹名。
既然我们可以克隆一个 GitHub 上的裸仓库,我们当然也能克隆一般的储存库。你可以找一个本地的 Git 储存库,然后克隆它试试:
$ git clone E:\git-remake-guide\.git
Cloning into 'git-remake-guide'...
done.
$ lsd --tree --classic .\git-remake-guide\
git-remake-guide
├── assets
│ ├── custom.css
│ ├── sidetoc.css
│ └── sidetoc.js
├── book.toml
├── README.md
├── src
│ ├── Git-重学指南.md
│ ├── SUMMARY.md
└── theme
├── favicon.png
├── favicon.svg
└── index.hbs
完美。