1.版本控制
使用版本控制可以将某个文件回溯到之前的状态,设置将某个项目回退到过去某个时间点的状态。
集中化的版本控制系统 (SVN)
优点:代码存放在单一的服务器上,便于项目管理
缺点:
中央服务器的单点故障
如果服务器宕机一小时,那么在这一小时内,谁都无法提交更新,也就无法协同工作。(并不是说服务器故障了就没有办法写代码了,只是在服务器故障的情况下,编写的代码是没有办法得到保障的.试想 svn 中央服务器挂机一天.你还拼命写了一天代码,其中 12 点之前的代码都是高质量可靠的,而且有很多闪光点.而 12 点之后的代码由于你想尝试一个比较大胆的想法,将代码改的面目全非了.这样下来你 12 点之前做的工作也都白费了 有记录的版本只能是 svn 服务器挂掉时保存的版本!)
中央服务器磁盘发生故障
要是中央服务器的磁盘发生故障,碰巧没做备份,或者备份不够及时,就会有丢失数据的风险。最坏的情况是彻底丢失整个项目的所有历史更改记录,而客户端偶然提取出来的保存在本地的某些快照数据就成了恢复数据的希望。但这样的话依然是个问题,你不能保证所有的数据都已经有人事先完整提取出来过。只要整个项目的历史记录被保存在单一位置,就有丢失所有历史更新记录的风险。
SVN每次存的都是版本之间的差异代码,需要硬盘空间相对小一些,但是回滚的速度会很慢
分布式的版本控制系统 (Git)
客户端并不只是提取最新版本的文件快照,而是把代码仓库完整地镜像下来
Git每次存储的都是项目的完整快照,需要的硬盘空间会相对大一些(Git团队对代码做了极致的压缩,最终需要的实际空间比SVN多不了多少),Git的回滚速度极快
优点:完全的分布式
缺点:学习成本高
2.Git底层概念
2.1 基础Linux命令
1 | clear # 清除屏幕 |
2.2 初始化新仓库与.git目录
首次使用
1 | # git版本信息 |
初始化新仓库
1 | git init |
.git目录
2.3 Git区域与对象
2.3.1 区域
- 工作区(Working Directory)
本地代码,日常书写代码目录,肉眼可见区域(沙箱环境:git不会对其进行管理) - 暂存区(Stage 或 Index)
数据暂时存放的区域,可在工作区和版本库之间进行数据的友好交流。 - 版本库(commit History)
git commit 后给你生成版本的地方,注意push是提交到远程仓库而不是版本库,请勿混淆
工作流程
每个项目都有一个git目录(.git),它是用来保存元数据和对象数据库的地方,每次克隆镜像仓库时,实际上就是拷贝这个目录里的数据。
①、在工作目录中修改某些文件
从项目中取出某个版本的所有文件和目录,用以开始后续工作的叫做工作目录,这些文件实际上都是从Git目录中的压缩对象数据库中提取出来的,接下去就可以在工作目录中对这些文件进行编辑
②、保存到暂存区域,对暂存区做快照
暂存区域只不过是个简单的文件,一般都放在Git目录中,有时候人们会把这个区域的文件叫做索引文件,不过标准说法还是叫暂存区域
③、提交更新
将保存区在暂存区域的文件快照永久转储到本地数据库(Git目录)中
可以从文件所处的位置来判断状态
2.3.2对象(Git底层概念)
Git对象
key : value 组成的键值对,key是value对应的hash,键值对在git内部都是一个blob类型
git对象存储文件内容
git对象代表文件的一次次版本1
2
3
4
5
6
7
8
9
10
11
12
13》了解即可《
① 直接写入git对象方法与读取(存入".git/objects")
#将打印内容写入对象(git数据库)并且返回其相应哈希值
echo "写入的对象内容" | git hash-object -w --stdin
#读取内容并不能直接cat读取,因为git存入时已经加密,需要如下代码 -p:内容 -t:类型
git cat-file -p 存入对象的哈希值(此值可以由上一步得到)
#将文件写入git对象,即我们常见的版本控制中出现的
git hash-object -w ./test.txt
#查看Git存储的数据 返回其文件夹内的所有哈希文件
find .git/objects -type f树对象
树对象代表项目的一次次快照1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16》了解即可《
构建树对象
我们可以通过 update-index , write-tree , read-tree 等命令来构建树对象并且塞到暂存区
① 利用 update-index 命令 创建暂存区
利用 update-index 命令 为test.txt文件的首个版本创建一个暂存区,并通过write-tree命令生成树对象
#1生成一个树对象
git update-index --add --cacheinfo 100664(文件状态码:普通文件) 哈希值 对应文件名
#生成快照(树对象)
git write-tree
#2 将第一个树对象加入第二个树对象,使其成为新的树对象
git read-tree -prefix=bak 哈希值(树对象的)
git write-tree
② 查看暂存区当前样子
git ls-files -s提交对象 – 链式
我们可以通过调用commit-tree命令创建一个提交对象,为此需要指定一个树对象的SHA-1值,为此需要指定一个树对象的SHA-1值 , 以及该提交的父提交对象(如果有的话,第一次将暂存区做快照就没有父对象)
2.4小结
- 底层命令
1
2
3
4
5
6
7
8
9
10git对象:
git hash-object -w fileUrl //生成一个key(hash值):value(压缩后的文件内容)键值对存到.git/objects
tree对象
git update-index --add --cacheinfo 100644 hash test.txt //往暂存区添加一条记录(让git对象 对应上 文件名)存到.git/index
git write-tree //生成树对象存到.git/objects
commit对象
echo 'first commit' | git commit-tree treehash //生成一个提交对象存到.git/objects
对以上对象的查询
git cat-file -p hash //拿对应对象的内容
git cat-file -t hash //拿对应对象的类型 - 查看暂存区(需要记忆)
git ls-files -s
3.Git高层命令
1 | git init 初始化仓库 |
3.1 git操作最基本流程
创建工作目录 ——> 对工作目录进行修改
1 | git add ./ |
检查当前文件的状态
命令: git status
作用:确定文件当前处于什么状态
工作目录下面的所有文件都不外乎这两种状态:已跟踪 或 未跟踪
已跟踪的文件是指本来就被纳入版本控制管理的文件,在上次快照中有它们的记录,工作一段时间后,它们的状态可能是已提交,已修改或者已暂存
查看操作日志
命令:git log
作用:在提交了若干更新,又或者克隆了某个项目之后,想回顾下提交历史。
其他:
1 | # 规整查看信息的格式 |
3.2 git的分支
创建分支
命令:git branch
作用:为你创建了一个可以移动的新的指针。 比如,创建一个 testing 分支:git branch testing
。这会在当前所在的提交对象上创建一个指针
Git 的分支本质上是一个提交对象,HEAD是一个指针,默认指向master分支,切换分支时就是让HEAD指向不同的分支
分支切换会改变你工作目录中的文件。在切换分支时,一定要注意你工作目录里的文件会被改变。 如果是切换到一个较旧的分支,你的工作目录会恢复到该分支最后一次提交时的样子。如果 Git 不能干净利落地完成这个任务,它将禁止切换分支
- git切换分支会改变三个地方:HEAD、暂存区、工作目录
- 最佳实践:每次切换分支前,当前分支一定要处于已提交状态
- 切换分支时,如果当前分支上有未暂存的修改 或者 有未提交的暂存(第一次),分支可以切换成功,但是这种操作可能会污染其他分支
3.3小结
已下命令需要记忆
1 | # 安装 |
4.Git存储
有时,当你在项目的一部分上已经工作一段时间后,所有东西都进入了混乱的状态,而这时你想要切换到另一个分支做一点别的事情。 问题是,你不想仅仅因为过会儿回到这一点而为做了一半的工作创建一次提交。 针对这个问题的答案是 git stash
命令。
1 | 可以在任何时候重新应用这些改动(```git stash apply```) |
5.Git后悔药
三种情景:
- 工作区:如何撤销自己在工作目录中的修改
git checkout -- filename
- 暂存区:如何撤销自己的暂存
git reset HEAD filename
- 版本库:如何撤销自己的提交【注释写错】
git commit --amend // 重新提交注释信息
5.1 reset 三部曲(原理)
☆ 1.移动 HEAD
reset 做的第一件事是移动 HEAD 的指向。git reset --soft HEAD~
- 只动HEAD(带着分支一起移动)
看一眼上图,理解一下发生的事情:它本质上是撤销了上一次 git commit
命令。 当你在运行 git commit
时,Git 会创建一个新的提交,并移动 HEAD 所指向的分支来使其指向该提交。
当你将它 reset 回 HEAD~(HEAD 的父结点)时,其实就是把该分支移动回原来的位置,而不会改变索引和工作目录。 现在你可以更新索引并再次运行 git commit
来完成 git commit --amend
所要做的事情了。
☆ 2.更新暂存区(索引)git reset --mixed HEAD~
- 动HEAD(带着分支一起移动)
- 动暂存区
☆ 3.更新工作目录git reset --hard HEAD~
- 动HEAD(带着分支一起移动)
- 动暂存区
- 动工作目录
必须注意,–hard 标记是 reset 命令唯一的危险用法,它也是 Git 会 真正地销毁数据的仅有的几个操作之一。
git checkout commithash 与 git reset –hard commithash区别:
- checkout 只动HEAD、–hard动HEAD而且带着分支一起走
- checkout对工作目录是安全的、–hard是强制覆盖工作目录
路径reset
前面讲述了 reset 基本形式的行为,不过你还可以给它提供一个作用路径。 若指定了一个路径,reset 将会跳过第 1 步,并且将它的作用范围限定为指定的文件或文件集合。
6.数据恢复
在你使用 Git 的时候,你可能会意外丢失一次提交。 通常这是因为你强制删除了正在工作的分支,但是最后却发现你还需要这个分支;亦或者硬重置了一个分支,放弃了你想要的提交。 如果这些事情已经发生,该如何找回你的提交呢?
最方便,也是最常用的方法,是使用一个名叫 git reflog
的工具。
当你正在工作时,Git 会默默地记录每一次你改变 HEAD 时它的值。 每一
次你提交或改变分支,引用日志都会被更新
git reflog 并不能显示足够多的信息。为了使显示的信息更加有用,
我们可以执行 git log -g,这个命令会以标准日志的格式输出引用日志
☆ 恢复
看起来下面的那个就是你丢失的提交,你可以通过创建一个新的分支指向这个提交来恢复它。 例如,你可以创建一个名为 recover-branch 的分支指向这个提交(ab1afef)
git branch recover-branch ab1afef
现在有一个名为 recover-branch 的分支是你的 master 分支曾经指向的地方,再一次使得前两次提交可到达了。
7.打tag
Git 可以给历史中的某一个提交打上标签,以示重要。 比较有代表性的是人们会使用这个功能来标记发布结点(v1.0 等等)。
1 |
|
8.团队协作
- 项目经理初始化远程仓库
一定要初始化一个空的仓库,在GitHub上操作 - 项目经理创建本地仓库
git remote 别名 仓库地址(可选)
git init
将源码复制进来(项目内容)
修改用户名、邮箱git add .
git commit
- 项目经理推送本地仓库到远程仓库
清理windows凭据git push 别名/项目地址 分支名
(输入项目经理的github用户名和密码;推送完之后会附带生成远程跟踪分支) - 项目邀请成员 & 成员接受邀请
在GitHub上操作 - 成员克隆远程仓库
git clone 仓库地址
(在本地生成.git文件,默认为远程仓库配了别名 origin)
只有在克隆的时候,本地分支master和远程分支 别名/master 是有同步关系的 - 成员贡献代码
修改源码文件git add
git commit
git push 别名 分支
(输入成员的github用户名和密码;推送完之后会附带生成远程跟踪分支) - 项目经理更新修改
git fetch 别名
(将修改同步到远程跟踪分支上)git merge 远程跟踪分支
8.1正常的数据推送和拉取步骤
- 确保本地分支已经跟踪了远程跟踪分支
- 拉取数据:
git pull
- 上传数据:
git push