尚硅谷最新Git教程全套完整版(12h带你深入掌握Git)【笔记】

背景

虽然一直在用 Git,但是实际只会一些基础操作,并不理解其中的原理,随着工作的时间越来越长,感觉对 Git 的深入理解越来越有必要。

视频时间

版本信息

视频版本:Git version 2.19.1.windows.1

笔记版本:Git version 2.26.0.windows.1

1. Git 操作

版本控制

版本控制分为集中式(SVN)和分布式(Git)两种;

  • 集中式(SVN):
    SVN 每次存的都是差异,需要的硬盘空间会相对的小一些,可是回滚的速度会很慢
  • 优点:
    代码存成在单一的服务器上,便于项目的管理
  • 缺点:
    服务器宕机:员工写的代码得不到保障
    服务器炸了:整个项目的历史记录都会丢失
  • 分布式(Git)
    Git 每次存的都是项目的完整块照,需要的硬盘空间会相对大一点
    Git 团队对代码做了极致的压缩,最终需要的实际空间比 SVN 多不了多少,可是 Git 的回滚速度极快

Git 初始化配置

在 Windows 中,

system 级别的配置文件位于 C:\Program Files\Git\etc\gitconfig

global 级别配置文件位于 ‪C:\Users\80953\.gitconfig

项目的配置文件位于为 .git\config

## 查看帮助信息
git --help
## 查看 Git 版本
git --version
## 查看 Git 配置信息
git config --list
## 配置全局用户信息
git config --global user.name "hwj"
git config --global user.email "hwj@github.com"

##	配置别名
git config --global alias.lol 'log --oneline --decorate --graph --all'

Git 底层概念(底层命令)

基础的 Linux 命令

* clear 清除屏幕
* echo 'hello word '>test.tet 命令台书写内容
* ll 将当前目录下的子目录展现出来
* find ./ 将当前目录下的子目录以及文件也展现出来
* find ./ -type f 只讲文件展现出来
* rm text.txt 删除文件
* mv a.txt b.txt 更名字
* cat a.txt 查看文件内容
* vim a.txt 编辑内容 
	i 插入 
	o 插入新行
	ese 进入命令模式
	:wq 保存退出 
	:set nu 显示行号 
	:q! 强制退出不保存

项目的 .git 目录

## 初始化仓库
git init
  • hooks (钩子函数的一个库 类似于回调函数)
  • info (包含一个全局性的排除文件)
  • logs (日志信息)
  • objects (目录存储所有数据内容)
  • refs (目录存储指向数据(分支)的提交对象的指针)
  • config (文件包含项目特有的配置选项)
  • description (显示对仓库的描述信息)
  • HEAD (文件目前被检出的分支)
  • index (文件保存暂存区的信息)

git 对象

Git 的核心部分是一个简单的键值对数据库。你可以向该数据库插入任意类型的内容,它会返回一个键值,通过该键值可以在任意时刻再次检索该内容。

#	hash-object
##	向数据库写入内容,并返回对应键值
###	返回的键值,前2位为文件夹名称,后38位为文件名称
### -w 指示存储数据对象,不指定则不存储,只返回键值
### --stdin 指示从标准输入读取内容,不指定则需要在命令尾部给出存储文件的路径
$ echo 'test content' | git hash-object -w --stdin
d670460b4b4aece5915caf5c68d12f560a9fe3e4

## Git 存储文件
$ git hash-object -w a.txt
190a18037c64c43e6b11489df4bf0b9eb6d2c9bf

## 查看 Git 存储的对象
$ find .git/objects/ -type f
.git/objects/19/0a18037c64c43e6b11489df4bf0b9eb6d2c9bf
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4

#	cat-file
##	查看任意对象
##	根据键值拉取数据,键值不需要完整,只要前面几位就可以
### -p 指示自动判断文件类型,并为我们显示格式友好的内容
### -t 查看文件类型
$ git cat-file -p d670460b4
test content
$ git cat-file -t d670460b4
blob

以上所有操作都是在对本地数据库进行操作,不涉及暂存区

上述操作存在的问题:

  • 记住文件的每一个版本对应的 SHA-1 值并不现实
  • 在 Git 中,文件名并没有被保存,我们仅保存了文件的内容

解决方案:树对象

tree 对象

树对象,它能解决文件名保存的问题,也允许我们将多个文件组织在一起。Git 以一种类似于 UNIX 文件系统的方式存储内容。所有内容均以树对象和数据对象(Git 对象)的形式存储,其中树对象对应了 UNIX 中的目录项,数据对象(Git 对象)则大致上对应文件内容。

一个树对象包含了一条或多条记录(每条记录含有一个指向 Git 对象或者子树对象的 SHA-1 指针,以及相应的模式、类型、文件名信息)。

一个树对象也可以包含另一个树对象。

#	ls-files
##	查看暂存区当前的样子
$ git ls-files -s

#	update-index
##	更新索引
##	只是为 Git 对象起一个名字,不生成任何对象,需要指定已生成对象的 hash,否则 write-tree 时会报错;但文件名称不需要与实际文件相同
##	相同文件如果已存在缓存区中,更新后再生成对象、更新索引,缓存区中会更新为更新后的文件
### 文件模式为100644 表明这是一个普通文件
### 文件模式为100755 表明这是一个可执行文件
### 文件模式为120000 表明这是一个符号连接
### --add 因为此前该文件并没有在暂存区中 首次要加add
### --cacheinfo 因为要添加的文件在git数据库中,没有位于当前目录下
git update-index --add --cacheinfo 100644 915c628f360b2d8c3edbe1ac65cf575b69029b61 test.txt

##	将文件添加为 Git 对象,并更新索引
##	hash-object + update-index
git update-index --add new.txt

#	write-tree
##	暂存区做一个快照生成一个对象放到git数据库中
##	对象类型是一个树对象
##	树对象里面的内容是暂存区的快照(项目的快照)
##	暂存区中文件名字不变 如果改变文件的内容,就会重新生成一个hash
git write-tree

#	rm
##	删除操作
###	-f 指示强制删除
###	--cached 指示删除的是缓存区中的内容
$ git rm -f --cached a.txt
rm 'a.txt'


#	read-tree
##	将一个树对象读入暂存区
$ git read-tree --prefix=bak 58e6d12d1bf385222144538d11ef7714c87da3b4

存在的问题:

  • 不知道 hash 值对应的是哪一个版本
  • 不知道这个树对象快照的一些基础信息

这些,正是 提交对象 能为你保存的基本信息

commit 对象

#	git commit-tree
##	本质就是给树对象做一层包裹包含项目的基础信息
##	commit-tree 创建一个提交对象,为此需要指定一个树对象的hash值,以及该提交的父提交对象
###	-p 用来指定父提交对象
echo "first commit" | git commit-tree 019fb2c522b604cd94929085bbac93d60e2f2063

echo "second commit" | git commit-tree e8d77cd21e29ba9a511f129a8b908afc2151bb3b -p f0d25e23b9a52c992f3eab8e4fb8ed6973f670c1

commit-tree 不但生成提交对象,而且会将对应的快照(树对象)提交到本地库中

真正代表一个项目的是一个提交对象(数据和基本信息)这是一个链式的!!

Git 本地操作(高层命令)

Git 中的区域

  • 工作区
  • 暂存区
  • 版本库

工作目录中的文件状态

  • 未跟踪(untracked)
  • 已跟踪
  • 已提交(未修改)(unmodified)
  • 已修改(modified)
  • 已暂存(staged)

尚硅谷 spark 安装_远程分支

高层命令

#	add
##	将修改添加暂存区
##	先到版本库,再到暂存区
##	hash-object + update-index
git add ./


#	commit
##	提交
##	生成一个树对象,一个提交对象
##	write-tree + commit-tree
### -m 指示描述信息
git commit -m "first commit a.txt v1" a.txt
###	-a 跳过 add 过程,将所有暂存一起直接提交,后面不能跟文件或目录;文件必须处于已跟踪状态
### -a 适用于修改了文件内容,不适用于新建文件的提交
git commit -am "m 1"


#	status
##	检查当前文件状态
git status

#	restore
##	add 的反操作,将文件从暂存区移除
##	仅移除暂存区,对象仍然存在,工作目录中的文件仍然存在
##	作用等同于 rm --cached
git restore --staged c.txt

#	diff
##	查看已暂存和未暂存的更新
###	不加参数,与暂存区中的比较
###	--cached 指示与已提交的比较
###	--staged 同 --cached
git diff a.txt

#	rm
##	删除文件
##	rm + git add
git rm a.txt

#	mv
##	文件改名
##	mv + git add
git mv b.txt bb.txt

#	log
##	查看历史记录
###	--oneline 指示简化日志显示
git log --oneline
###	查看完整的分支图(没删除前)
git log --oneline --decorate --graph --all

#	reflog
##	查看 HEAD 的操作日志
##	比完整分支图更详细的日志信息
git reflog

Git 分支操作(杀手功能)

分支的本质是指向提交对象的可变指针。

HEAD 的本质是一个指针,默认指向 master 分支,切换分支就是让 HEAD 指向不同的分支。每次有新的提交时,HEAD 就会带着当前指向的分支,一起向前移动。

##	查看分支列表
git branch
##	查看所有分支最后一个提交
git branch -v

##	在当前的提交对象上创建一个分支 test
git branch test
##	在指定提交对象上新建一个分支
git branch test hashcode

##	切换分支
git checkout test
##	创建分支并且切换过去
git checkout -b test
## 检出远程分支到本地分支
git checkout -b dev(本地分支名) origin/dev(远程分支名)

##	删除分支
###	删除已合并分支
git branch -d test
###	强制删除分支,不管是否合并
git branch -d test

##	合并分支
git merge test

##	查看合并到当前分支的分支
git branch --merged
##	查看没有合并到当前分支的分支
git branch --no-merged

分支切换会改变你工作目录中的文件

切换分支的时候一定要提交完的时候再切否则会出现问题

每次切换分支前当前分支一定要是已提交状态,否则会污染主分支,如果第一次提交了再修改的时候没有提交他就不让切换分支了

最佳实践:每次切分支时,使用 git status 保证分支是干净的。

分支合并

合并分支分为快进合并典型合并

快进合并不会产生冲突

Git 存储

解决的问题:

不希望因为切换分支过多的创建提交

Git 存储是栈结构,先进后出

#	stash
##	创建存储
git stash

## 将栈顶存储移出,并恢复存储
git stash pop

##	查看存储列表
git stash list

##	恢复存储,不移除出栈
##	不指定则默认为栈顶存储
git stash apply stash@{1}

##	将存储在栈中删除
##	不指定则默认为栈顶存储
git stash drop stash@{2}

撤销&重置(后悔药)

##	工作区撤销修改
##	会修改文件内容
##	从已修改状态改变为未跟踪状态
git restore e.txt
git checkout -- e.txt

##	暂存区撤销修改
##	缓存区内容被修改,不改变文件内容
##	从已暂存状态改变为未跟踪状态
git restore --staged f.txt
git reset HEAD f.txt

##	版本库撤销修改
###	修改提交注释
git commit --amend

重置 reset

#	reset
##	撤销一次提交
##	动HEAD(带着分支一起移动);不动暂存区和工作目录;文件内容不变
##	文件状态从已提交改为已暂存
git reset --soft HEAD~

##	动HEAD;动暂存区;文件内容不变
##	文件状态从已提交改为已修改
git reset [--mixed] HEAD~

##	动暂存区;动文件内容
git reset --hard HEAD~

git checkoutgit reset --hard 区别:

  • checkout 制动 HEAD;reset --hard 动 HEAD,而且带着分支一起走
  • checkout 对工作目录是安全的;reset --hard 是强制覆盖工作目录

git checkout -- filename 只动工作目录,不动 HEAD 和暂存区

git checkout commitHash filename 动工作目录和暂存区,不动 HEAD

数据恢复

##	1. 通过命令查找要恢复的提交 hash
git reflog
git log -g

##	2. 使用两种方式恢复数据
###	2.1. checkout(更常用)
git checkout 分支名称 hashcode
###	2.2. reset
git reset --hard hashcode

Tag 功能

Git 可以给历史中的某一个提交打上标签,以示重要。

#	tag
##	列出标签
git tag
##	正则匹配
git tag -l "v1*"

##	为提交对象打上 tag
git tag v1.0 [commitHash]

##	查看特定 tag
git show v1.0

##	删除标签
git tag -d v3

##	检出 tag
##	会导致头部分离,可以找到 tag 指向的提交对象后,检出为分支
git checkout v1.0
git checkout -b v1.0c dee383a

Git 特点

  • 直接记录快照,而非差异比较
  • 近乎所有操作都是本地执行
  • 时刻保持数据完整性
  • 多数操作仅添加数据
  • 文件的三种状态
  • 已提交(committed)
  • 已修改(modified)
  • 已暂存(staged)
  • Git 管理项目时,文件流转的三个区域
  • 工作目录
  • 暂存区域
  • 本地仓库

2. 远程仓库

#	remote
##	添加远程分支
git remote add tg https://github.com/liuxing5yu/testGit.git

##	重命名远程分支
git remote rename old new 

##	删除远程分支
git remote rm b1

##	查看远程分支
git remote -v

#	push
##	将 master 分支推到远程仓库
git push tg master

#	clone
##	克隆远程仓库
git clone https://github.com/liuxing5yu/testGit.git

#	fetch
##	拉取远程仓库更新
git fetch [tg]

##	合并远程分支
git merge tg/master

##	fetch 后出现新的远程分支时,在本地创建对应的本地分支
git checkout -b cb tg/cb
git checkout --track tg/b1

##	设置本地分支与远程跟踪分支同步
##	同步后可以直接执行 git push、git pull
git branch -u tg/master

##	查看设置的所有跟踪分支
git branch -vv

##	同步后,推送提交到远程仓库
git push
##	同步后,拉取远程更新到本地仓库
git pull


# 没有远程分支,本地已切换到 test2 分支
# 操作后,远程会创建 test2 分支,本地分支将会推送到远程
git push --set-upstream origin test2


# 本地分支关联远程分支
# git branch --set-upstream-to=origin/remote_branch local_branch
git branch --set-upstream-to=origin/remote_branch
# 解除关联
git branch --unset-upstream
  • 可以在 Windows 的【凭据管理器|Windows 凭据】,删除已有的 GitHub 凭据
  • 在 GitHub 仓库的【Settings|Manage access】中可以邀请合作者
  • fetch 后需要 merge 远程分支;如果 fetch 后出现了新的远程分支,需要先建立本地分支,再合并远程分支
  • 远程协作是存在 本地分支,远程跟踪分支,远程分支
  • 远程跟踪分支 是远程分支状态的引用。它们是你不能移动的本地分支。当你做任何网络通信操作时,它们会自动移动。
  • push 和 clone 时,生成远程跟踪分支
  • 当克隆一个仓库时,它通常会自动创建一个跟踪 origin/mastermaster 分支

解决远程协作冲突

  1. push 冲突
    先 pull,解决冲突后,再 push
  2. pull 冲突
  1. 先提交到本地,然后 push,会产生 push 冲突,之后解决方法如上
  2. 先 stash ,后 pull,stash pop,解决 pop 后的冲突

删除远程分支

##	删除远程分支
git push origin --delete b1
##	列出仍在远程跟踪但是远程已被删除的无用分支
git remote prune origin --dry-run
##	清除上面命令列出的远程无用分支
git remote prune origin

pull request 流程

GitHub 上操作 pull request 流程,提交后,等待被合并后关闭

.gitignore 文件

可以在 .gitignore 文件中列出要忽略的文件模式

.gitignore 参考写法

.gitignore 的格式规范:

  • 所有空行或者以注释符号开头的行都会被Git忽略。
  • 可以使用标准的glob模式匹配。
  • * 代表匹配任意个字符
  • ? 代表匹配任意一个字符
  • ** 代表匹配多级目录
  • 匹配模式前跟反斜杠 / 代表项目根目录
  • 匹配模式最后跟反斜杠 / 说明要忽略的是目录。
  • 要忽路指定模式以外的文件或目录,可以在模式前加上惊収号 ! 取反。

SSH

##	验证用户时走的不是验证密码的道路而是密匙
##	在 C:\Users\用户名\.ssh 下生成公私密匙
ssh -keygen -t rsa -C "邮箱"

##	在 GitHub 上添加 SSH keys

##	测试是否成功
ssh -T git@github.com
  • 在 GitHub 的【Personal settings | SSH and GPG keys】里可以添加 SSH keys

3. Git 操作补充

git submodule

git 主库和子库之间的关系:

  • git 主库拥有一个指向子库某一次提交的指针,更新指针需要 push 主库
  • git 子库是独立的,git 子库的修改不影响 git 主库的 push
  • 如果要操作子库,需要将目录路径从主库切换到子库,切换之后的操作只体现在子库,与主库无关
# 添加子库
git submodule add https://gitee.com/liuxing5yu/git-sub

# 加 -f 参数表示强制删除,即使子库中存在修改内容
# 字库删除后,本地文件
git submodule deinit -f git-sub/
git rm git-sub

# 检出存在子库的 git 库
git clone --recurse-submodules https://gitee.com/liuxing5yu/git-main