进化论-Git的使用

版本控制(Revision control)是一种在开发的过程中用于管理我们对文件、目录或工程等内容的修改历史,方便查看更改历史记录,备份以便恢复以前的版本的软件工程技术。

一. git简介

git是一个分布式的,用于版本控制的系统/软件,由Linus使用C在两周内编写出最初版本,特点:

  1. git采用分布式,所以没有中心节点,每个clone都是一个完整的版本库,git的server只是方便交换修改;
  2. git更加强调个体,在单机上可以创建分支,修改代码,合并分支等;

1.1 构成

git本质上时一个基于键值对的文件系统,一个文件系统由文件和文件夹/目录组成;

git整体划分为三种结构:

image-20210813215556152

仓库/版本库 Repository:一个被git所管理的目录,任何的变动都会被记录,保存所有的commit;

工作区 Working Directory:仓库中除了隐藏的.git文件夹的其他空间,区内文件用户可编辑/查看;

暂存区 Stage/Index:暂存工作区的变化并用于提交/回退/暂存等,Stage赋予Git更多灵活性,

1.2 数据存储

image-20210813215721658

git中主要有3种对象,stage及commit区的所有对象实际上都存储于objects中:

blob:文件系统中的文件,SHA-1文件内容为blob对象名/key,文件内容为blob对象的值/value;

  1. blob只存文件内容,不存文件名,文件名为在tree指向blob的mapping中的备注;
  2. 所以当一个文件的内容改变后,会额外生成一个blob对象,但是名字改变不会新增blob;

image-20210813200826893

tree:文件系统中的文件夹,SHA-1计算生成tree对象名,tree里存放着与tree/blob的映射关系:

  1. tree在提交的时候生成,stage中仅映射至blob的对象;
  2. tree的SHA-1值,依赖内部的映射管理来生成,比如变更其内部文件名也会改变其SHA-1值;

image-20210813201747429

commit:对文件系统当前状态的一次封装,里面有tree-对应文件系统,父提交-上一级commit对象,author的信息,committer的信息,msg等;

image-20210813202924801

commit/tree/blob对象间的关系:

image-20210813203012237

blob/tree/commit对象在objects中的存储:

  1. 三个对象均使用SHA算法来生成40位key,并使用前2位作为文件名来分类存储对象;

image-20210813203756039

  1. pack中存放压缩后数据,可以使用git gc 来生成,包含共两个文件:
    • .idx文件是.pack文件中的三对象列表及其偏移量,可以基于这两个文件提取所有的三对象;
    • 在push与gc的时候生成,gc/push时只会打包被最新commit或stage所引用的对象,其他对象保留在本地,可以使用–prune=now参数或git prune --expire=0来清除;

image-20210813211207638

image-20210813211241651

1.3 整体的抽象

git 模型可以抽象为:

  1. 本地三级仓库之level1——working directory
  2. 本地三级仓库之level2——stage(index)
  3. 本地三级仓库之level3——repository(History)
  4. 远程移机仓库之level4——remote

git使用命令来实现各个仓的数据转移

等级 低level输入 高level输入
Working directory-lv1 手工创建 Git checkout/git stash
Stage/index-lv2 git add git reset
History/repository-lv3 git commit git pull
Remote-lv4 git push -

1.4 Git存储文件的方式

git使用快照流的方式来保存各个版本的文件:

  1. 如果文件没有修改,则不会产生新的blob对象,则新版本的这个文件仍指向之前的blob对象;
  2. 如果文件发生修改,则会产生新的blob对象,如A1,较A是一个全新的文件,没有关联;

image-20210815231032296

二. git的使用

2.1 git仓库的初始化

配置当前系统/仓库的编辑者信息-签名

与github或gitee(代码托管中心)的账号没有关系.

# 安装好git后,需要配置当前系统的信息-自报家门
# 这个与登录github的账号没有半毛钱关系
git config --global user.name "Bruce"
git config --global user.email "bruce@gmail.com"
# 如果不带--global则是为每个本地库配置user信息,优于global
git config user.name "alvin"
git config user.email "alvin@gmail.com"

初始化一个仓库

mkdir pt_git
cd pt_git
git init # 仓库的初始化

最直接的效果是创建了一个.git的目录

.git目录中存放的是本丢相关的子目录和文件,不要删除或修改;

image-20210815194310900

image-20210815194810469

image-20210815194927063

2.2 git命令图解

2.2.1 临近等级间的切换

image-20210813215835651

git add file:把文件file放入stage,.代替所有,支持多个文件,支持*匹配字符等;

git commit:把stage中文件生成快照并提交,建议添加 -m参数,为此次提交生成msg注释;

git reset:撤销Stage中file文件(带 --file参数 ),或者撤销所有(不带参数);

git checkout --file:复制stage的文件到working目录,撤销修改,还可用于分支的切换;

可以使用 git reset -p,git checkout -p,git add -p进入交互模式。

2.2.2 跨等级间的切换

image-20210813221324459

git commit -a:直接将工作目录被track的文件(当前commit中存在)&暂存区的文件提交;

git commit files:将stage中的指定file提交;

git checkout HEAD -- files:将working目录及stage中的files全部还原为上次提交时;

2.2.3 diff比较文件

image-20210813223615327

2.2.4 rm删除文件

git rm file.txt:working目录与stage中同时删除该文件,带 -r参数可以删除目录;

git rm --cached filexample.txt:从stage中删除文件,working目录保存;

2.2.5 stash临时保存

git stash [save] [message]:临时保存,只有git stash也可以,只是不方便查找

git stash list:查看stash了哪些存储

git stash show[stash@{1}] [-p]:显示stash与当前的区别,-p更加具体,指定某个stash

git stash apply [stash@{1}]:取到某个stash,不删除stash;

git stash pop [stash@{1}]:取到某个stash,同时删除stash;

git stash drop[stash@{1}] :删除某个stash,不取出;

git stash clear:清除所有暂存;

git stash –keep-index:忽略modify已经提交到stage的忽略,复原其他的至本地库分支位置

三. git的操作

3.1 添加与提交

Git status 作用:显示目前git的状态,工作目录在哪个分支,本地库有没有commit,stage中是否有文件,是否有可操作的文件;

# 进入空目录
cd WeChat
git status

空目录中的显示在主分支/无history/无stage内容

image-20210815195312620

# 创建一个文件并add
vim good.txt
111111
222222
# 查看状态
git status

其他不变,但显示有未被git所追踪的文件,可以使用git add <file>来添加到暂存区;

未track的文件只能使用git add来添加,而没法直接使用git commit -a命令来添加,区别于编辑已被track的文件;

image-20210815195843715

# 按照提示添加
git add good.txt

good.txt已经被添加到stage且变为绿色,并告诉你可以使用git rm --cached <file>回退上一状态

image-20210815200028086

# 提交到本地库
git commit
# 会进入一个vim类型的交互页面,填写一个commit的msg,或者可以直接用 -m参数来带
git commit -m "Wechat's first commit"

master分支的第一次提交/ID/MSG及变更的信息:1个文件修改,2行内容新增,创建一个good.txt;

image-20210815200540725

提交后的状态:

image-20210815200919459

# 修改文件后
vim good.txt
333333
git status

区别于新建,git add现在起update作用非track,同时可以使用git commit -a直接提交

image-20210815201431482

git add good.txt

image-20210815201707380

git commit -m "My second commit,modify good.txt"

第二次提交不会提示root-commit

image-20210815201936964

3.2 前进与后退

git log 作用:显示所有的commit的信息;

git log

image-20210815202839753

git log --pretty=oneline # 美化下显示
git log --oneline # SHA的值会更短

image-20210815203130355

git reflog # 比Git log多显示了一个相对于HEAD的移动量

image-20210815203431253

版本的操作本质上是操作HEAD指针,HEAD指针的前进与后退会影响目前的stage或working区域:

git reset --hard 614f781 # 退回777版本

HEAD的指针跟随移动了/working与stage目录都退回HEAD指向的commit版本

image-20210815203743903

git reset --hard 5c6760b # 前进888版本

image-20210815204004671

git reset --hard HEAD^ # 回退一个版本, 每个^会回退一个版本

image-20210815204111005

git reset --hard HEAD~4 # 相对于当前HEAD移动4步
git log # 只能查看当前HEAD之前的commit,之后的看不到
git reflog # 可以查看所有

image-20210815204213843

git的三个参数

git reset --soft # 仅仅移动本地库的指针
git reset --mixed # 移动本地库及stage的指针
git reset --hard # 移动本地库及stage及working的指针
git reset --soft HEAD^

image-20210815204725994

git reset --mixed HEAD^

image-20210815204817526

3.3 文件的删除与找回

# 新增文件
vim apple.txt
aaaa
git add apple.txt
git commit -m "new apple.txt"

# 删除文件
rm -rf apple.txt
git add apple.txt
git commit -m "del apple.txt"

# 恢复文件
git reset --hard 7b1b32c

image-20210815210216015

# 只针对stage区域时
git reset --hard HEAD # 即可以使用HEAD指向的位置来恢复

image-20210815210428473

3.4 文件的比较

git diff <file># working与暂存区的比较
git diff HEAD <file> # 与本地库HEAD的commit比较
git diff 5c6760b <file> # 与历史版本的commit比较
# 如果不带file表示比较所有文件

image-20210815210950558

3.5 分支的操作

image-20210815211155955

分支的好处:

  1. 同时并行推进多个功能开发,提高开发效率;
  2. 各个分支在开发过程中,如果某个分支开发失败,不会对其他分支有影响;
# 创建分支
git branch -v # 查看分支
git branch hot_fix # 创建分支
git branch -d hot_fix # 删除分支
git branch -v # 查看分支

image-20210815211557373

git checkout hot_fix

image-20210815211652818

# 修改host_ifx分支的修改
vim good.txt
....
git commit -a -m "edit good.txt add host_ifx"
# hot_ifx领先master分支版本

image-20210815211918335

# 合并分支
# 1. 切换到接收修改的分支上-被修改的分支
git checkout master
# 2. 执行merge命令
git merge hot_ifx

image-20210815212316008

# 在hot_ifx上编辑good的第8行
git checkout hot_ifx
vi good
git commit -a -m "edit good.txt line 8 by hot_ifx"
# 在master上编辑good的第8行
git checkout master
vi good
git commit -a -m "edit good.txt line 8 by master" # 此时commit不能提交
# 在master分支上合并
git merge hot_ifx
# 产生冲突

image-20210815230208765

image-20210815230313394

image-20210815223914938

# 修复冲突
vi good.txt # 查看产生冲突的文件

<<<<<<< HEAD .... ========:当前分支这一块的内容

======= ..... hot_ifx >>>>>>>:被合并分支这一块的内容

image-20210815224119684

# 删除特殊符号,选择保留的行,或者同时修改
vi good.txt

image-20210815224436654

# 在解决冲突模式下add文件至stage
git add good.txt
# 在解决冲突模式下提交
git commit -m "merge master & hot_ifx"

image-20210815224554650

四. git与github/gitee

4.1 同一term的协作

同一Term间的协作:

image-20210815232933953

# 在github或gitee上创建创库
# 获取仓库的http地址/ssh地址-http://gitee.com/bruce/bbb.git
# 新建一个remote,别名为orgin,地址为...
git remote add origin http://gitee.com/bruce/bbb.git 
# 查看当前可用远程库地址
git remote [-v]

image-20210815233656754

# git推送参数为,origin-remote别名,master-想要推送的分支
git push origin master

image-20210815233927401

# 另一个团队内成员将文件clone到本地
git clone https://gitee.com/Bruce_Amadeus_Lee/practice_git.git
# 效果:
# 1. 完整的将远程库下载到本地
# 2. 创建origin远程地址别名
# 3. 初始化本地库
# push = fetch + merge
# 1. fetch将远程库下载到本地称为远程地址/分组名
# 2. 使用merge将origin/master合并到本地库的master
git fetch origin master # 远程地址别名 + 分支名

image-20210815235208672

image-20210815235118036

4.2 同一term的冲突解决

当gitee上的master分支的同一文件同一位置被修改后,push操作将失败,如下图:

image-20210815235718515

需要先pull(fetch + merge)后,修复conflict,然后add/commit/push即可;

image-20210816000210502

4.3 跨团队协作

1. 其他团队的C,fork当前库到自己的远程库
2. 其将远程库下载到本地并完成修改后,push到自己的远程库;
3. 在gitee上发起pull-request;
4. master分支拥有人在线审核这个pull-request的代码;
5. 选择merge完成合并;
  1. 其他团队首先forked这个项目到自己的仓库里面

image-20210816102017230

  1. 然后clone到本地
git clone https://gitee.com/alvin-apple/practice_git.git

image-20210816102403204

  1. 本地修改后,其他团队推送到自己的远程库

image-20210816103448476

  1. 其他团队向原项目拥有人发起request pull;

image-20210816104322416

  1. bruce在pull-request可以看到;

image-20210816105211733

  1. bruce审核与测试

image-20210816105259661

  1. bruce选择merge

image-20210816105531416

  1. 完成整体的合并

image-20210816105625321

4.4 跨团队pull-request冲突解决

当有人给你的项目贡献代码,但他修改的地方你在之前也修改了,conflict产生。

当其他人给我们代码的pull-request与我的master/其他分支当前代码冲突时,gitee/github无法自动merge,需要人工干预;

# 在bruce/master(我们自己的仓)下,创建分支
git branch alvin-master [master] # 新建alvin-master分支并指向本地库的master
git branch -v | cat
git checkout alvin-master # 上面两条可以使用 git checkout -b alvin-master master

image-20210816152720954

# 拉取alvin的practice_git的远程库
git pull https://gitee.com/alvin-apple/practice_git.git master
# 提示冲突,进入手工merging状态

image-20210816152914030

# 编辑文件解决冲突
vi pp.txt
git add pp.txt # mark resolution
git commit -m "resolve conflict with alvin" # 提交至分支,冲突解决,alvin-master合并远程库成功;

image-20210816153121485

# 切换至master并合并alvin-master分支
git checkout master
git merge alvin-master
git status

image-20210816153151276

# 将本地master分支推送至别名为origin的远程库
git push origin master

参考:

博客园-深入浅出Git教程(转载)

博客园-Git图解剖析

廖雪峰的官方网站-Git教程

posted @ 2021-08-16 15:36  FcBlogs  阅读(68)  评论(0编辑  收藏  举报