从零开始的 Git 代码管理指南(〇) 基本概念

〇、为什么(即使是一个很小的项目也)需要代码管理

在维护代码,或者类似代码的过程当中,我们往往会做一些肯定会做大量的修改,其中一些改动会让我们的程序不再完好,或者在大量的改动之后发现方向上的错误,为此不得不回退到某个时间点的状态——为了恢复文件,这是版本管理最朴素的需求,这一系列需求不一定需要用版本管理系统来实现(比如MacOS的Time Machine每日备份就能解决一部分问题),但版本管理系统一定是最灵活的解决方案。

另一部分代码,我们的开发往往不是线性的,即我们有可能有多个特性同时开发,在特性开发完成之前,我们不希望特性之间互相影响,在特性开发完成之后,我们需要能够方便的合并若干特性的代码——这是版本树(DAG,有向无环图)的来源。

还有一些情况,我们需要将某个特性单独分发给别人,或者在发现有重大Bug引入的时候,需要回退改动——需要获取版本之间的改动,这是版本管理系统擅长的操作。

而以上几个需求,分别对应了Git当中的commit,branch,cherry-pick等操作。

一、commit(提交)

如果要新建一个Git仓库,只需要在需要使用Git维护版本的目录下,输入:

1
$ git init

即可新建一个Git仓库。Git仓库的各种信息保存在目录下的.git文件夹中,如果不再使用Git,只需要删除这一文件夹即可。

此时,这个新的Git仓库不包含任何内容,Git需要手动指定每一个需要被Git管理的文件,当然也可以通过指定一个文件夹来将这个文件夹下的所有文件加入Git。

1
2
3
$ git add .                 # 将当前文件夹加入到Git当中
$ git add a-file.txt        # 将 a-file.txt 加入到Git当中
$ git add a-directory       # 将 a-directory 加入到Git当中

很多文章都会提到,Git里面的文件可能有多种状态,有的已经编入Commit,有的在Stage(暂存区)当中,有的尚未被Git编入,上文的add命令,即将文件从未被收录的状态移入到暂存区当中。

当文件被加入到暂存区当中之后,可以通过git commit来提交(commit)在暂存区当中的文件。之后,Git会要求你用一段文字描述你的提交内容,这一内容可以随意填写,不同的项目会给出不同的提交内容的规范。如果提交描述比较简短,可以通过git commit -m <描述>来快速提交内容

1
2
$ git commit
$ git commit -m "A simple commit"

提交上去的改动并非不能修改,可以通过add新的内容到暂存区,并通过git commit --amend来修改刚刚的提交。

在Git当中,所有的提交都会被分配一个Commit ID,即提交号码,这是一串很长的十六进制字符串,在实际使用当中,尤其是在命令行当中,只需要Commit ID的一个唯一前缀,即可引用一个Commit,当然,还有很多别的方式可以实现对Commit的引用。

关于Commit的更多操作,会在后文当中继续阐述。

二、branch(分支)

前文提到,分支功能是同时维护多个特性时所必须要有的基本功能,git的分支本身非常简单,只是一个对于Commit ID的引用,分支本身不存储任何版本信息,它只是一个指向特定版本的指针。

在Git当中,创建一个分支非常简单,只需要:

1
$ git checkout -b <分支名>

即可创建一个分支,在Git的i18n当中,checkout被翻译为检出,即check与out两词的直译,算不上一个特别好的翻译,但未尝不可,比如check in在中文中即有“检录”一词与其对应。

在分支之间互相切换也是使用checkout,如:

1
2
$ git checkout master        # 切换到主分支
$ git checkout test          # 切换到test分支

事实上,还可以通过checkout命令来检出一个提交,如

1
$ git checkout ade2bb9       # 检出由ade2bb9开头的一个提交

关于分支与指针的更多信息,将在后续的文章中阐述。

三、协作

当维护一个仓库的时候,往往需要与他人协作,实现协作的方法很多,此处暂且介绍其中一种,即通过Git远程仓库来完成协作。

对于一个新的仓库,需要通过添加一个源来指定拉取(pull),或者推送(push)的目标,如:

1
2
3
4
5
6
$ git add origin https://git.example.com/repo.git
  # 添加一个名为origin的源,地址是https://git.example.com/repo.git
$ git push origin master
  # 将master分支的内容推送到origin当中
$ git pull origin master
  # 从origin拉取master分支的内容,到当前分支

使用Git协作不是一件非常直接的事情,如果仅仅使用pull与push,由于共同更改,显然会存在一些冲突,但这一操作已经可以实现最原始的协作模型,即一方修改之后,将改动推送到远端仓库,另一用户修改之后,将他的改动推送到远端仓库,然后己方再拉取,如此反复。

关于使用Git协作的更详细介绍,参见后文。

版本历史

2020/08/08 初始版本