版本控制系统(Version Control System, VCS) 类似于代码的历史记录面板,当然功能更加丰富,它可以给多个人同时使用,添加修改,撤销修改等等…
1972年,贝尔实验室在开发祖宗级操作系统Unix时,最早的版本控制系统SCCS诞生了
1982年,Revison Control System 诞生了,虽然支持跨平台,但其与前者相同,只适用于文本文件
1986年,集中式版本控制系统(Centralized Version Control Systems, CVCS)开始研发,其采用一个中央服务器作为仓库载体,存储代码,追踪文件修改,但还没有追踪整个文件目录
80年代后期,Perforce已经广泛应用于各大网站了(直到现在仍有一些大公司在使用,如育碧,英伟达等)
2000年,Subversion出现了,不仅支持非文本文件,还支持追踪整个文件夹内的变化
2004年,微软开发了 Team Foundation Server (TFS),功能上更加全面丰富,利于协同开发,且收到了其他企业的订单
--------------------------------------------------------------
林纳斯·托瓦兹(Linus Torvalds) 与他的团队开发Linux系统的内核时,当时他们使用的VCS是免费版的BitKeeper,然而有一天 BitKeeper 不再免费服务,林纳斯决定创造一个免费的VCS
2005年4月7号,分布式版本控制系统 Git(的第一个提交)诞生了
集中式 VCS
通过同一个集中管理的中央服务器保存所有文件的修订,开发人员通过客户端连到这台服务器,更新文件或提交更新,如前文所说的 CVS、Subversion、Perforce,这种工作原理有一个致命问题:如果中央服务器(Central VCS Server)不工作了,那所有人就都不用工作了…
分布式 VCS
开发者不只提取最新版本的文件快照,并完整地镜像代码仓库到本地,如前文所述的 Git、Mercurial 以及 Bazaar、Darcs 等,即使文件无修改,也会快照文件,这种工作机制不仅避免了中央服务器带来的尴尬问题,而且能保证仓库在每个人本地有完整的备份,与前者相比,分布式 VCS 具有很大的优越性
安装过程比较简单,除了在官网下载安装程序,Windows 也可通过 Chocolatey 安装
https://git-scm.com/downloads
Linux 系统的安装指令
安装完成后,可直接在命令行输入 git 或者 git --version 确认是否安装成功
输入 git help 可以获取帮助
git 子命令的选项有长短两种形式,长选项是 Linux 风格
有时需要 双破折号– 分离参数,
比如分离指令的控制部分与操作数部分, 如标识文件名或区别文件名与tag
版本库 Repository
一个 Git 版本库(仓库)对应一个文件夹(工作目录),仓库的重要信息存储于工作目录下的 .git 文件夹里,类似一个简单的数据库,其包含所有用于维护与管理项目的修订版本和历史的信息,主要维护两件东西:对象库、索引
对象库 Object Store
----- 对象库是版本库的核心,其包括 4 种对象,每个对象都有一个唯一的SHA1散列值,散列值由内容决定,与操作系统,路径等均无关
- 块 Blob:Binary Large Object,大意为二进制大对象,保存一个文件的主要数据
- 目录树 Tree:即目录信息,记录Blob,路径名以及文件元数据,如文件名
- 提交 commit:记录着一次提交的详细信息,每个提交指向一个目录树
- 标签 tag:分配给一个对象自定义的名称,通常是提交对象.
索引 Index
----- 一个临时的、动态的二进制文件,捕获项目在某一时刻的整体目录结构的版本,记录当前有哪些修改
重要特点
- 直接记录快照,而非差异比较:每次提交或在 git 中保存项目状态时,git对当时的全部文件制作快照并保存该快照的索引。没有修改的文件,则不再重新存储该文件,只保留一个链接指向其之前存储的文件。 git 对待数据更像是一个快照流
- 保证数据完整性:git 存储数据前以 SHA-1 散列计算校验和,使用前再校验,因此不可能在 Git 不知情时更改任何文件内容或目录内容
- 一般只添加数据:很难执行不可逆操作,或者以任何方式清除数据
- 近乎所有操作都是访问本地文件不需要网络
- 原子操作:要么执行所有修改要么放弃所有修改
状态
仓库中的文件通常处于 3 种状态下:
- 已追踪 Tracked ----已在版本库中的文件,或是已暂存到索引中的文件
- 已忽略 Ignored ----版本库中存在但不需要追踪的文件
- 未追踪 Untracked ----不属于以上两者的文件
而文件的修改状态有以下 3 种:
- 已修改 modified ----- 在工作目录中修改文件
- 已暂存 staged ----- 暂存文件,将已修改的文件的快照放入暂存区域
- 已提交 committed ----- 找到暂存区域的文件,将快照永久性存储到 Git 仓库目录
Git 的配置级别分为 3 种:
Local 针对当前仓库的配置 project/.git/ config
global 针对当前用户的配置 ~/.gitconfig
System 针对所有用户及其仓库通用的配置 /etc/ gitconfig
如果出现相同配置项如 user.email 则优先使用 Local 的其次是 global 最后 system
⚡ 查看所有配置
⚡ 常用配置项
- 配置提交人的名字与邮箱
- 配置默认编辑器
- 配置提交模板
- 配置忽略文件
- 设置颜色输出 true/false/always
方法一:克隆
通常情况下,仓库已经建好,我们需要从 gitlab 或者 github 上将仓库下载到本地
默认创建的文件夹名称为仓库名,如需自定可以替换 <custom_repository_name>
方法二:初始化+添加
如果是首次创建仓库,则需要先在 github 或 gitlab 上创建一个仓库,创捷完成后,会生成一个地址,在本地找个空目录,
⚡ 查看未暂存的文件变更 git diff
⚡ 加入暂存区 git add
⚡ 提交 git commit
Note: 提交信息应少于 50 个字符(25个汉字)
提交的时候,若需要忽略某些文件,如.pyc,local_settings.py等,可以设定.gitnore文件
.gitignore 语法:
- 所有空行或者以 # 开头的行都会被 Git 忽略
- 可以使用标准的 glob 模式匹配
- 匹配模式可以以(/)开头防止递归
- 匹配模式可以以(/)结尾指定目录
- 要忽略指定模式以外的文件或目录,可以在模式前加上 !取反
⚡ 删除文件 git rm
删除某个 Tracked文件 不追踪 + 删除文件
删除某个既是 staged 也是 modified 的文件只能 --force
不追踪 + 保留文件 Tracked —> Untracked
⚡ 重命名/移动 git mv
实际上,git 执行了下列三项指令
⚡ 暂存文件 git stash
查看暂存区
恢复暂存的修改
移除指定暂存
直接将暂存移入新分支
⚡ 清理文件 git clean
⚠️注意:clean 不会删除 .gitignore排除的文件,删除排除文件加上 -x
修改多个提交的备注 可用git rebase 解决
⚡ 撤销修改/回退版本
通常情况下 git log 即可,当然也有一些实用的选项
显示的格式可以通过 –pretty 参数自定义
写工作日志或月总结,忘了上周自己做了哪些项目,此时用这项指令很有用
⚡ 快速查看昨天 develop 分支上的提交
⚡ 列出所有提交者的提交统计
可以看到每一个提交者分别有多少次提交,以及每次提交的提交信息
其记录了最近几个月 HEAD 和分支引用所指向的历史
⚡ 增删
⚡ 推拉
git fetch 命令会将数据拉取到你的本地仓库, 它并不会自动合并或修改你当前的工作
它与 git pull 的关系可大概理解为 git pull = git fetch + git merge
分支的本质是指向提交对象的可变指针, 是包含所指对象校验和(长度为 40 的 SHA-1 值字符串)的文件,分支还可以分为两种,长期分支如 master,功能(特性)分支如 feature, hotfix
Note: 个人建议将分支理解为指针,这样有助于理解学习git
⚡ 查看
HEAD 指向当前所在的本地分支,ORIG_HEAD 指向原始HEAD
⚡ 切换与增删
-----------直接挪动指针的神器之一
常见用途是保持你正在开发的分支相对于主分支是最新的
如我从主分支 master 上新建一个功能分支 feature-upload,开发当前迭代的新功能,
某位同事修复了一个重大bug并提交到了 master 分支上,此时可用变基获取这些修改
一如既往,获取修改时可能遇到需手动处理的冲突 ~~~
⚡ 交互式变基
用途:一次修改多个提交的message | 重新排序commits | 删除某个不要的commit
- 如果需要压缩多个提交为一个,可以在编辑器里将需要被压缩的 commit 前加上s(squash) 标记 s 的会被压入上一个提交
- 如果是修改多个提交的 Message,只修改四个中某个提交的message,只要将你想修改的提交前面的 pick 改为 edit
⚡ 两个比较实用参数:–onto | --preserve-merges
⚡ 中断或恢复
当前的提交历史
⚡ 往当前分支合入需要的分支
用变基+合并也可以,提交历史会更加“完美”:
- fast-forward
合并时出现该词,说明主分支是被合并分支的直接祖先,所以指针只是向后快速移动了
合并时出现冲突,可以通过 git status 查看冲突文件并解决
⚡ 继续 & 终止
⚡ 忽略合并时由任意数量空白引起的冲突