这是我参与「第三届青训营 -后端场」笔记创作活动的第6篇笔记
为什么要学习Git
- 协同工作 业界绝大多数公司都是基于Git进行代码管理
- 开源社区 目前绝大多数的开源项目都是基于Git维护的,参与这些项目的开发都需要使用Git
常见问题
- 入职后按照文档进行Git配置,但是配置后依然拉取代码有问题,缺少自己排查配置问题的能力
- 研发流程重进行一些异常操作,不符合研发规范,不清楚保护分支,MR/PR等概念
目标
- 学习基本的git命令,并了解原理,在遇到git相关问题时,能自行排查并解决
- 了解研发流程中的基本概念和规范,学会正确使用git
01.Git是什么
1.1 版本控制
- Git是什么? Git is a free and open source distributed version system (分布式版本控制系统) designed to handle everythingform small to very large projects with speed and efficiency.
- 版本控制是什么? 一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统 (记录每一次的版本变化)
- 为什么需要版本控制? 更好的关注变更,了解每个版本的改动是什么,方便对改动的代码进行检查,预防事故发生;
也能更好随时切换到不同的版本,回滚对代码的错误操作;
1.1.1 本地版本控制
- 最初的方案 通过本地复制文件夹,用自定义文件名区分不同版本
- 解决方案
开发了一些本地的版本控制软件,eg:
RCS - 基本原理 本地保存所有变更的补丁集,可以理解成就是所有的Diff,通过这些补丁,我们可以计算出每个版本的实际的文件内容
- 缺点 RCS 这种本地版本控制存在最致命的缺陷就是只能在本地使用,无法进行团队协作,因此使用的场景非常有限,因此衍生出了集中式版本控制
1.1.2 集中版本控制
- 代表工具:
SVN - 基本原理
- 提供一个远端服务来保存文件,所有用户的提交都提交到该服务器中
- 增量保存每次提交的 Dff,如果提交的增量中和远端现存的文件存在冲突,则需要本地提前解决冲突
- 优点
- 学习简单,更容易操作
- 支持二进制文件,对大文件支持更友好(游戏、美术公司)
- 缺点
- 本地不存储版本管理的概念,所有提交都只能联上服务器后才可以提交
- 分支上的支持不够好,对于大型项目团队合作比较困难
- 用户本地不保存所有版本的代码,如果服务端故障容易导致历史版本的丢失。
1.1.3 分布式版本控制
- 代表工具:
Git - 基本原理
- 每个库都存有完整的提交历史,可以直接在本地进行代码提交
- 每次提交记录的都是完整的文件快照,而不是记录增量
- 通过 Push (同步代码,在本地完成)等操作来完成和远端代码的同步
- 优点
- 分布式开发,每个库都是完整的提交历史,支持本地提交,强调个体
- 分支管理功能强大,方便团队合作,多人协同开发
- 校验和机制保证完整性,一般只添加数据,很少执行删除操作,不容易导致代码丢失
- 缺点
- 相对 SVN更复杂,学习成本更高
- 对于大文件的支持不是特别好(git-lfs工具可以弥补这个功能)
1.2 git发展历史
02.Git 的基本使用方式
2.1 Git 基本命令
- 配置
git configgit remote
- 提交代码
git addgit commit
- 远端同步
- 拉取代码
clonepullfetch
- 推送代码
push
- 拉取代码
2.2 常见问题
为什么明明配置了Git 配置,但是依然没有办法拉取代码?
没有配置密钥、没有权限
为什么我 fetch 了远端分支,但是我看本地当前的分支历史还是没有变化?
一方面git fetch只会下载远程的提交记录从而更新o/master,但不会更新本地的非远程分支。
项目初始化
mkdir study
cd study
git init
除init外其参数
默认初始化是进入master分支,但有些场景master不好,可以用
--inital-branch的初始化分支
--bare创建一个裸仓库(纯git目录,没有工作目录,与init区别:不允许进行添加文件操作)eg:在服务器上的仓库(本地仓库用git init)
--template可以通过模板预先构建好的自定义git目录
$ tree .git
bash: tree: command not found
windows 下没有tree命令,需要自己下载
解决方法:blog.csdn.net/Jioho_chen/…
安装检查:tree --version
| 文件名 | |
|---|---|
| HEAD | 表示当前指向的分支 |
| config | 当前git仓库的配置 |
| objects | 存一些文件信息 |
| refs | 存一些分支信息 |
2.1.1 Git Config
不同级别(全局、系统、本地)的 Git配置
每个级别的配置可能重复,但是低级别的配置会覆盖高级别的配置
2.1.2 常见Git 配置
2.2 Git Remote
查看Remote
git remote -v
添加Remote
ssh$ git remote add origin_ssh git@github.com:git/git.git
http$ git remote add origin_http https://github.com/git/git.git
错了怎么办 用
git remote -h查看用法场景:从开源库里面拉代码,在push到自己的仓库上,但是不想设置两个不同的origin,在同一个origin上实现功能
同一个Origin 设置不同的Push 和Fetch URL
add 一个push
2.2.1 HTTP Remote
不推荐用http来访问git,相对来说不安全,不方便。所有一般用SSH来连接远端仓库
2.2.2 SSH Remote
URL:git@github.com:git/git.git 免密配置 SSH 可以通过公私钥机制,将生成公钥存放在服务端,从而实现免密访问 目前的Key 的类型四种,分别是
dsa、rsa、ecdsa、ed25519默认使用的是rsa,由于一些安全问题,现在已经不推荐使用dsa、ras了,优先推荐使用ed25519若已经配置了公私钥,但还是不能够访问。是因为:新版windos已经不允许只是用dsa和rsa,直接拒绝访问
公私钥的配置
1. 生成
ssh-keygen -t ed25519 -C "zuo199911@qq.com"
ssh-keygen 生成ed25519类型的key输入自己的邮箱
2. 查看
cat /c/Users/DELL/.ssh/id_ed25519.pub
3. 复制,存到git上
- 添加就好,title自己取 key粘贴刚刚cat后打出来的内容
可以配置多对公私钥,通过修改ssh里面的设置来指定你需要的公私钥
2.4 Git Add
工作区的内容,通过git add .来添加到暂存区
通过tree .git来观察变化
e6 9d.....连起来就是它(readme.md)的object id
通过git cat-file -p 文件id查看文件内容
id由两部分组成
git add .只是存到暂存区,再通过git commit -m "add readme"提交到真的git目录中
再通过tree观察objects目录的变化
git cat-file -p 具体id
查看具体内容
commit后会新增两个文件,一个存放目录数,另一个存放tree、author、committer等信息 通过
git log查看最新commmit就是刚刚的内容
2.5 Object
commit / tree /blob 在 git 里面都统一称为 Object,除此之外还有个 tag 的object,下面我们将分别介绍
- Blob 存储文件的内容
- Tree 存储文件的目录信息
- Commit 存储提交信息,一个Commit可以对应唯一版本的代码
如何将三者串起来? 1. 通过commit 寻找 Tree 信息,每个Commit 都会存储对应的Tree ID
2. 通过Tree 存储信息,获取到对应的目录树信息
3. 通过commit 寻找 Tree 信息,每个Commit 都会存储对应的Tree ID
2.6 Refs
refs下存的是master的commit信息
创建一个分支git checkout -b test
cat .git/refs/head/test内容和master分支下一致
Refs 文件存储的内容
refs 的内容就是对应的 Commit ID
因此把 ref 当作指针,指向对应的Commit 来表示当前 Ref 对应的版本
不同种类的 ref
refs/heads 前缀表示的是分支,除此外还有其他种类的 ref ,比如 refs/tags 前缀表示的是标签
Branch
git checkout -b 分支名可以创建一个新分支
分支一般用于开发阶段,是可以不断添加 Commit 进行迭代的
Tag
标签一般表示的是一个稳定版本,指向的Commit 一般不会变更,要迭代、要发布版本用tag
通过git tag命令生成tag
Annotation Tag
什么是附注标签? 一种特殊的 Tag,可以给 Tag 提供一些额外的信息。 如何创建附注标签? 通过
git tag -a命令来完成附注标签的创建。
查看该 tag object 的内容
object 后存放的是真正指向的commit ID,会附带一些信息,谁打的附属标签、标签名字,massage的内容
tag v0.0.2
add feature 1
小结
管理代码的四种object
- Blob 存储文件的内容
- Tree 存储文件的目录信息
- Commit 存储提交信息,一个Commit可以对应唯一版本的代码
- tag 标签一般表示的是一个稳定版本,指向的Commit 一般不会变更,要迭代、要发布版本用
2.8 追溯历史版本
- 获取当前版本代码 通过ref 指向的commit 可以获取唯一的代码版本。
- 获取历史版本代码 commit 里会有存 parent commit 字段,通过commit 的串联获取历史版本代码
关联方式
2.9 修改历史版本
方式一 commit --amend 通过这个命令可以修改最近一次 commit 信息,修改之后 commit id 会变
方式二 rebase (功能强大) 通过
git rebase -i HEAD~3可以实现对最近三个commit 的修改:
1. 合并commit
2. 修改具体的 commit message
3. 删除某个 commit
方式三 filter --branch 该命令可以指定删除所有提交中的某个文件或者全局修改邮箱地址等操作
2.10 Objects
新增的Object
2.11 Git GC
2.13 Git Clone && Pull && Fetch
- Clone 拉取完整的仓库到本地目录,可以指定分支,深度
- Fetch 将远端某些分支最新代码拉取到本地,不会执行merge 操作,
会修改refs/remote 内的分支信息,如果需要和本地代码合并需要手动操作。
- Pull
近似于:
git fetch+git merge,拉取远端某分支,并和本地代码进行合并。
也可以通过git pull --rebase 完成 git fetch + git rebase 操作
可能存在冲突,需要解决冲突
2.14 Git Push
Push 是将本地代码同步至远端的方式
- 常用命令
一般使用
git push origin master命令即可完成 - 冲突问题 1.如果本地的commit记录和远端的 commit 历史不一致,则会产生冲突,比如git commit--amend or gitrebase 都有可能导致这个问题。
2.如果该分支就自己一个人使用,或者团队内确认过可以修改历史则可以通过 git push origin master -f来完成强制推送,一般不推荐主干分支进行该操作,正常都应该解决冲突后再进行推送。
02.2 常见问题 回复
为什么明明配置了Git 配置,但是依然没有办法拉取代码?
- 免密认证没有配
- instead of 配置没有配,配的 SSH 免密,但是使用的还是HTTP 协议访问。
没有配置密钥、没有权限
为什么我 fetch 了远端分支,但是我看本地当前的分支历史还是没有变化?
- Fetch 会把代码拉取到本地的远端分支,但是并不会合并到当前分支,所以当前分支历史没有变化。