说到Git
,作为程序员的你,在项目开发中一定会使用到或将来也一定会使用到的,但是我相信,很多在使用Git
的人,都只是停留一些简单的操作上,比如提交(commit
)、拉取(pull
)、推送(push
)。
而对于Git
的工作原理,如何解决Git
的版本冲突以及如何使用Git
进行源码管理等问题可能并没有太深的认识,那么接下来,我们从最基础的开始,一起由浅入深来探讨一下。
什么是Git?
-
Git
目前最流行和最强大的开源分布式版本控制管理系统。 -
Git
作者是Linus Torvalds
,这个名字是不是听着很熟,没错,是Linus Torvalds
也是Linux
操作系统的作者。 -
Git
的作者因为很讨厌集中式版本控制管理系统,所以才会想开发分布式版本管理系统,这才有Git
的诞生。 -
Git
开发的初衷也是为了方便Linux
社区更好地管理和维护Linux
系统的代码。
Git和SVN的比较
Git
与SVN
之间的比较,也可以看作是分布式版本管理系统
与集中式版本管理系统
的比较,Git
是分布式版本管理系统,而SVN
是集中式版本管理系统。
从版本库存储的位置进行比较
对于集中式版本管理系统
而言,版本库是放在远程服务器上的,开发人员通过与服务器上的版本库连接进行代码版本提交,如果无法连接到服务器上,根本没有办法进行代码的版本管理,如:
而分布式版本管理系统,代码提交与版本管理都可以本地进行,不必连到服务器就可以进行各种版本管理操作。
只有当我们觉得需要与其他人同步代码时,才需要连到其他版本库进行同步操作,如下图所示:
学习难度上进行比较
Git
虽然非常强大好用,但其学习难度比SVN
大,虽然上手很容易,只需要学习git add
,git commit
,git push
和git pull
,但要真正学会且能很好地应用于复杂的项目开发管理,其学习周期还是比较长的,而SVN
则相对比较容易掌握。
从版本库大小进行比较
Git
的版本库是存储在我们的本地,所以会占用我们本地的存储空间,另外,由于Git
版本库包含每个文件的的副本,因此相比集中式的版本控制管理系统,也会占用更多的存储空间。
区分Git、GitLab、GitHub
Git
是分布式版本控制系统,通过Git
提供的工具集,我们可以管理本地版本库,并可以将代码提交到远程版本库或拉回其他人提交的版本。
Github
是基于Git
的在线Web
代码托管服务,我们可以在Github
上创建自己的公有或私有的版本库(私有库要钱的
),并可以通过Web
页面进行管理,而在我们本地还可以通过Git
与之交互,将代码提交到Github
上面的远程版本库中与团队其他成员共享。
如果我们对自己的项目源代码的安全性要求更高呢?这时候我们需要搭建自己的代码托管服务,这时候GitLab
便是很好的选择了。
GitLab
是一套用于搭建我们自己的私有Web
代码托管服务项目,通过使用GitLab
,我们可以在自己的服务器上搭建与Github
一样的Web
代码托管服务器,同样,GitLab
也提供一样的Web
页面管理操作。
最小化配置
如果你完成了Git
的安装,那么在使用Git
之前你需要完成一个小小的配置,就是配置用户信息。
Git
的所有配置使用git config
命令来完成,而用户信息只需要配置user.name
和user.email
即可,如下:
# 配置用户名
git config --global user.name '你的用户名'
# 配置邮箱
git config --global user.email '你的邮箱'
复制代码
上面git config
命令用参数--global
指定的配置为全局配置,也就是对所有版本库都会生效,除了--global
外,git config
命令还可以通过--local
、-- system
两个参数来指定配置的级别。
参数 | 说明 |
---|---|
--global | 全局有效 |
--system | 对当前所有登录的用户有效 |
--local | 对当前版本库有效 |
如果有相同的配置,通过--local
指定的配置优先大于--system
,而--system
的优先级大于--global
。
查看配置
在git config
后面跟上--list
参数可以查看Git
配置,再指定--global
,--system
,--local
,可以查看不同级别的配置,如:
查看全局配置
git config --list --global
复制代码
查看用户级别配置
git config --list --system
复制代码
查看当前版本库配置
git config --list --local
复制代码
如果指定--local
时,当前执行命令的目录必须在一个版本库下,否则会报以下的错误:
fatal: --local can only be used inside a git repository
复制代码
版本库管理
版本库是Git
中最重要的概念,在一个版本库中,包含了当前项目所有的提交。
创建本地版本仓库
安好Git
之后,便可以通过Git
提供的命令来创建版本库了,通过版本库,将添加到版本库里面的文件进行版本管理。
先创建目录,再创建版本库
# 创建空目录
$ mkdir test
# 进入空目录
$ cd test
# 初始化版本库
$ git init
复制代码
我们也可以将上面的的步骤简化为:
$ git init test
$ cd test
复制代码
克隆远程版本仓库
上面我们通过git init
命令在本地初始化一个版本库,一种这种称为裸库
,而有时候,我们会直接通过git clone
命令将远程的版本库克隆到本地,如:
git clone https://www.github.com/test/test.git
复制代码
通过这种方式,我们可以将远程版本库中项目克隆到本地,当我们参与一些老的项目时,一般就是采用这种方式来创建本地的版本库。
工作目录、版本库(stage)、暂存区(repository)
通过上面的两种方式,我们已经在本地创建好了版本库,接下来我们就可以开始将自己的文件添加到版本库了。
首先我们在工作目录创建名为test.txt
的文件,内容可以随意,比如:
这是我添加到版本库中的第一个文件
复制代码
这时候我们通过git status
命令查看工作目录的状态,如下所示:
$ git status
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
test.txt
nothing added to commit but untracked files present (use "git add" to track)
复制代码
可以看到,Git
提示我们要执行git add <file>
操作,这是将文件到添加Git
的暂存区,我们执行一下:
# 下面三个命令都可以将test.txt添加到暂存区
git add test.txt
git add .
git add all
复制代码
再使用git status
查看状态,如下表示已经添加到暂时区了。
$ git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: test.txt
复制代码
接下来便是将暂存区中的文件提交到版本库了,使用git commit
命令,后面的-m
表示提示说明。
git commit -m "添加test.txt文件"
复制代码
提交后,结果如下:
[master 23811d4] 添加test.txt文件
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 test.txt
复制代码
上面结果提示中,23811d4
表示本次的提交的ID
,这个ID
是实际上是由40个十进制数字组的SHA1散列值,上面结果中显示只是这个提交ID的前7位值。
这里需要明确几个概念,那就是工作区
、暂存区
、版本库
,该项目所有目录,我们称为工作区
,而在该目录下,会生成一个.git
的隐藏目录,这个目录我们称为版本库
,暂存区(stage)
是Git
独有的概念,暂存区
是版本库
的一部分,这三者之间的关系,我们如下图所示:
如果想把文件从暂存区移除,可能使用下面的命令:
git rm --cached test.txt
复制代码
分支管理(branch)
我们知道在Git
中,每个提供都会产生一个40
位十六进制数字组成的SHA1
散列值,而由这些值串成的一条时间线,便是分支,在上面的演示中,我们一直在Git
的master
分支上。
master
是Git
的默认分支,除了master
外,我们任意创建自己的分支,分支总是向指最新的提交(commit
),而在Git
版本库中,还保留着一个指针HEAD
,默认指向当前分支,所以分支、HEAD与commit的关系是HEAD
是一个指针,指向当前分支的最新提交(commit
),并且将HEAD
保存在.git/HEAD
文件当中。
通过下面的图,我们可以更好地理解不同分支,提交与HEAD
的关系:
创建分支
在git branch
命令后面跟上分支名
可以基于当前的分支再创建一个新的分支,如:
git branch deveolp
复制代码
查看分支
git branch
复制代码
执行结果如下:
develop
* master
复制代码
也可以使用下面的方式查看分支列表
$ git show-branch
! [develop] develop
* [master] develop
--
+* [develop] develop
复制代码
检出分支
通过git branch
命令创建好分支后,Git
并不会帮我们检出该分支,我们可以使用git checkout
命令检出该分支,这样便可以在该分支下进行开发了,如:
$ git checkout develop
复制代码
如果检出的分支不存在,则会报错,比如我们检出不存在的dev
分支,会报如下所示的错误:
error: pathspec 'dev' did not match any file(s) known to git
复制代码
如果在检出分支不存在时,想基于当前分支直接创建分支,也可以在git checkout
跟上参数-b
,如:
git checkout -b dev
复制代码
这样便可以直接创建分支了,当然,如果分支已经存在,也会报错,比如:
git checkout -b develop
复制代码
由于我们创建了develop
,因此会报出以下错误:
fatal: A branch named 'develop' already exists.
复制代码
删除分支
对于不想的分支,可以使用git branch -d
命令进行删除,如:
git branch -d develop
复制代码
强制删除
git branch -D develop
复制代码
合并分支
当我们开发完成后,从develop
合并到master
,这时的操作应该切到master
分支下,在master
执行合并命令。
git merge develop
复制代码
简单的标签管理(Tag)
Git
支持打标签(tag
)的操作,标签有时候也称为里程碑,当我们开发到一定阶段有一定的成果,我们可以在当前分支上打上一个标签,比如说我们在开发到某个阶段时,在分支打上v1.0
的标签,表示1.0
版本已经完成。
查看所有的标签
在打标签之前,我们先看一下如何查看所有的标签,如:
$ git tag
v1.0
v1.1
v1.2
v2.3
复制代码
上面的命令会简单显示所有的一个简单的标签列表,如果想查看标签的说明,可以这样
$ git tag -n1
v1.0 develop
v1.1 develop
v1.2 develop
v2.3 develop
复制代码
使用通配符查看本地标签
$ git tag -l v1.*
v1.0
v1.1
v1.2
复制代码
创建标签
创建标签有以下几种方式:
git tag <tag_name> [commit_id]
git tag -a <tag_name> [commit_id]
git tag -m message <tag_name> [commit_id]
git tag -s <tag_name> [commit_id]
git tag -u <key> <tag_name> [commit_id]
复制代码
不带commit_id
,创建没有说明的tag
:
git tag v1.0
复制代码
使用-a
参数添加标签说明,这种方式会打一个vim
编辑器让我们输入说明:
git tag -a v1.1
复制代码
在某个commit
之上打标签
git tag v1.2 c22be11
复制代码
删除标签
Git
标签不允许修改,如果我们对某个标签不满意,可以删除标签,再重新创建,删除标签语句如下:
git tag -d v1.2
复制代码
忽略特殊文件
在项目开发时,有一些文件我们不想添加到怎么版本库中进行版本控制,比如IDE
自动生成的配置文件、项目数据库配置文件或者编译后生成的临时目录等等。
这时候我们可以在工作目录中添加.gitignore
文件来指要忽略哪些目录或文件,并将.gitignore
文件添加到版本库,因为.gitignore
文件需要进行版本控制。
当然,除了通过.gitignore
文件指定忽略文件外,也可以通过命令行直接指定。
忽略文件的位置
工作区根目录
在工作区根目录创建.gitignore
文件是最常用的方式,这种方式可以控制整个项目的文件。
工作区子目录
在某个子目录上创建.gitignore
文件来覆盖上层目录中.gitignore
的忽略规则对当前目录的影响。
全局配置
当我们在工作区创建忽略文件后,如果我们通过push
操作把项目推送到远程版本库,那么忽略文件同样也要推送上去,这里别的开发者也会得到同样的的忽略规则,如果有时候忽略规则只是我们本地独有的,不想与别人共享,那我们可以通过下面的方式,配置一个全局的
git config --global core.excludesfile ~/.gitignore
复制代码
.git/info/exclude
在.git/info/exclude
也可以添加忽略规则,这种方式并不常用,与全局.gitignore
文件一样,这种方式也是本地独有,并不会与其他开发者共享。
Git 忽略规则优先级
既然可以通过这么多种方式来指定.gitignore
文件,那么不同的.gitignore
就有不同的优先级,其优先级由高到低如下所示:
-
从命令行中读取可用的忽略规则最高
-
当前目录定义的规则
-
父级目录定义的规则,依次递推,直到工作区根目录
-
.git/info/exclude
文件中定义的规则 -
core.excludesfile
中定义的全局规则
忽略文件的语法
#
:#用于注释说明
*
:通配符,表示任何个字符。
?
:表示一个任何字符。
!
:表示不忽略该文件或目录
/
:/
位置一行开始位置时,表示忽略这个目录下的文件,不忽略其他子目录的同名文件,如果/
位置一行的最后位置,则表示只忽略目录,而同名文件不忽略。
[abc]
:可选的字符范围
示例
# 这是一行注释
a* #忽略任何以a开头的文件和目录
!action # 不忽略action文件
/verdor #忽略根目录下的verdor文件
复制代码
忽略文件只对未跟踪文件有效
忽略文件只对未跟踪的文件有效果,如果某个文件已经被提交到版本库了,这时候再把文件添加了忽略文件中,也不会有效果了。
小结
其实,无论你是不是一名程序员,都可以把Git
作为管理一个自己文档或代码的工具,通过使用Git
,我们可以更高效地管理和组织自己的项目和文档,在不断地修改和变更中,也不害怕文档的丢失。
作者:张君鸿
链接:https://juejin.im/post/5ddbeed9e51d45230a3306cc
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。