Git | 青训营笔记

97 阅读5分钟

为什么要学习Git

协同工作 业界绝大多数公司都是基于Git进行代码管理,因此Git是一个程序员的必备技能。 开源社区 目前绝大多数的开源项目都是基于Git维护的,参与这些项目的开发都需要使用Git。

Git是什么

分布式版本控制系统

是一种记录一个或若干个文件内容变化,以便将来查阅特定版本修订情况的系统

更好的关注变更,了解每个版本的改动是什么,方便对改动的代码进行你检查,预防事故的发生,也能够随时切换到不同的版本,回滚误删误改的问题代码。

历史

本地版本控制(如:RCS)

最初通过本地复制文件夹,来完成版本控制,一般可以通过不同的文件名来区分版本

解决方案:开发了一些本地的版本控制软件

基本原理:本地保存所有变更的补丁集,可以理解成就是所有的Diff,就是这些补丁,我们可以计算出每个版本的实际的文件内容

缺点:只能在本地使用,无法用于团队协作,使用场景非常有限

集中版本控制(如:SVN)

基本原理:提供一个远端服务来保存文件,所有用户的提交都提交到服务器中。增量保存每次提交的Diff,如果提交的增量中和远端现存的文件存在冲突,则需要本地提前解决冲突

优点:学习简单,更容易操作。支持二进制文件,对大文件的支持更好

缺点:本地不存储版本管理的概念,所有提交都只能连上服务器之后才可以提交。分支上的支持不够好,对于大型项目团队合作比较困难。用户本地不保存所有版本的代码,如果服务端故障容易导致历史版本的丢失。

分布式版本控制(Git)

基本原理:每一个库都存有完整的提交历史,可以直接在本地进行代码提交。每次提交记录的都是完整的文件快照,而不是记录增量。通过push等操作来完成和远端代码的同步。

优点:分布式开发,每个库都是完整的提交历史,支持本地提交,强调个体。分支管理功能强大,方便团队合作,多人协同合作。校验和机制保证完整性,一般只添加数据,很少执行删除操作,不容易导致代码丢失。

缺点:相对SVN更复杂,学习成本更高。对于大文件的支持不是特别好(git-lfs可以弥补这个功能)

Git的基本使用方式

项目初始化

mkdir demo
cd demo
git init

git init

  • --initail-branch 初始化的分支
  • --bare 创建一个裸仓库(纯git仓库,没有工作目录)
  • --template 可以通过模板来创建预先构建好的自定义git目录

通过tree .git可以观察git的目录文件

tree .git
卷 Data 的文件夹 PATH 列表
卷序列号为 00000045 5863:2318
D:\MYPROGRAMME\MYWEBPROJECT\GITSTUDY\DEMO\.GIT
├─hooks
├─info
├─objects
│  ├─info
│  └─pack
└─refs
    ├─heads
    └─tags

工作区&暂存区 在工作区完成之后,执行git add命令加到暂存区,再执行commit提交到git目录

配置

  • --global : ~/.gitconfig
  • --system : ${prefix}/etc/gitconfig
  • --local : .git/config

每个级别的配置可能会重复,但是低级别的配置会覆盖高级别的配置

用户名配置

git config --global user.name "XXX"
git config --global user.email "XXXXX@xxx.com"

Instead of 配置(做一些url替换)

git config --global url.git@github.com:.insteadOf https://github.com

Git命令别名配置

git config --global alias.cin "commit--amend --no-edit"

Git Remote

查看Remote

git remote -v

添加Remote

git remote add origin-ssh git@github.com:git/git.git
git remote add origin-http https://github.com/git/git.git

image.png

config中:

image.png

HTTP Remote

URL:github.com/git/git.git

免密配置

  • 内存:git config --global credential.helper 'cache --timeout=3600'
  • 硬盘:git config --global credential.helper "store --file /path/to/credential-file",不指定目录的情况默认是~/.git-credentials

将密钥信息存在指定文件中 具体格式:${scheme}://${user}:${password}@github.com

SSH Remote

URL:git@github.com:git/git.git

免密配置, ssh可以通过公私钥的机制,将生成的公钥存储在服务端,从而实现免密访问 key的四种类型:dsa,rsa(默认),ecdsa,ed25519(推荐)

image.png

配置过程

执行图片中的命令,会在.ssh中生成一个这样的文件

image.png 复制.pub文件中的内容,到github->setting->SSH and GPGkeys ->New SSH key

提交代码

Git Add

比如我们创建一个readme.md文件,在里面编辑“hello world”,之后执行git add . 命令添加到暂存区,会发现在.git的objects中新增了一个文件,我们使用

git cat-file -p <文件夹名+包含文件名的字符串>,来观察里面的信息,发现是我们的文件内容。

之后再执行git commit -m "add readme" 命令添加到仓库。发现.git的objects中新增了两个文件,同样的方式进行查看可以发现一个是blob的目录信息,另一个提交的信息(作者,提交者,提交备注等信息)

Objects

  • blob:存储文件的内容
  • Tree:存储文件的目录信息
  • Commit:存储提交信息

三者如何联系起来的呢?

  1. 通过Commit寻找Tree信息,每个Commit都会存储对应的TreeID
  2. 通过Tree存储的信息,获取到对应目录的目录树信息
  3. 从Tree中获得blob的id,通过blobid获取对应的文件内容

Refs

refs/heads/master中存储了最新的commitid

我们新建分支通过:

git checkout -b test
//切换到一个新分支“test”

refs的内容就是对应的commitid 因此把refs当作指针,指向对应的commit来表示当前ref对应的版本

Breach

git checkout -b 

可以创建一个新的分支 分支一般用于开发阶段,是可以不断添加Commit进行迭代的

Tag

标签一般表示的是一个稳定的版本,指向的Commit一般不会变更

通过git tag命令生成tag

Annotation Tag

一些特殊的Tag,可以给Tag提供一些格外的信息 通过

git tag -a v0.0.2 -m "add feature 1"

追溯历史版本

获取当前版本代码: 通过refs指向的commitid可以获取唯一的代码版本

获取历史版本的代码: Commit里面会存有,parent commit字段,通过commit的串联获取历史版本代码

image.png

commit --amend 可以修改最近的一次commit信息,修改之后commitid会变

修改后老的object没有ref指向它,为悬空commit 通过git fsck --lost-found来查找悬空commit ,通过Git GC删除不需要的object,以及对object进行打包压缩减少仓库的体积

指定时间 git gc prune=now指定的是修建多久之前的对象,默认是两周前

完整的git视图

image.png

远端同步

Git Clone & Pull & Fetch

image.png

Git研发流程

image.png