学习笔记:Git(尚硅谷)

介绍

  • 本文主要记录在学习尚硅谷的 Git 课程时的一些笔记
  • 尚硅谷前端学科全套课程请点击这里进行下载,提取码:afyt

一、Git

  • 可前往 这里 练习 Git 相关练习

  • 可前往 这里 查看廖雪峰总结的相关 git 命令

1.版本控制

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

  • 优点:

    • 便于回滚版本
    • 便于分工开发
  • 缺点:

    • 所有的版本控制系统,其实只能跟踪文本文件的改动,比如TXT文件,网页,程序代码等等,而对于二进制文件是无法跟踪的

(1).集中化的版本控制系统

  • 例子:SVN、CVS、Subversion、Perforce

  • 优点:

    • 代码存放在单一的服务器上,便于项目的管理
  • 缺点:

    • 服务器宕机:员工写的代码得不到保障
    • 服务器炸了:整个项目的历史记录都会丢失

(2).分布式的版本控制系统

  • 客户端并不只提取最新版本的文件快照,而是把代码仓库完成的镜像下来

  • 例子:Git、BitKeeper

  • 优点:

    • 回滚速度快(因为每次存的都是项目的完整快照)
    • 完全的分布式
  • 缺点:

    • 占用空间相对大一些

2.安装与配置

  • 官网点击这里

  • 一般在新系统上需要配置一下自己的 Git 工作环境

  • Git 提供了一个叫做 git config 的命令来配置或者读取相应的工作环境变量,这些变量存放在以下三个不同的地方:

    • etc/gitconfig 文件:系统中对所有用户都普遍适用的配置,若使用该命令添加 --system 选项是读写的就是这个文件
    • ~/ .gitconfig 文件:用户目录下的配置文件只适用于该用户,若使用该命令添加 --global 选项是读写的就是这个文件
    • .git/config 文件:当前项目的 Git 目录中的配置文件(也就是工作目录中的那个文件),若使用该命令不添加任何选项是读写的就是这个文件
  • 配置方法:

    • 我们一般只需要配置用户文件即可,需要配置自己的用户名和邮件地址,用来作为标识
    • 使用 git config --global user.name "用户名" 命令来设置自己的用户名
    • 使用 git config --global user.email 邮箱 命令来设置自己的邮箱
  • 检查配置方法:

    • 使用 git config --list 命令来检查自己的配置

3.概念

(1).区域

  • 工作区

  • 暂存区

  • 版本库

(2).对象

  • Git对象

    • Git 的核心是键值对数据库
  • 树对象

  • 提交对象

(3).文件状态

  • 工作目录下的所有文件有两种状态:未跟踪已跟踪

  • 已跟踪分为如下三种:

    • 已暂存:当文件被提交到暂存区时就变为已暂存状态,颜色为绿色
    • 已修改:当文件被修改时,为已修改但未暂存状态,颜色为红色
    • 已提交:当文件被提交到版本库时就变为已提交状态
  • 图示如下:
    git01.png

4.底层命令

(1).Git对象

  • echo "test" | git hash-object -w --stdin:向数据库写入内容并返回对应键值(-w表示存储数据对象,-stdin表示从标准输入中读取内容)

  • git hash-object -w 文件路径:生成文件的键值

  • git has-object 文件路径:读取文件的键值

  • find .git/objects -type f:查看 git 存储的数据,文件夹为哈希值的前面位,文件名为哈希值的剩余位

  • git cat-file -p 哈希值:根据键值来查看数据内容

  • git cat-file -t 哈希值:查看存储的数据类型

(2).树对象

  • git update-index --add --cacheinfo 100644 哈希值 文件名:向暂存区中添加一条记录(让Git对象对应文件名)

  • git write-tree:生成树对象

(3).提交对象

  • echo "注释" | git commit-tree 树对象的哈希值:生成提交对象

(4).查看暂存区

  • git ls-files -s

5.高层命令

(1).初始化

  • 要对现有的某个项目开始用 Git 管理,需要到此项目的目录中执行初始化操作

  • 命令:git init

  • 初始化后有如下目录结构:

    • hooks:包含客户端或服务端的钩子脚本
    • info:包含一个全局性排除文件
    • logs:保存日志信息
    • objects:存储所有数据内容
    • refs:存储指向数据(分支)的提交对象的指针
    • config:文件,包含项目特有的配置选项
    • description:文件,显示对仓库的描述信息
    • HEAD:文件,指示目前被检出的分支
    • index:文件,保存暂存区信息

(2).添加

  • 作用:将当前工作目录中的文件添加到暂存区(即使文件被跟踪)

  • 命令:git add 路径

  • 以上命令涉及到底层以下两个命令:

    • git hash-object -w 文件名
    • git update-index

(3).提交

  • 作用:将暂存区中的文件提交到版本库

  • 命令如下:

    • git commit:进入 vim 界面书写较长的注释文字并将暂存区中的文件提交到版本库
    • git commit -m "注释":将暂存区中的文件提交到版本库
    • git commit -a:进入 vim 界面书写较长的注释文字并将工作目录中已被跟踪的文件提交到版本库(跳过添加到暂存区)
    • git commit -a -m "注释":将工作目录中已被跟踪的文件提交到版本库
  • 以上命令涉及到底层以下两个命令:

    • git write-tree
    • git commit-tree

(4).删除

  • 作用:删除工作目录中的文件(并不会删除该文件的相关git对象)

  • 命令:git rm 文件名

  • 以上命令涉及到以下两个命令:

    • rm 原文件名
    • git add 路径

(5).改名

  • 作用:对当前文件进行改名操作

  • 命令:git mv 原文件名 新文件名

  • 以上命令涉及到以下三个命令:

    • mv 原文件名 新文件名
    • git rm 原文件名
    • git add 路径

(6).查看状态

作用:可以查看到文件的相关状态

命令:

  • git status:查看当前文件的状态

  • git diff:查看哪些修改过的文件还没有被暂存

  • git diff --staged/--cached:查看哪些修改过的文件已经被暂存但没有被提交

(7).查看历史记录

作用:可以看到整个项目的提交历史记录

命令:

  • git log:正常显示log

  • git log --pretty=oneline:单行显示log,hash值正常显示

  • git log --oneline:单行显示log,hash值简写

  • git reflog:查看 HEAD 发生变化时的历史记录

(8).回退

作用:可以回退到上一版本

命令:

  • git reset --soft 哈希值/~ 只修改HEAD(带着分支)

  • git reset [--mixed] 哈希值/~ 同时修改HEAD(带着分支)和暂存区

  • git reset --hard 哈希值/~ 同时修改HEAD(带着分支)、暂存区和工作区

(9).撤销修改

git checkout -- 文件名:把文件在工作区的修改全部撤销

  • 修改后文件未放入暂存区:回到版本库一模一样的状态

  • 已入暂存区又进行了修改:回到添加到暂存区中的状态

git reset HEAD 文件名:可以把暂存区的修改撤销掉(unstage),重新放回工作区

git commit --amend

  • 可以重新编写上一次提交的提交信息

  • 当发现工作区有内容忘记暂存,可以先使用 git add 文件名,然后再执行该命令,可以将两次提交合为一次提交

如何撤销远程 commit ?

确保你在你想要撤销的分支上且该分支工作区干净

  • 本地使用 get reset --hard 哈希值,切换到特定的commit

  • 使用 --force推送到远程分支(如果报错需要前往仓库设置中允许 force 操作)

1
2
git reset --hard cedc856
git push --force origin master

(10).数据恢复

git branch recover-branch 哈希值:当硬重置到某个提交时,如果想要回去,可以使用该命令创建一个新的分支来进行开发

git reflog && git reset --hard 最后一次提交的哈希值:当硬重置到某个提交时,如果想要回去,也可以使用该命令硬重置回去,但一般不推荐,因为此时 HEAD 会形成相应的修改记录

6.分支命令

  • 分支的本质:是指向提交对象的可变指针HEAD

  • HEAD:

    • 是一个指针,默认指向 Master 分支,切换分支时就是让 HEAD 指向不同的分支
    • 每次有新的提交时,HEAD 都会带着当前指向的分支一起往前移动
  • 分支的模式:

    • 长期分支:一般指 master 和 develop 分支
    • 特性分支:一般指每一个功能的分支
  • 分支的原理:

    • .git/refs 保存了分支及其对应的提交对象 hash 值
    • HEAD引用 是一个符号引用,指向目前所在的分支

(1).创建

  • 作用:给当前的提交对象创建一个分支

    • 命令:git branch 分支名
  • 作用:给指定的提交对象创建一个分支(可以达成版本回滚操作)

    • 命令:git branch 分支名 指定的hash值

(2).切换

  • 作用:切换到指定分支

    • 命令:git checkout 分支名
  • 作用:新建分支并切换到该分支上

    • 命令:git checkout -b 分支名
  • 缺点:在切换分支时,如果当前分支上有未暂存的修改(第一次)或者有未提交的暂存(第一次)时,分支可以切换成功但会污染其他分支

  • 注意:切换分支会动 HEAD、暂存区、工作目录 这三个地方,因此每次切换分支前,一定要提交一次当前分支!

  • 撤销修改与切换分支的命令很类似,所以最新版本的 Git 中提供了以下命令来切换到该分区

1
2
git switch -c dev	// 新建并切换分区
git switch master // 切换到现有分区

(3).合并

1).快进合并

  • 适用于:当需要合并的分支在主分支的后边且在一条线上时,可以直接进行快进合并

  • 方法:

    • 先提交当前分支的内容
    • 切换到主分支上
    • 使用 git merge 需要合并到主分支上的分支名
    • 删除已合并的分支名即可

2).典型合并

  • 适用于:当需要合并的分支在主分支的历史进行了分叉,即当前分支不是最新的主分支代码,可能会与主分支同时修改到同一文件

  • 方法:

    • 先提交当前分支的内容
    • 切换到主分支上
    • 使用 git merge 需要合并到主分支上的分支名
    • 此时会提示哪个文件产生冲突,进入该文件解决冲突
    • 同时可以使用 git status 来查看哪些因包含合并冲突而处于未合并状态
    • 当解决完后提交当前代码就可以成功合并了
    • 删除已合并的分支名即可

(4).查看

  • 作用:查看项目分叉历史

    • 命令:git log --oneline --decorate --graph --allgit log --graph --pretty=oneline --abbrev-commit
  • 作用:查看分支列表

    • 命令:git branch
  • 作用:查看每一个分支的最后一次提交

    • 命令:git branch -v
  • 作用:查看每一个分支的最后一次提交以及跟踪的远程分支

    • 命令:git branch -vv
  • 作用:查看哪些分支已经合并到当前分支

    • 命令:git branch -merged
  • 作用:查看所有包含未合并工作的分支

    • 命令:git branch --no-merged

(5).删除

  • 注意:删除分支时必须切换到主分支,不然无法自己删自己

  • 作用:删除某已合并或空的分支

    • 命令:git branch -d 分支名
  • 作用:删除未合并的分支

    • 命令:git branch -D 分支名

(6).修改

作用:可以修改当前分支名

命令git branch -m oldName newName

7.分支引申

  • 禁用Fast Forward:

    • 可以禁用 “快速合并模式” 来在合并分支时生成新的 commit,这样从分支历史上就可以看出分支信息
    • 只要在合并时使用 git merge --no-ff -m "merge with no-ff" dev 即可禁用该模式
  • 分支策略:

    • master 分支是非常稳定的,仅用来发布新版本
    • dev 分支是不稳定的,等版本发布时,再把dev分支合并到master上,在master分支发布1.0版本
    • 每个人都在 dev 分支上干活且都有自己的分支,时不时地往 dev 分支上合并就可
    • 团队图:这里

(0).删除远程分支

  • 先查看所有的分支,使用 git branch -a 可以看到本地和远程的所有的分支

  • 然后使用 git push origin --delete 远程分支名 即可删除远程分支

(1).临时处理Bug

  • 可以使用 git stash 将当前的工作现场临时存储起来

  • 然后处理相应 Bug

  • 然后合并 Bug 分支到主分支上

  • 切换到当前工作分支

  • 使用 git stash list 查看所有被存储的工作区

  • 恢复工作区:

    • 先使用 git stash apply 恢复,然后使用 git stash drop 删除 stash 内容
    • 直接使用 git stash pop 恢复,且同时把 stash 呢日荣删除

(2).在子分支修复主分支同样的bug

  • 可以使用 git stash 将当前的工作现场临时存储起来

  • 然后处理相应 Bug

  • 然后合并 Bug 分支到主分支上

  • 切换到当前工作分支

  • 使用 git stash list 查看所有被存储的工作区

  • 使用 git cherry-pick <bug修复的哈希值> 命令把 bug 提交的修改“复制”到当前分支

  • 恢复工作区:

    • 先使用 git stash apply 恢复,然后使用 git stash drop 删除 stash 内容
    • 直接使用 git stash pop 恢复,且同时把 stash 呢日荣删除

(3).多人协作

  • 首先,可以试图用git push origin <branch-name>推送自己的修改

  • 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并

    • 如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to <branch-name> origin/<branch-name>
  • 如果合并有冲突,则解决冲突,并在本地提交

  • 没有冲突或者解决掉冲突后,再用git push origin <branch-name>推送就能成功

8.存储命令

使用 git stash 可以将当前分支上未提交的修改暂存在栈中

使用 git stash apply 可以应用暂存在栈顶的修改,并不会删除该暂存

使用 git stash list 可以查看当前暂存的修改

使用 git stash drop {暂存编号} 可以删除指定编号的暂存

使用 git stash pop 可以应用暂存在栈顶的修改,并删除该暂存

9.远程仓库

(1).创建

  • 创建 SSH Key

1
ssh-keygen -t rsa -C "youremail@example.com"
  • 创建好后可以去用户主目录中查看是否含有 .ssh 文件夹,在该文件夹里存放着两个文件

    • id_rsa 为私钥,只能自己使用
    • id_rsa.pub 为公钥,可以给其他人使用
  • 登录 GitHub 或者 GitLab 中,在设置中找到 SSH Keys 字段添加一个 key,在其中输入公钥

(2).拉取远程仓库项目

  • git clone git@192.168.129.110:zhangyangeng/test.git 命令可以拉取指定仓库

  • cd test 进入到项目目录中

  • touch README.md 创建一个文件

  • git add README.md 将修改提交到暂存区

  • git commit -m "add README" 将暂存区中的文件提交到版本库

  • git push -u origin master 将当前版本库中的内容推送到远程仓库

(3).推送已有项目到远程仓库

  • git remote add origin git@192.168.129.110:zhangyangeng/test.git 将远程仓库与当前项目目录进行关联

    • origin 为远程仓库的名字,默认为其
    • 后面的内容是自己仓库的链接,自行修改
  • git push -u origin master 将当前版本库中的内容推送到远程仓库

  • git push origin master 之后只要本地做了提交,就可以通过命令把本地 master 分支的最新修改推送至远程仓库了

(4).查看远程仓库

  • git remote -v 可以查看到当前所有的远程仓库

  • 一般会含有两行内容,分别代表抓取和推送的 origin 地址

(5).删除远程仓库

  • git remote rm origin 注意:这里并不是直接删除了远程仓库,而是解除了本地与远程仓库的连接,删除还需要去网站后台进行删除

(6).修改远程仓库

直接修改:

  • git remot set-url <name> <newUrl> 将指定远程链接名的 URL 修改为新的 URL

先删除再添加:

  • git remote remove <name> 删除指定远程链接名

  • git remote add <name> <newurl> 新增远程仓库

10.远程分支

当本地想要新建一个分支来开发远程指定分支上的代码时,可以使用:

1
2
git fetch upstream
git checkout -b dev upstream/dev 或 git checkout --track upstream/dev

当本地已有分支想要跟踪远程分支代码时,可以使用:

1
2
git fetch upstream
git checkout -u upstream/dev

二、Rebase

  • 看不懂

三、Tag

发布一个版本时,我们通常先在版本库中打一个标签(tag),这样,就唯一确定了打标签时刻的版本所以,标签也是版本库的一个快照

1.创建标签

git tag <name> 切换到需要打标签的分支上执行该命令来创建标签

git tag <name> 哈希值 给对应的 commit 打标签

git tag -a <name> -m "提示文字" 创建带有说明的标签

2.查看标签

git tag 查看标签(标签默认是按字母顺序排序的)

git show <name> 查看标签的具体信息

3.推送标签

git push origin <name> 推送某个标签到远程

git push origin --tags 一次性推送全部尚未推送到远程的本地标签

4.删除标签

git tag -d <name> 删除本地标签

git tag -d <name> 然后 git push origin :refs/tags/v0.9 删除已经推送到远程的标签

5.检出标签

git checkout <name> 切换到标签所在处,但此时会出现 HEAD 和分支分离的情况,所以不推荐使用

git checkout -b <name> 切换到标签所在处,并新建一个分支,推荐使用

四、自定义Git

1.忽略特殊文件

  • 在 Git 工作区的根目录下创建一个特殊的 .gitignore 文件,然后把要忽略的文件名填进去,Git 就会自动忽略这些文件

  • 不需要从头写.gitignore文件,GitHub 已经为我们准备了各种配置文件,只需要组合一下就可以使用了。所有配置文件可以直接在线浏览:https://github.com/github/gitignore

  • 忽略文件的原则:

    • 忽略操作系统自动生成的文件,比如缩略图等
    • 忽略编译生成的中间文件、可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如Java编译产生的.class文件
    • 忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件
  • 当某个自己想要上传的文件被忽略时我们可以使用 -f 参数来强制添加到 Git

  • git check-ignore -v 文件名 来检查哪个规则有问题

  • 忽略文件中的例外规则:可以不排除指定文件,如下:

1
2
3
4
5
6
7
# 排除所有.开头的隐藏文件:
.*
# 排除所有.class文件:
*.class
# 不排除.gitignore和App.class:
!.gitignore
!App.class

2.配置别名

  • Git 并不会在输入部分命令时自动判断需要输入的命令,所以可以通过 config 文件来给长命令设置一个别名

  • 使用如下:

    • git config --global alias.co checkout,当需要该命令时直接输入 git co 即可
    • git config --global alias.br branch,当需要该命令时直接输入 git br 即可

3.搭建Git服务器

五、Git Fork流操作

  1. 从远程仓库A fork到自己仓库B

  2. 从自己仓库clone到本地

  3. git remote add upstream https://gitLab.XXXX.com/A/project(添加一个upstream指向远程仓库)

  4. git fetch upstream(获取A上的所有分支到你本地)

  5. git merge upstream/master(将远程的master分支的内容同步到本地的master上),此时你的项目与远程一致了,这是时候在本地进行修改后正常 add ,commit,push之前要确定你这次提交之前与你最后一次拉代码的时候没有人提交,这时候需要再拉一次代码

  6. git git fetch upstream (将远程分支同步到本地)

  7. git merge upstream/master (合并分支,每次将远程仓库项目同步到本地project需要6,7操作,/后可以是你想同步的任意分支)

  8. git pull(同步到本地)

  9. git push origin master(将内容推到你的仓库B)

  10. 然后请求合并到远程仓库A

六、Git配置问题

1.执行 git push 出错

  • 错误代码:git@github.com: Permission denied (publickey). fatal: Could not read from remote repository.

  • 解决方法1:检查是否成功在远程仓库中添加了本机对应的 SSH Key,如果没有,添加后再次执行

  • 解决方法2:检查本地Git仓库是否和该SSH key关联,即执行 ssh-add "你的 id-rsa 文件地址"

2.执行 ssh-add 出错

  • 错误代码:Could not open a connection to your authentication agent

  • 解决方法:执行 ssh-agent bash ,然后再执行 ssh-add