Git 使用笔记

详细的说明文档: 请参考安装目录下的doc文档

D:\Program Files\Git\mingw64\share\doc\git-doc\git-stash.html

git 版本管理介绍

git 是一个分布式版本控制系统, 客户端并不只提取最新版本的文件快照, 而是把代码仓库完整的镜像下拉; 这么一来任何一处系统工作服务器发生故障,事后都可以用任何一台镜像出来的本地仓库恢复

因为每一次提取操作, 实际上是代码仓库的完整备份;

更进一步: 许多这类系统都可以指定和若干不同的远程代码仓库(如github)进行交互, 因此, 你可以在同一个项目中分别和不同的工作组的人相互协作;

分布式版本管理系统在管理项目时, 存放的不是项目 版本与版本 之间的差异, 他存的是索引(所需要的磁盘空间少 , 所以每个客户端都可以放下整个项目的历史版本)

理解分析: 
补丁版本模式, 是链表方案顺序找
A1[+1]  -->  补丁版本 A2[+2,+4,+6,+8] --> 补丁版本 A3[-2,-4, -6] --> ... --> An[0,8]
每次版本更新 都是记录上次版本更改的部分如下:
A2 版本仅记录添加了 2 ,4, 6, 8   
A3 版本仅记录删除了 2 ,4, 6  
最终的版本An 为 An[0,8]
这种方式的更新快, 但是一次回滚较容易, 如果想跳过多个版本, 回滚到A1版本, 就需要依次从An->A3->A2->A1

而git的版本是完整备份的, 类似于数组直接定位获取
每次的更新都是将新的版本保存为独立可用的文件包
因此每次更新需要备份的文件会比补丁版多, 但是回滚的时候, 可以直接找到指定版本立即使用

分布式版本控制系统出现以后,解决了集中式版本控制系统的缺陷:

1. 断网的情况下可以进行开发(因为版本控制是在本地进行的)
2. 使用github 进行团队协作, 哪怕github 挂了, 每个客户端保存的也都是整个完整项目(包含历史版本的所有记录)
小贴士: Git的历史:

​ Git是目前是世界上最先进的分布式版本管理控制系统, 同生活中的许多伟大的事件一样,Git诞生于一个极富纷争大举创新的时代, Linux内核开源项目有种位数众多的参与者, 绝大多数的Linux内核维护工作都花在了补丁和保存归档的繁琐事务上

​ 到了2005年, 开发Bitkeeper的商业公司同Linux内核开源社区的合作关系结束, 他们收回了免费试用Bitkeeper的权利, 这就迫使Linux开源社区(特别是Linux的缔造者Linus Torvalds) 不得不吸取教训, 只有开发一套属于自己的版本控制系统才不至于重蹈覆辙, 他们对新系统定制了若干目标:

​ 分支切换速度极快, 容量小, 简单的设计 完全分布式

​ 对非线性开发模式的强力支持,( 允许上千个并行的分支)

​ 有能力高效管理类似 Linux 内核一样的超大规模项目(速度和数量)

自诞生于2005年以来, Git 日臻成熟, 在高度易用的同时, 仍然保留着切切换初期设定的目标, 他的速度飞快, 极其适合大型项目, 他还有令人难以置信的非线性分支管理系统,可以应付各种复杂的项目开发需求;

SVN 版本管理介绍

原始代码托管系统SVN版本管理系统, 最明显的区别是中央服务器的单点问题,:

如果中央服务器的磁盘发生故障

  1. 设备没有做备份 如果无法恢复数据,那将丢失所有历史记录数据, 而个人的电脑通常仅保留了当前的版本代码,只能重建SVN 服务, 代码的版本也只能以当前大家保存的为准了

  2. 设备自动备份为定时任务, 那么在上一次备份到故障点区间内的这段时间的数据就可能丢失

    总之, 只要项目管理的服务器保存数据是单一位置, 都有丢失数据的风险

二者比较:

集中式(SVN):

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

​ 缺点:

​ 服务器宕机: 员工写的代码没有办法得到保障

​ 服务数据损毁: 整个项目的历史记录都会丢失

分布式(Git):

​ 优点: 分布式代码托管的安全性, 代码更新回滚的独立版本数据

​ 缺点: 操作稍显复杂;

git 安装:

首先下载git 安装包: https://git-scm.com/downloads

在这里插入图片描述

图形化安装: 下一步下一步 即可

安装完成后:

window程序中可以看到:
在这里插入图片描述

在window 资源管理器中右击:

可看到快速启动按钮:
在这里插入图片描述

命令行 分析Git 信息保存的流程:

git 的初始化配置:

一般在新的系统上,我们都需先配置一下自己的Git工作环境,配置工作只需要一次, 以后升级是还会沿用现在的配置

Git 提供了一个叫做Git config 的命令来配置或读取响应的工作环境变量

这些变量有三个级别:

system 级别:

/etc/gitconfig文件: 系统中对所有用户都普遍使适用的配置, 若使用gitcofnig时 使用 --system 选项 ,读写的就是这个文件

~/.gitcofig 文件, 用户目录下的配置文件只适用于该用户, 若使用gitconfig时, 使用 --global选项, 读写的就是这个文件

.git/config 文件, 当前项目的Git目录中的配置文件(也就是工作目录中的.git/config文件, 这里的配置仅仅针对项目有效

用户配置信息:

​ 第一个要配置的就是个人用户名和电子邮件地址, 这两条配置很重要, 每次Git提交时都会引用这两条信息, 说明谁提交了更新, 会随更新内容一起提交到git更新历史记录中;

$ git  config  --global  user.name "xxxx"
$ git  config  --global  user.email "xxxxx"

#查看已配置的信息
$git  config  --list

Git的底层概念:

Git基础的linux 命令

clear : 清空屏幕

echo “message content” : 往控制天输出信息

ll : 打印当前目录下的文档信息列表

find 目录名: 将对应目录下的子文件&子目录文件列出

find 目录名 -type f : 将对应目录下的文件列出

rm 文件名: 删除文件

mv src desc : 移动

cat 文件的url : 查看文件内容

学些Git 重点理解两组概念

区域

工作区

​ .git 文件所在目录, git clone 下载的文件目录, 项目源码文件目录

暂存区

​ 使用git add 命令 将新文件提交暂存区内, 可以使用git status 查看暂存区信息

版本库

​ commit 提交后, 代码保存到工作库中

对象

Git对象
树对象
Git 根据某一时刻暂存区(即index区) 所表示的状态创建并记录一个对应的树对象, 如此重复便可依次激励某个时间内, 一系列的树对象
其实树对象就是对暂存区内操作的抽象, 这一棵树对象就相当于快照, 当我们的工作区由任何更改同步到暂存区是, 便会调用write-tree 命令
通过write-tree命令, 向暂存区内写入一个树对象, 他会根据当前暂存区状态自动创建一个新的树对象,即每一次同步都产生一个树对象,且该命令会返回一个hash指向该树对象;
在Git中每一个文件(数据) 都对应一个hash(类型blob)
	每一个树对象都对应一个hash(类型tree)

总结: 我们可以认为 树对象就是项目的快照

提交对象

Git对象的实验:

初始化项目

新建一个目录, 右击打开git bash 命令行窗口, 执行git仓库初始化:

$ git  init 

解析: 要对现有的某个仓库开始使用Git 管理, 只需要到此项目所在目录,执行git init

作用: 初始化后, 在当前目录下会出现一个名为.git的目录, 所有Git需要的数据和资源都存放在这个目录中, 不过目前,仅仅是按照既有的结构框架初始化好了里面所有的文件和目录, 但我们还没有开始跟踪管理项目中的任何一个文件;

目录结构:

​ hooks: 目录包含客户端或服务器端的钩子脚本

​ info : 包含一个全局属性排除文件

​ logs : 保存日志信息

​ objects : 目录存储所有数据内容,本地git仓库

​ refs : 目录存储指向数据(分支) 的提交对象的指针

​ config: 文件包含此项目持有的配置信息

​ description : 用来显示目录被检出的分支信息

​ HEAD : 文件提示目录前被检出的分支

​ index: 文件保存暂存区信息(只要暂存区有信息,就会有该文件夹)

git hash-ojbect 命令:

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

首先熟悉 git hash-object 命令:


$ git hash-object -h
usage: git hash-object [-t ] [-w] [–path= | --no-filters] [–stdin] [–] …
or: git hash-object --stdin-paths

-t <type>             object type
-w                    write the object into the object database
--stdin               read the object from stdin
--stdin-paths         read file names from stdin
--no-filters          store file as is without filters
--literally           just hash any random garbage to create corrupt objects for debugging Git
--path <file>         process file as it were from this path

操作:
向Git 数据库中写入信息
  • 向数据库写入内容, 并返回对应的数值, 写入的内容键被转化为一个hash值作为文件名, 值就是文件内容, 被保存在object文件夹下

    命令: git hash-object -w 文件路径

    $ echo  "test content"  | git  hash-object  -w   --stdin
    # -w  选项指示 hash-object  命令存储数据对象: 若不能指定此选项, 则返回该命令对应的键值
    # --stdin  选线  指示该命令从标准输入读取内容; 若不能指定此选项, 则返回命令尾端给出的待存储文件的路径
    
    
    从数据库读取内容

    查看数据库的存储信息git对象

    命令:

    $ find  .git/objects/   -type  f
    
    从数据库查看文件内容信息:

    命令:

    $ git  cat-file  -p   hash码
    #  -p  选项可指示该命令自动判断内容的类型, 并未我们现实格式友好的内容
    
    从数据库读取文件类型:

    命令:

    $ git  cat-file  -t  hash码
    #  注意:  git数据库中保存的文件类型为blob类型
    

    在这里插入图片描述

  • 对一个文件进行简单的版本控制

    • 创建一个文件并将其内容存入数据库

      命令:

       $ echo  "test.txt"  > test.txt
       $ git   hash-object  -w   test.txt
      

      返回: 一个hash码值

      4871fd52755be519c29ae719f385bd5f2863627c
      在这里插入图片描述

  • 查看数据库内容:

    命令:

    $  find  .git/objects   -type  f
    

    问题:

    1. 我们想object databasde 中写入的文件(object), 其文件名并没有被直接保存,而是转化为一个hash码作为文件名, 文件内容是完整保存起来的

    2. 但是要记住文件的每一个版本对应的SHA-1 值可是不现实的

      解决方案: 树对象

      ​ 他保存了git数据库中的键hash值 与 文件名的对应关系 ;使得用户可以根据文件名在树对象中找到对应的hash值,再通过hash值, 到git数据库中获取文件数据

      注意: 当前的操作都是在对象本地数据库进行操作,不涉及缓存区

    树对象:

    ​ 树对象够解决文件名保存的问题, 也允许我们将多个文件组织到一起, Git以一种类似于UNIX文件系统的方式存储内容, 所有内容均以树对象和数据对象(git对象) 的形式存储;

    • 树对象对应了UNIX中的目录项

    • 数据对象(git对象) 则大致对应文件内容

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

    构建树对象

    我们可以通过update-index ; write-tree ; read-tree 等命令来构建树对象并加入到暂存区

    操作:

    1.新建一个工作区

    $ git  init
    

    2.创建一个文件:

    $ echo " test.txt" > test.txt
    

    3, 为该文件生成一个hash码值 , 并将该hash码作为键, 将文件内容作为值 写入 git对象(object)

    $ git  hash-object   -w   test.txt
    # 返回一个hash 码为 :  4871fd52755be519c29ae719f385bd5f2863627c
    

    4, ls 查看git 数据库中的文件信息, 文件即保存的信息:

     # 查看.git/objects的文件列表
    $ ll  .git/objects
    #  drwxr-xr-x 1 Administrator 197121 0 四月   17 15:44 48/
    #  drwxr-xr-x 1 Administrator 197121 0 四月   17 15:43 info/
    #  drwxr-xr-x 1 Administrator 197121 0 四月   17 15:43 pack/
    $ ll  .git/objects/48 
    #  -r--r--r-- 1 Admin 197121 24 四月   17 15:44 71fd52755be519c29ae719f385bd5f2863627c
    

    5, find查看可能更加直接,查看Git仓库的所有文件

     
     $ find  .git/objects/    -type  f
     #  .git/objects/48/71fd52755be519c29ae719f385bd5f2863627c
    

    发现返回的hash码 , 前两位是文件夹名, 后面的是文件名

    6, 查看文件内容

    $ git  cat-file  -p  4871fd52755be519c29ae719f385bd5f2863627c
    #  返回文件内容为  :  test.txt
    

    7, 使用cat 查看文件内容是不可直接看到的, 存储的类型为blob加密类型
    E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587110649976.png

    8.利用update-index 命令, 为test.txt 文件的首个版本创建一个暂存区, 并通过write-tree 命令生成树对象;

    ​ 命令:

    $ git update-index --add --cacheinfo 10064 4871fd52755be...[hash码]  test.txt 
    # 文件模式为:   10064 , 表明这是一个普通文件
    #			  10075 , 表明这是一个可执行文件
    #			  12000 , 表明这是一个符号连接文件
    # update-index 添加暂存区
    #--add 选项:  do not ignore new files 首次需要--add
    #--cacheinfo 选项: add the specified entry to the index 所以需要--cacheinfo
    

    9, 查看Git 暂存区信息 : 就是一个类似索引库, 记录了hash和 文件名test.txt的对应关系

    命令 :

    $ git ls-files -s
    # 输出: 
    # 100644 4871fd52755be519c29ae719f385bd5f2863627c 0       test.txt
    

    10, 将 index中的信息生成一个树对象

     $ git write-tree
     # 输出又返回一个hash值 
     # 554949018a91d425d582b512b17f1052047db469
     # 该hash值同样是一个文件,使用ls查看,在55文件下有一个4949018a91d425d582b512b17f1052047db469的文件生成
    

    11, 查看生成的文件类型:

    git  cat-file  -t 554949018a91d425d582b512b17f1052047db469
    # 返回文件类型为 : tree 
    

    12, 使用find 查看当前项目objects下的文件

    $  find  .git/objects/   -type f 
    #.git/objects/48/71fd52755be519c29ae719f385bd5f2863627c -->这是一个数据对象 保存文件信息
    #.git/objects/55/4949018a91d425d582b512b17f1052047db469 -->这是一个树对象  保存文件名-hash
    

    可见, 一个文件要保存到Git中, 需要至少生成两个文件, 一个数据文件git对象, 一个树对象文件

    git 对象 代码文件的一次版本

    树对象 代表项目一次版本

    13, 再次查看暂存区:

    $ git  ls-files -s 
    # 输出: 100644 4871fd52755be519c29ae719f385bd5f2863627c 0       test.txt
    # 暂存区的内容仍然存在, 说明一次版本保存,并不会清理暂存区信息
    

    14, 测试版本升级迭代:

    # 生成一个新文件
    $  echo "new.txt" >  net.txt
    # 生成hash 并写入
    $ git  hash-object  -w new.txt
       #  返回hash码:  d29d7c16a565be39b980a88fded57af24fea9b6b
    # 查看文件信息
    $ find  .git/objects/  -type f 
    # .git/objects/48/71fd52755be519c29ae719f385bd5f2863627c
    # .git/objects/55/4949018a91d425d582b512b17f1052047db469
    # .git/objects/d2/9d7c16a565be39b980a88fded57af24fea9b6b   -- > new.txt的数据对象
    
    # 更新test.txt文件内容
    $ echo "new info added "  >> test.txt
    $ cat test.txt
    # test.txt
    # new info added
    #再次写入更新后的test.txt文件到git/objects数据仓库下
    $ git hash-object  -w   test.txt
    # 再次查看object 文件
    $ find .git/objects/  -type f
    #.git/objects/0d/a073d751f5d756fc95485b2872ca897ee87d8a -- > 更新后的test.txt的数据对象
    #.git/objects/48/71fd52755be519c29ae719f385bd5f2863627c
    #.git/objects/55/4949018a91d425d582b512b17f1052047db469
    #.git/objects/d2/9d7c16a565be39b980a88fded57af24fea9b6b  -- > new.txt的数据对象
    
    #将新建的new.txt 添加到index 
    git update-index  --add  --cacheinfo 10064 d29d7c16a565be3...[hash码]  new.txt
    
    #查看暂存区
    git  ls-files  -s 
    #100644 d29d7c16a565be39b980a88fded57af24fea9b6b 0       new.txt
    #100644 4871fd52755be519c29ae719f385bd5f2863627c 0       test.txt
    
    #将更新后的test.txt 更新到index
    git update-index --add --cacheinfo  10064 0da073d751f5d756fc9...[hash码] test.txt
    
    # 再次查看暂存区 
    git ls-files -s
    #100644 d29d7c16a565be39b980a88fded57af24fea9b6b 0       new.txt
    #100644 0da073d751f5d756fc95485b2872ca897ee87d8a 0       test.txt 发现test.txt被更新了
    
    # 查看git/objects/ 工程下的文件
    $ find  .git/objects/  -type  f
    #.git/objects/0d/a073d751f5d756fc95485b2872ca897ee87d8a  -- > 更新后的test.txt的数据对象
    #.git/objects/48/71fd52755be519c29ae719f385bd5f2863627c  
    #.git/objects/55/4949018a91d425d582b512b17f1052047db469
    #.git/objects/d2/9d7c16a565be39b980a88fded57af24fea9b6b  -- > new.txt的数据对象
    
    # 生成树对象
    git wirte-tree 
    # 返回一个hshs码: dfaef2053e87cf3fb5c60f29ac52b1267136002d
    
    # 再次查看 git/objects/  工程下的文件
    $ find  .git/objects/   -type  f
    #.git/objects/0d/a073d751f5d756fc95485b2872ca897ee87d8a -- > 更新后的test.txt的数据对象
    #.git/objects/48/71fd52755be519c29ae719f385bd5f2863627c  --首次写入的test.txt数据独享
    #.git/objects/55/4949018a91d425d582b512b17f1052047db469  --首次创建的tree对象
    #.git/objects/d2/9d7c16a565be39b980a88fded57af24fea9b6b -- > new.txt的数据对象
    #.git/objects/df/aef2053e87cf3fb5c60f29ac52b1267136002d --> 新建的tree对象
    # 一次构建tree的过程就是工程的一次保存,tree对象保存的数据是每次项目当前的所有信息, 而非仅保存更新的部分
    

    至此, git 版本控制的一个基础原理演示完毕

    下面演示将第一次生成Tree对象加入到 第二次生成的tree对象中;并使其成为一个新的tree对象

    git  read-tree  --prefix=back  554949018a91d425d582b512b17f1052047db469
    # 返回一个新的tree对象hash 码: a7178495c93c3757e9ff6cfbd2f4e2c43b95dd62
    
    #查看当前暂存区:
    git  ls-files -s
    #100644 4871fd52755be519c29ae719f385bd5f2863627c 0       back/test.txt
    #100644 d29d7c16a565be39b980a88fded57af24fea9b6b 0       new.txt
    #100644 0da073d751f5d756fc95485b2872ca897ee87d8a 0       test.txt
    
    
    查看git/objects  工程下文件
    $ find  .git/objects/  -type  f
    .git/objects/0d/a073d751f5d756fc95485b2872ca897ee87d8a
    .git/objects/48/71fd52755be519c29ae719f385bd5f2863627c
    .git/objects/55/4949018a91d425d582b512b17f1052047db469
    .git/objects/a7/178495c93c3757e9ff6cfbd2f4e2c43b95dd62
    .git/objects/d2/9d7c16a565be39b980a88fded57af24fea9b6b
    .git/objects/df/aef2053e87cf3fb5c60f29ac52b1267136002d
    

    目前的git数据库tree对象结构为

    tree03

    |__>tree 01

    ​ |__>当前的暂存区信息

问题:

​ 现在有三个树对象(执行了三次write-tree), 分别代表了我们想要跟踪的不同项目快照, 然而问题依旧, 若想要重用这些快照, 你必须记录所有的SHA-1码, 并且,完全不知道是谁保存了这些快照, 在什么时候保存的, 以及为什么保存, 而以上这些信息,这是提交对象(commit object) 能为我们提供的;

提交对象:

我们可以通过调用commit-tree 命令创建一个提交对象,为此需要指定一个树对象的SHA-1 值, 以及该提交的父提交对象(第一次暂存区 做快照提交就没父对象)

创建提交对象

$ echo "fire commit "   |  git  commit-tree  dfaef2053e87cf3fb5c60f29ac52b1267136002d
# 返回提交对象的hash值:
# 		a530d5bf709b21871ee92e1ada34378fff860cc1

# 查看 该对象类型
$ git  cat-file -t  a530d5bf709b21871ee92e1ada34378fff860cc1 
# 返回: commit

# 查看 该对象的内容
$ git  cat-file -p  a530d5bf709b21871ee92e1ada34378fff860cc1
# 输入: 
#tree dfaef2053e87cf3fb5c60f29ac52b1267136002d
#author user-name <email@163.com> 1587117342 +0800   --> 作者信息
#committer user-name <email@163.com> 1587117342 +0800  --> 提交人信息
#
#fire commit    --> 注释说明信息
#


在这里插入图片描述

项目的版本实际上是一个commit对象

项目的快照就是一个tree对象

小结:
git 对象: 
  git  hash-object  -w  文件名  # 生成一个hash值, val压缩后的内容键值对保存到.git/object

tree 对象
  git  update-index --add   --cacheinfo   10064  hash码    文件名 # 往暂存区添加一条记录(让git对象对象上下文) 存到 .git/index
  git  write-tree   # 生成树对象
  git  read-tree   # 读取树对象
commit 对象
  echo "commit message"  | git  commit-tree  tree对象的hash码  # 生成一个提交对象到.git/ojbect
git  cat-file -t  hash码  # 查看对象类型
git  cat-file -p  hashma  # 查看对象信息
git ls-files  -s   # 查看暂存区信息

Git 高级命令:

$ git help

usage: git [–version] [–help] [-C ] [-c =]
[–exec-path[= ]] [–html-path] [–man-path] [–info-path]
[-p | --paginate | -P | --no-pager] [–no-replace-objects] [–bare]
[–git-dir= ] [–work-tree= ] [–namespace=]
[]

These are common Git commands used in various situations:

start a working area (see also: git help tutorial)
   clone     Clone a repository into a new directory
   init      Create an empty Git repository or reinitialize an existing one

work on the current change (see also: git help everyday)
   add       Add file contents to the index
   mv        Move or rename a file, a directory, or a symlink
   restore   Restore working tree files
   rm        Remove files from the working tree and from the index

examine the history and state (see also: git help revisions)
   bisect    Use binary search to find the commit that introduced a bug
   diff      Show changes between commits, commit and working tree, etc
   grep      Print lines matching a pattern
   log       Show commit logs
   show      Show various types of objects
   status    Show the working tree status

grow, mark and tweak your common history
   branch    List, create, or delete branches
   commit    Record changes to the repository
   merge     Join two or more development histories together
   rebase    Reapply commits on top of another base tip
   reset     Reset current HEAD to the specified state
   switch    Switch branches
   tag       Create, list, delete or verify a tag object signed with GPG

collaborate (see also: git help workflows)
   fetch     Download objects and refs from another repository
   pull      Fetch from and integrate with another repository or a local branch
   push      Update remote refs along with associated objects

'git help -a' and 'git help -g' list available subcommands and some
concept guides. See 'git help <command>' or 'git help <concept>'
to read about a specific subcommand or concept.
See 'git help git' for an overview of the system.
$ git help -g  # 查看git 说明文档

The common Git guides are:

attributes          Defining attributes per path
   cli                 Git command-line interface and conventions
   core-tutorial       A Git core tutorial for developers
   cvs-migration       Git for CVS users
   diffcore            Tweaking diff output
   everyday            A useful minimum set of commands for Everyday Git
   glossary            A Git Glossary
   hooks               Hooks used by Git
   ignore              Specifies intentionally untracked files to ignore
   modules             Defining submodule properties
   namespaces          Git namespaces
   repository-layout   Git Repository Layout
   revisions           Specifying revisions and ranges for Git
   tutorial            A tutorial introduction to Git
   tutorial-2          A tutorial introduction to Git: part two
   workflows           An overview of recommended workflows with Git
$ git help -a   # 查看git 所有命令

常用命令记录:

 git  init # 初始化git仓库
 git  add   ./    #将前路径下的所有目标文件添加到暂存区, 同时未跟踪的文件标记为已跟踪
 git  status    # 查看当前git的状态, 会打印当前的添加文件信息
 git  commit  -m "说明信息"  # 提交暂存区信息到版本库中
 git  commit  -m  -a  # 跳过暂存取, 直接提交, 只能用于跟踪过的文件
 git  lot  --oneline  #查看提交的历史记录

git 工作区中的文件状态

  1. 未跟踪的文件, 没有任何git add 等操作的文件
  2. 已跟踪的文件, 已添加 / 已修改 / 已提交
  3. 初次克隆某个仓库时, 工作目录中的所有文件都属于已跟踪文件;
git  diff     #查看哪些修改还没有暂存, 记录跟踪文件未被add到暂存区之前的修改过程记录,文件被add之后, 则该文件进入以暂存,原有的该文件的未暂存记录被清空;

git  diff  --cached  # 查看哪些文件还没有暂存, 记录到进入暂存区的文件,但未提交之前,文件的所有修改记录, 文件被提交之后, 则该文件进入以提交状态, 原有的关于该文件的暂存区记录被清空;

git  diff  --staged  # 同git  diff  --cached  , 适用于1.6版本以上

跳过暂存区 直接提交:

git  commit   -a  -m "message"    # 直接将文件修改提交到版本库中

删除文件:

git  rm filename  # 删除工作区文件, 并添加到暂存区

重命名文件

git  mv   src-file  dest-file  # 将工作目录中文件从命名 , 并添加到暂存区

查看历史记录:

# 查看提交记录
git  log 
# 查看提交记录简写, 省略hash值
git  log  --oneline

git 操作流程:

git init 初始化工作目录

​ |–> 添加文件

​ |-- > git add 将文件添加版本库然后在添加到暂存区

​ |–> git commit 将暂存区添加到仓库

Git 基本操作:
1. 跟踪新文件:

命令:

git  add  README.md 文件名

作用: 跟踪一个新文件

​ 再次运行 git status 命令, 会看到 README.md 文件以被跟踪, 并且处于暂存状态;

状态:
在这里插入图片描述
只要在Changes to be committed : 下面列出的文件, 就说明是已暂存状态, 如果此时提交, 那么该文件此时此刻的版本将被留存在历史记录中, 在git add 后面可以指明要跟踪的文件或者目录 如果是目录的话,就说明要递归跟踪该目录下所有的文件

说明

# git add 的潜台词就是把目标文件保存为git 对象 后, 在将git 对象保存快照放入暂存区 同时将目标文件标记为已跟踪状态
2. 修改已暂存的文件

现在README.md 文件都已经暂存, 但未提交; 假设此时,你再次修改 README.md we文件中的信息, 然后在查看

状态:
在这里插入图片描述
发现test02 既有暂存状态, 又有以修改状态

如果此次提交: 就是将当前暂存区文件保存, 标记为已修改的文件是不会提交的, 需要再次add 保存到暂存区才可重新提交,保存了两次版本;

如果不提交, 直接再次是有git add 命令, 将test02.txt 暂存, 那么暂存区的test02.txt文件将被覆盖更新; 此时仅保存了最终版版本;
在这里插入图片描述

3. 查看已暂存和未暂存的更新

实际上git status 是显示比较简单的信息, 仅仅列出了修改过的文件, 如果要查看具体修改了什么地方, 可以用git diff 命令

git diff
# 该命令主要记录已跟踪但未add暂存区文件的修改信息
# 1. 当前做的那些更改还没有暂存, 即文件本身的更改信息
git diff   (不加任何参数)
# 2. 哪些更新已经暂存起来但未提交, 即暂存区文件的更新信息
git  diff  --cached   或者   git  diff   -staged  (1.6以上版本)

在这里插入图片描述

每次执行 git commit 命令 , 提交之后; git diff --cached 暂存区更新记录的信息清空
在这里插入图片描述
再次修改文件,并天机到暂存区, git diff --cached 暂存区更新记录中又有记录信息

在这里插入图片描述

但是 git diff 记录的是跟踪文件本身被修改的内容信息

特别说明

git diff --cached # 查看哪些文件还没有暂存 — 记录到进入暂存区的文件,但未提交之前,文件的所有修改记录, 文件被提交之后, 则该文件进入以提交状态, 原有的关于该文件的暂存区记录被清空;

git diff #查看哪些修改还没有暂存 — 记录跟踪文件未被add到暂存区之前的修改过程记录,文件被add之后, 则该文件进入以暂存,原有的该文件的未暂存记录被清空;
在这里插入图片描述

4. 提交更新

当暂存区信息已经准备OK, 确认可以提交了, 确认以修改的文件已add到暂存区中, 可以使用git status 或者 git diff

确认Ok

执行命令:

git commit   或者  git  commit  -m "提交记录说明"

注意: 直接使用 git commit 会启动文本编辑器, 以便输入本次提交的说明

​ 默认的提信息包含的是最后一次git status 的输入, 放在注释行里

​ 另外开头还有一个空行, 供你输入说明信息, 你也可以去掉这些注释行

使用 git commit -m “message” 后面直接跟说明信息, 可以一次提交ok

提交的记录是放在暂存区的快照信息, 任何还未暂存的信息仍然保持已修改状态; 可在下次提交是纳入版本管理, 每一次运行提交操作; 都是对项目的一次快照,以后可以回滚到这个状态,或者进行比较;

5. 直接跳过暂存区:

尽管攒簇你去的方式可以精心准备提交的细节, 但是有时为了直接一次提交, Git 提供了跳过暂存区的方式, 只要在提交的时候,给Git commit 加上 -a 选项; Git 就会自动把所有跟踪文件暂存起来一并提交;

git commit  -a   -m "message"
删除文件

命令:

git rm  README.md 文件名   # 将文件从工作区删除, 并将文件更新到暂存区

说明:

如果直接使用 linux 命令 : rm README.md , 则 git的暂存区任然记录了暂存区信息,

使用命令: git restore /back/data 将暂存区的文件恢复到/back/data 目录下

移动文件:

命令:

git  mv   README.md  文件名  # 将文件移动到指定位置,  并将文件信息更新到暂存区

在这里插入图片描述

小结
#安装
git  -version  #查看git  版本
# 初始化配置
git config  --global  user.name  "daemon"
git config  --global  user.email "daemon@email.com"
git config  --list   或者  git config  -l


git  init   # 初始化仓库
git  status # 查看状态
git  add   文件名  # 添加文件到暂存区
git  commit  -m  " message" #  提交暂存区信息到仓库
git  rm  文件名    # 删除文件, 并添加到暂存区
git  mv  文件名    # 修改文件名, 并添加到暂存区
git  restore      #将文件从暂存区返回
git  diff   # 已跟踪但未暂存
git  diff --chache   # 以暂存但未提交
git  log --oneline   # 查看提交记录
git  reflog   # 查看历次提交的详细记录信息
git  lot --oneline  --decorate  --graph  --all   # 查看整个项目的分支图

Git 分支命令:

几乎所有的版本控制系统都以某种形式支持分支, 使用分支意味着你可以把你的工作从主线上面分开来,以免影响开发主线, 在很多版本控制主线中, 这是一个略微低效的过程-- 常常要完全创建一个源代码目录的测试版本, 对于大项目来说, 这样的过程会耗费很多时间;

而 git 的分支模型极其的高效轻量,也因为这一特性, 使得Git 从众多的版本控制系统中脱颖而出;

1. 创建分支:

命令:

git branch  test01 分支名   # 创建一个分支 test01

作用:

为你创建一个指向当前最新提交对象的指针, 比如, 创建一个test分支, git branch test , 这会在当前所在的提交对象上创建一个指针

注意:

git branch 分支名: 创建一个分支, 并不会自动切换到新的分支去

命令:

git  branch   # 不只是可以创建于删除分支,  如果不加任何参数运行, 会得到当前分支的所有列表;

在这里插入图片描述

分支的本质就是一个目录指针, 或者说是一个连接文件HEAD 其指向的是一个分支记录文件内容为一次commit的hash值

打开git 工作目录, 查看目录结构中的HEAD文件夹

/.git/refs/heads  # 该文件夹下保存的是分支名称列表信息, 文件名为分支名, 文件值为comiit对象的hash值

发现有一个master文件, 他保存一个hash值代表当前master分支
在这里插入图片描述
在这里插入图片描述

查看当前分支:
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587899375370.png

新建分支:
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587899419294.png

发现: 新建分支后, 当前分支仍然为master分支, 但是多了一个test01的分支, 同时head文件夹下生成一个分支记录文件:

E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587899536232.png

2. 切换分支

切换到 新建的test01分支

git checkout tets01

E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587899733571.png

3. 查看项目分叉历史
git  log   --oneline  --decorate  --graph --all

4. 分支合并

命令:

git  merge 分支名
5. 删除分支
git branch  -d   分支名   # 删除没有使用的分支
git  branch  -D   分支名  # 如果想强制删除分支, 使用-D 
# 无法删除当前所在的分支
6. 查看每个分支的最后一次提交
git branch -v
7. 创建一个指定提交对象的分支
git branch name  commitHash 

查看合并到当前分支的其他分支

git branch  --merged
# 在这些分支列表中, 没有* 号的分支通常可以使用git branch -d 删除掉
8. 查看当前分支锁指向的对象
git  log  --oneline   --decorate 
9. 配置别名

git 并不会在你输入部分命令时自动推断出你想要更新的命令, 如果不想每次输入完整的git命令,可以通过git config 文件来轻松的为每一个命令设置别名.

git  config  alias.ck  checkout
git  confit  alias.lol  "log   --oneline  --decorate  --graph --all"
小结:
git branch    # 分支列表
git branch  分支名  #创建分支
git branch  -b  分支名  # 创建分支名,并直接切换到该分支中
git branch -v   # 查看分支指向的最新提交对象
git branch name # 在当前提交对象上创建新的分支
git branch name  commitHash  # 在指定提交对象上创建分支并指定分支名
git checkout  分支名  # 切换分支
git branch -d name   # 删除空的分支, 删除已经被合并的分支
git branch  -D  分支名  # 强制删除分支

# 分支对象的本质
# 他是对于git提交对象所保存的文件创建的一个连接文件HEAD, 是数据模型上的指针概念
# 并且每次提交对象, HEAD都会指向最新的版本提交对象文件

注意: 
# 分支切换会改变你的工作目录中的文件
# 在切换分支时, 一定要注意你的工作目录里的文件会被改变, 如果是切换到一个较旧的分支,你的工作目录会恢复到该分支最后一次提交时的样子, 如果 Git 不能干净利落的完成这个任务,它将禁止切换分支
切换分支最佳实践
每次使用git branch  分支名
注意: 会自动操作三个地方的文件
#1. HEAD  link 文件的指向会从当前.git/refs/master[分支名] 文件 切换到新分支的.git/refs/test01文件
#2. 暂存区的文件如果未提交或者 新建文件未暂存并未受控的文件会被遗漏,尽管可以切换分区但是会污染到新分区中
#3. 工作目录即和.git同级的路径内的文件会直接修改切换分区的文件组织结构, 当前分区的文件如果修改单未保存也会丢

### 因此每次修改分区时, 一定要使用git status  查看当前分区信息, 确保所有修改都提交保存后在操作
测试任务:
  1. 开发摸个网站
  2. 为了实现摸个需求,新建了一个分支
  3. 在这个分支上开展工作
  4. 此时,突然有另一新的需求急需解决
  5. 需要提交当前分支,然后切换到主分支
  6. 为这个紧急任务再新建一个分支
  7. 测试通过后,再切换会原来开发新功能的分支急需工作
实践:

git branch 查看分支

E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587959406459.png

切换到test01分支
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587959458355.png

查看当前分支状态:
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587959510956.png

修改分支任务
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587959667300.png

目前分支还未保存

现在要去修改一个紧急任务, 需要先提交当前分支的修改
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587959780269.png

当前分支提交Ok , 切换会主分支
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587959955958.png

在主分支上建立新的分支,test02用来解决紧急bug

E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587959974582.png

修改紧急bug
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587960138014.png

提交当前的bug解决
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587960191215.png

进入master 分支, 将 紧急bug解决test02的分支合并
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587960313559.png

然后合并到master主分支中, test02的临时分支就可以删除了
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587960362052.png

此时临济紧急bug结局完成

再次回到原来没有完成的test01分支,继续
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587960581561.png

修改bug OK, 提交该分支
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587960618027.png

如果此时

另外需要修改公共文件 test.txt文件内容
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587961017027.png
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587961044514.pngE:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587961098432.png

此时回到主分支:

将test01 分支的修改合并到
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587961964999.png
注意: 解决冲突, 需要在文件中修改冲突部分的代码, 在master分支中 在此 使用 git add 就相当于解决冲突

Git存储

有时,当你在项目的一部分上已经工作一段时间后, 所有东西都进入了混乱的状态,而这时你想要切换到另一个分支做点事情,问题是,你又不想仅仅因为过一会儿在回到这一点而为了做一半的工作创建一次提交; 针对这样的问题,答案是使用git 存储

git-stash(1) Manual Page
NAME

git-stash - Stash the changes in a dirty working directory away

SYNOPSIS
git stash list [<options>]
git stash show [<options>] [<stash>]
git stash drop [-q|--quiet] [<stash>]
git stash ( pop | apply ) [--index] [-q|--quiet] [<stash>]
git stash branch <branchname> [<stash>]
git stash [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]
             [-u|--include-untracked] [-a|--all] [-m|--message <message>]
             [--] [<pathspec>…]]
git stash clear
git stash create [<message>]
git stash store [-m|--message <message>] [-q|--quiet] <commit>
DESCRIPTION

Use git stash when you want to record the current state of the working directory and the index, but want to go back to a clean working directory. The command saves your local modifications away and reverts the working directory to match the HEAD commit.

The modifications stashed away by this command can be listed with git stash list, inspected with git stash show, and restored (potentially on top of a different commit) with git stash apply. Calling git stash without any arguments is equivalent to git stash push. A stash is by default listed as “WIP on branchname …”, but you can give a more descriptive message on the command line when you create one.

The latest stash you created is stored in refs/stash; older stashes are found in the reflog of this reference and can be named using the usual reflog syntax (e.g. stash@{0} is the most recently created stash, stash@{1} is the one before it, stash@{2.hours.ago} is also possible). Stashes may also be referenced by specifying just the stash index (e.g. the integer n is equivalent to stash@{n}).

DISCUSSION

A stash entry is represented as a commit whose tree records the state of the working directory, and its first parent is the commit at HEAD when the entry was created. The tree of the second parent records the state of the index when the entry is made, and it is made a child of the HEAD commit. The ancestry graph looks like this:

       .----W
      /    /
-----H----I

where H is the HEAD commit, I is a commit that records the state of the index, and W is a commit that records the state of the working tree.

命令

# **说明**:  
# git stash  仅对于跟踪文件有效,新建的未跟踪文件, 不受控 ,  一旦生成一个stash存储, 就会清空当前git 工作区和暂存区, 恢复到HADE指向的工作区状态, 可以使用git stash  apply  存储名 恢复到保存的存储状态,包含工作区和暂存区状态同时都会恢复;


git stash  
# git stash 命令会将未完成的修改的受控文件保存到一个栈上,而你可以在任何时候重新建立应用这些改动(git stash apply )
git stash list  # 查看存储
git stash apply  stash@{2}  #如果不指定一个存储,git认为指定的是最近的存储, 且它仅应用栈顶元素, 但不会删除栈顶元素
git stash drop  存储名 #删除指定存储
git stash pop  # 来应用存储然后立即从栈上扔掉它, 它是 git stash apply --> git stash drop的组合
实践

初始化一个git工作目录:
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587974945929.png
新建并进入分支test01, 新建一个文件:test01.txt

E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587975118645.png
由于该文件还处于位跟踪状态:

使用git stash 为当前工作区创建git存储,会提示没有任何修改可以保存
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587975230372.png
将该文件添加到暂存区:
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587979789042.png
说明: waring: LF will be replaced by CELF : 的提示信息:

# 是因为Window的换行符为\r\n ;  而 linux的换行符为 \n  ; 而mac的换行符为\r 
# git中对换行符的检查是默认按照linux规则, 所以会报该警告信息

# Git可以在你提交时自动地把行结束符CRLF转换成LF,而在签出代码时把LF转换成CRLF。用core.autocrlf来打开此项功能,如果是在Windows系统上,把它设置成true,这样当签出代码时,LF会被转换成CRLF:

$ git config --global core.autocrlf true

查看当前暂存区信息:
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587979839163.png
此时在将当前的修改提交到git存储中
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587976325870.png

会提示你还没有任何提交对象:

此时的对象目录.git/object,只有一个暂存区对象

在没有任何一次提交之前, .git/HEAD 信息虽然为 ref: refs/heads/master

但是此时并没任何提交对象, 所以 .git/refs/head/目录下没有任何文件(该文件名为提交对象的名字,内容为提交对象的hash值)

此时还没有任何分支存在, master分支也因 没有提交对象, 分支的建立是基于提交对象的一次保存,因此master分支也是不存在的;
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587979355380.png

需要先完成一次提交, 创建commit对象, 然后会发现refs/heads/master 才会存在
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587979972358.png
可以看到.git/refs/head/master 文件已存在

且生成了一个tree对象 和一个commit对象

此时在查看分支: master 分支建立完成
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587980066729.png

创建test01 分支:
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587980111189.png
在test01分支下建立新文件, 并创建git 存储, 因为新建的文件为未跟踪文件
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587980168199.png
查看暂存区
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587980360425.png
再次创建存储
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587980444443.png
发现一次存储其实默认完成了一次提交
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587983710541.png

但是,每次建立存储之后, 都会恢复到存储修改之前的commit 状态
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587984040848.png
而当前修改的存储对象中保存了一个机遇本次修改的commit对象

应用存储:
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587984153119.png
退出当前存储状态回到存储之前的commit对象状态 :
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587984218401.png
一次存储, 就是一次不进行HEAD移动的commit操作; 所有提交对象的创建完成,但是HEAD的状态任然会到本次存储之前的commit对象状态, 包括文档结构也会恢复;
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1587984675264.png

git 撤销与重置:

git checkout  --filename   # 工作区回调,即文件结构信息的回调
git reset HEAD  --filename  # 暂存区回调
撤销:

命令:

git  commit --amend
# 作用: 这个命令会将暂存区中的文件提交
	如果自上次提交以来你还未做任何修改(例如,在上次提交以后马上执行了此命令),那么快照会保持不变, 而你所修改的只是提交信息,
	如果你提交后忘记了暂存某些需要的修改,可以像下面这样的操作:
	git  commit  -m  "init commit"
	git  add  target_file
	git  commit  --amend
最终你只会有一个提交, 第二次提交将代替第一次提交的结果;

命令:

git  reset HEAD 文件名 
# 作用: 将文件从暂存区中撤回到工作目录

命令:

git checkout  --文件名
# 作用: 将在工作目录中对文件的修改撤销

注意: git checkout – [file] 是一个危险的命令, 这很重要; 你对那个文件的任何修改都会消失, 你只是拷贝了另一个文件来覆盖他, 除非你确实清楚要删除那个文件, 否则不要使用该命令

HEAD : 是当前分支引用的指针, 他总是指向该分支的最后一次提交;

​ 这表示HEAD 将是下一次提交的父节点, 通常理解HAD的简单方式,就是将它看成当前的提交快照;

重置:
移动HEAD

命令:

假设初始状态如下
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588007375782.png

git reset  --soft  HEAD~
#分析; 它本质上是撤销了上一次git commit 命令, 当你运行git commit 时 , git会创建一个新的提交对象,并移动head所指向的分支来使其指向该新的提交对象文件
#  当使用reset 回 HEAD~ (HEAD父节点)时, 其实是把该访问移动会原来的位置,而不会改变索引和工作目录;
#  现在你可以更新索引并在此运行git commit来完成 git commit  --amend  所要做的事;
#  这与改变HEAD本身不同(checkout 所做的, HEAD移动, 但是master分支并不动) ; 
#  reset 移动HEAD 同时也 修改当前指向的分支点 回撤到上一次提交位置
#  git reflog : 主要记录HEAD的变化

E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588005763360.png
实践:

新建一个工作区,包含三次提交对象:
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588006842306.png
查看提交记录:
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588006897395.png
此时 git 保存状态如下:
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588007267355.png
查看当前的暂存区, 工作目录 和 head , 当前commit对象:

v3版本的HEAD对象(当前HEAD指向), 树对象 和 tree对象记录的文件信息
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588008322120.png

v2版本的HEAD对象(当前HEAD的父对象HEAD~ ) , 和对应的tree对象 以及 tree对象记录的文件信息
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588008488031.png
v1版本的HEAD对象(当前HEAD对象的父对象HEAD~的父对象) , 和 对应的tree对象 以及 tree对象记录的文件信息
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588008573972.png
可以看到git 对象保存的层级关系清晰且独立保存的特点:

下面使用 git reset --soft HEAD~ 移动HEAD, 但不修改暂存区,和git对象(工作区文件信息)

移动HEAD
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588008928722.png
查看暂存区信息: 暂存区信息仍为v3
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588008953929.png
查看git 对象(工作区文件信息)
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588009022305.png
查看HEAD的移动记录:
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588009061118.png
查看当前HEAD对象, HEAD指向的tree对象, 以及tree对象的文件信息: 信息回撤到v2的状态
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588009277882.png

当前的状态如下:
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588009498805.png
尽管HEAD被回撤, 但是v3版本的提交对象数据依然存在,且当前的暂存区和git对象(工作区文件信息)并未修改

此时如果直接在此提交, 就会在v2版本处继续推进HEAD, 而原有v3版本的数据相当于游离出分支的主线, 除非特殊需要, 可以通过保存其hash值来查看内部数据, 他相当于一个自v2版本的一个分支,单数由于其分支名仍然保留为master的特殊游离分支;

测试: 我们将当前的暂存区(v3版本信息) 做一次提交,HEAD进行一次压栈处理
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588010161051.png
查看HEAD移动:
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588010202033.png

发现, 当前HEAD的记录,总是HEAD@{0} , 每次提交,HEAD链的层次+1

现在我们探查当前HEAD的层级信息:向前追踪:
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588010454576.png
对比前面的v3版本的提价对象
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588010619587.png
对比可以很明显发现, HEAD{0} 仍然和v3版本提交对象完全一致, 而HEAD{1}和 原来的v2版本提交对象完全一致

从这里可以看到, 由于我们使用 git reset --soft HEAD~ 仅仅是将提交对象的当前指向HEAD回撤, 当前的暂存区和git对象(工作目录信息) 不变的情况下, 直接重新提交, 那么被回撤后游离v3版提交对象信息依然可以完全应用起来

现在测试当我们回撤后, 如果修改暂存区信息后,再次提交,是否v3版本的游离节点是否会被忽略,而失去主线控制

执行回撤:
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588011025213.png
查看当前HEAD
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588011057770.png

有回到v2版本, v3版本进入游离状态,且当前的暂存区和git对象(git工作区文件信息) 保留v3

现在我们修改文件,更新暂存区,并完成一次提交 :
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588011229514.png
此时暂存区为v4 状态, 我们要查看当前HEAD的指向commit对象, 并对比原来v3版本的commit对象
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588011425895.png

可以看到此时的v4版本对象信息 并不和v3版本信息一致, 这是必须的毕竟文件信息都已不同

不过我们仍然可以从v3的对象追踪会v2 , 在从v2追踪会v1版本信息;也就是说v3版本的信息真正从master分支中游离出来, 成为自v2版本开出的一个分支名并未独立处理, 我们无法像通过git branch 分支名 命令创建的分支一样快速调节HEAD指向分支最新提交对象的方式来获取其节点数据, 但是他的完全符合分支的数据结构, 我们似乎可以修改v3节点的数据中的分支名来使其成为一个分支…

# 小结:  通过 git reset  --soft  HEAD~ 会撤的方式,可以完成一次提交信息的回撤,分支记录的重新提交更新, 而被回撤的一次记录会从分支树上脱离,避免分支版本中冗余的数据, 但仍然可以通过reflog记录中的HEAD 记录, 找回被遗弃数据;
更换暂存区的HEAD回撤

命令:

git  reset  [--mixed]  HEAD~
# 该命令将撤销上一次提交,还会取消暂存区所有的东西,相当于回滚到了git add 和 git commit 命令执行之前状态

E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588025476123.png

更新工作目录和暂存区的HEAD撤回

命令:

git  reset  --hard   HEAD~
# 该命令撤销上一次提交,还撤回到上次的缓存区,并更新到上一次的工作目录, 相当于本次提交的修改信息完全被撤回

E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588026072215.png

小结:
后悔药 :
	工作区: 如何撤回自己在工作目录中的修改:  git checkout  --filename
	暂存区: 如何撤回自己的暂存:  gitreset  HEAD  filename
	版本库: 如何撤回自己的提交:  git  commit  --amend
reset:
	git log  :  只显示用户操作的修改
	git  reflog :  显示所有HEAD的操作过程 # 信息保存在.git/logs/HEAD中
	# git reflog 并不能显示足够多的信息, 为了显示信息更加有用,# 我们可以使用
	git lot -g   # 该命令会以标准日志的格式输出引用日志信息
	三部曲: 
		1. 第一步: git reset  --soft  HEAD~  (--amend)
			#	动HEAD(带着分支节点)的回撤
	 	2. 第二部: git reset  [--mixed] HEAD~ 
	 		#	动HEAD(带着分支节点)的回撤
	 		#	暂存区也回撤
	 	3. 第三部: git reset  --hard  HEAD~
        	#	动HEAD(带着分支节点)的回撤
	 	   	#	暂存区也回撤
	 		#	工作目录也回撤
checkout
	git checkout  和 git  rest  --head  commitHash  的区别: 
	 1. checkout 只动HEAD   --hard  动HEAD且带着分支一起移动
	 2. checkout 对工作目录是安全的  --hard 是强制覆盖工作目录

路径reset 
	git  rest [--mixed] HEAD  filename (reset 命令会跳过第一步 HEAD 回撤)
		#  只动暂存区 
	#HEAD 指向 一个commit对象 -- 对应一个tree对象 -- 对应1到多个文件  --每个文件都对应一个git对象

注意点:

# 必须注意: --hard标记是reset命令唯一的危险用法,他也是Git会真正的销毁数据的仅有的几个操作之一, 其他任何形式的reset调用都可以轻松撤回, 但是--hard 选项不能; 因为它强制覆盖了工作目录中的文件; 在这种特殊的情况下我们的git数据库中的一个提交对象文件仍然保留, 我们可以通过reflog 来找到撤回的commit对象数据,但是若该文件还未提交,Git仍会覆盖它导致无法撤回;

路径reset

前面描述了rest的基本形式的行为, 不过你还可以给它提供一个作用路径; 若指定了一个路径,reset 将会跳过第1步,

(因为HEAD 对应一个commit对象 , 对应一个tree对象 , 会对应1个或者多个文件即git对象), 如果特指了某个文件, 肯定无法完整的代表一次提交的所用部分, 因此指定文件路径的rest会将它的作用范围指定的文件或文件集合; 这样做自然有他的道理;因为HEAD只是一个指针,你无法让它同时指向两个提交中各自的部分; 不过索引和工作目录 可以部分更新, 所以重置会继续进行第2, 3 步;

现在假设我们运行git reset test.txt (这其实是git reset --mixed HEAD test.txt)的简写形式

他会移动HEAD分支的指向(因为是文件这一步忽略)

让索引看起来像HEAD

所以他本质上只是将test.txt 从HEAD复制到索引中

最佳实践:
  1. 我们在一个分支中有了5次提交
  2. 现在想要回到第三次提交的状态, 修改开发方案
  3. 使用git reset --hear HEAD@{3}
  4. 后来发现新的开发方案不成立
  5. 又要回到原来的第5次提交的状态
  6. 这是可以再次使用 git reflog 找到原来的第五次的HEAD
  7. 使用git rest --heard HEAD{5} 硬重置到5的状态
  8. 当然也可以在原来5状态的提交对象上建立分支进行开发

git 的tag标签

git 可以给历史中的某个提交打上tag标签,以示重要,比较有代表性的是人们会用这个功能来标记发布的节点(v1.0)

列出标签:

命令:

git tag   # 列出所有tag标签列表
git tag -l  "v1.8.*"   # 列出标签名为v1.8开头的所有标签

创建标签:

git使用两种主要类型的标签, 轻量级标签 和 附注标签

  1. 轻量级标签 很像一个不会改变的分支, 他只是一个特定的提交的引用

     git  tag  v1.4
    
     git  tag v1.4 commitHash
    
    1. 附注标签 是存储在git数据库中的一个完整的对象,他们是可以被校验的, 其中包含打标签者的名字, 电子邮件地址, 时间日期 等, 还有一个标签信息, 通常建议 创建附注标签, 这样你可以拥有以上所有信息,但是如果你只想用一个临时标签,或者因为某些原因不想保存那些信息, 则可以使用轻量标签]
     git tag -a  v1.4
    
     git  tag  -a  v1.42  commitHash
    
     git  tag  -a  v1.4.4  commitHash  -m  "my version  v1.4.4"
    

查看特定标签:

​ git show 可以显示任意类型的对象 (git 对象, 树对象, 提交对象 , tag对象)

	git show tag_name

远程标签:

​ 默认情况下, git push 命令并不会传送标签到远程仓库服务器上, 在创建完标签以后你必须显式的推送标签到远程共享服务器上, 你可以运行

	git push  origin  (tag_name)
如果想要一次性的推送多个标签, 可以使用带有 --tags 选项的 git push 命令,这将会把所有不在远程仓库服务器上的标签全部送到服务器; 

	git push  roigin  --tags 

删除标签

git  tag  -d  v1.4   # 删除tag 标签 v1.4

检出标签:

如果你想查看某个标签指向的文件版本, 可以使用

git checkout  tag_name

虽然说这会是你的仓库处于"分离 头指针 detached HEAD"状态, 在分离头指针状态下, 如果你做了某些更改,然后提交他们, 标签不会发生该表,但是新的提交将不属于任何一个分支, 并且将无法访问, 除非访问确切的提交Hash, 因此如果你需要进行更改, 比如说你正在修复旧版本的错误-- 这通常需要创建一个新分支

git checkout  -b  version2

代码风格

Eslint

lint 是检验代码格式工具的一个统称,具体的工具有eslint jslint等

使用Eslint

  1. 确保你的电脑安装了node 和 npm 环境

    https://www.runoob.com/nodejs/nodejs-install-setup.html

  2. 首先 使用 git init 初始化git 仓库

  3. 创建项目:

    $ npm  init
    #  This utility will walk you through creating a package.json file.
    #  It only covers the most common items, and tries to guess sensible defaults.
    
    #  See `npm help json` for definitive documentation on these fields
    #  and exactly what they do.
    #  
    #  Use `npm install <pkg>` afterwards to install a package and
    #  save it as a dependency in the package.json file.
    #  
    #  Press ^C at any time to quit.
    #  package name: (eslink_demo)
    #  version: (1.0.0)
    #  description:
    #  entry point: (index.js)
    #  test command:
    #  git repository:
    #  keywords:
    #  author:
    #  license: (ISC)
    #  About to write to D:\eclipse-workspace_edit\eslink\eslink\work\eslink_demo\package.json:
    #  
    #  {
    #    "name": "eslink_demo",
    #    "version": "1.0.0",
    #    "description": "",
    #    "main": "index.js",
    #    "scripts": {
    #      "test": "echo \"Error: no test specified\" && exit 1"
    #    },
    #    "author": "",
    #    "license": "ISC"
    #  }
    #  
    #  
    #  Is this OK? (yes)
    
    
  4. 本地安装eslint

    $ npm  i  eslint  --save-dev
    #  npm notice created a lockfile as package-lock.json. You should commit this file.
    #  npm WARN eslink_demo@1.0.0 No description
    #  npm WARN eslink_demo@1.0.0 No repository field.
    #  
    #  + eslint@6.8.0
    #  added 133 packages from 83 contributors and audited 178 packages in 47.721s
    #  
    #  7 packages are looking for funding
    #    run `npm fund` for details
    #  
    #  found 0 vulnerabilities
    
    
  5. 设置package.json文件

    "script":{
        "lint": "eslint ./src",
        "lint:create": "eslint --init"
    }
    #  eslint  --init    # 生成eslint.js文件, 提供编码规范
    #  eslint ./src        #  使用 eslint 检查 ./sec目录下的js文件语法检查
    
  6. 运行 eslint init 进行初始化eslint

    $ npm  run  lint:create
    
    #  > eslink_demo@1.0.0 lint:create D:\eclipse-workspace_edit\eslink\eslink\work\eslink_demo
    #  > eslint --init
    
    ? How would you like to use ESLint? To check syntax, find problems, and enforce code style
    ? What type of modules does your project use? JavaScript modules (import/export)
    ? Which framework does your project use? Vue.js
    ? Does your project use TypeScript? No
    ? Where does your code run? (Press <space> to select, <a> to toggle all, <i> to invert selection
    ? Where does your code run? Browser
    ? How would you like to define a style for your project? Use a popular style guide
    ? Which style guide do you want to follow? Standard: https://github.com/standard/standard
    ? What format do you want your config file to be in? JavaScript
    #  Checking peerDependencies of eslint-config-standard@latest
    #  The config that you've selected requires the following dependencies:
    #  
    #  eslint-plugin-vue@latest eslint-config-standard@latest eslint@>=6.2.2 eslint-plugin-import@>=2.1
    #  8.0 eslint-plugin-node@>=9.1.0 eslint-plugin-promise@>=4.2.1 eslint-plugin-standard@>=4.0.0
    
    ? Would you like to install them now with npm? Yes
    #  Installing eslint-plugin-vue@latest, eslint-config-standard@latest, eslint@>=6.2.2, eslint-plugi
    #  n-import@>=2.18.0, eslint-plugin-node@>=9.1.0, eslint-plugin-promise@>=4.2.1, eslint-plugin-stan
    #  dard@>=4.0.0
    #  npm WARN eslink_demo@1.0.0 No description
    #  npm WARN eslink_demo@1.0.0 No repository field.
    #  
    #  + eslint-plugin-import@2.20.2
    #  + eslint@6.8.0
    #  + eslint-plugin-promise@4.2.1
    #  + eslint-plugin-vue@6.2.2
    #  + eslint-plugin-node@11.1.0
    #  + eslint-config-standard@14.1.1
    #  + eslint-plugin-standard@4.0.1
    #  added 72 packages from 43 contributors, updated 1 package and audited 390 packages in 69.851s
    #  
    #  19 packages are looking for funding
    #    run `npm fund` for details
    #  
    #  found 0 vulnerabilities
    
    #  Successfully created .eslintrc.js file in D:\eclipse-workspace_edit\eslink\eslink\work\eslink_de
    #  mo
    

    npm 会自动添加如下插件, 信息见package.json中

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IYlJhEpv-1588198153587)(E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588142963132.png)]

  7. 测试eslint 语法检查:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IZ841gTR-1588198153589)(E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588143134527.png)]

    运行命令:

    $ npm  run  lint
    
    #  > eslink_demo@1.0.0 lint D:\eclipse-workspace_edit\eslink\eslink\work\eslink_demo
    #  > eslint ./src
    #  
    #  
    #  D:\eclipse-workspace_edit\eslink\eslink\work\eslink_demo\src\index.js
    #    1:1   error  'cosole' is not defined                        no-undef
    #    1:12  error  Strings must use singlequote                   quotes
    #    1:16  error  Extra semicolon                                semi
    #    1:17  error  Newline required at end of file but not found  eol-last
    #  
    #  ✖ 4 problems (4 errors, 0 warnings)
    #    3 errors and 0 warnings potentially fixable with the `--fix` option.
    
    

    以上错误: 1.1 cosole 改为 cosole.log

    ​ 1.12 “a” 的双引号要改为单引号, selint规范要求, 字符串使用单引号

    ​ 1.16 多余的分号, selint 规范不需要结尾分号

    ​ 1.17 js文件要以一个新建空行结尾

    修改为如下:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vhDkO9lP-1588198153590)(E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588143474342.png)]

    再次运行:

    $ npm run  lint
    
    # > eslink_demo@1.0.0 lint D:\eclipse-workspace_edit\eslink\eslink\work\eslink_demo
    # > eslint ./src
    
    # 没有错误提示信息, 证明语法检查通过
    
  8. 安装husky , husky 会将钩子程序安装值 git 仓库中

    因为, eslint 的语法检查需要主动调用通过 npm run lint 调用 eslint .src 的命令

    我们需要将git 的提价过程中强制绑定eslint 语法检查, 如果语法检查不通过, 就禁止提交, 就需用husky 组件

    $ npm  install   husky  --save-dev
    
    #  > husky@4.2.5 install D:\eclipse-workspace_edit\eslink\eslink\work\eslink_demo\node_modules\husky
    #  > node husky install
    #  
    #  husky > Setting up git hooks
    #  husky > Done
    #  
    #  > husky@4.2.5 postinstall D:\eclipse-workspace_edit\eslink\eslink\work\eslink_demo\node_modules\
    #  husky
    #  > opencollective-postinstall || exit 0
    #  
    #  Thank you for using husky!
    #  If you rely on this package, please consider supporting our open collective:
    #  > https://opencollective.com/husky/donate
    #  
    #  npm WARN eslink_demo@1.0.0 No description
    #  npm WARN eslink_demo@1.0.0 No repository field.
    #  
    #  + husky@4.2.5
    #  added 32 packages from 19 contributors and audited 440 packages in 24.202s
    #  
    #  28 packages are looking for funding
    #    run `npm fund` for details
    #  
    #  found 0 vulnerabilities
    

    查看husky 是否安装成功: package.json 的 devDependencies: 列表中以包含husky组件
    E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588144533444.png

    查看目录,发现添加了一个 node_modules的目录:下面包含众多js 工具集

E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588144060733.png
这是我们进行js 语法检查的工具组件, 但是git 提交时并不需要提交这些东西

我们可以使用git status 查看
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588144445818.png

因此我们通过 git 的忽略配置 , 在工作目录下 创建.gitignore 文件, 如下所示
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588144275039.png
再次查看
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588144620300.png

现在测试: 将index.js 修改为错误的地方:
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588143835672.png

使用git add . git commit 提交测试
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588144702341.png

发现 eslint 插件并没有执行语法检查, 这是因为我们还没有给husky 运行添加前置 语法检查调用;

"husky" : {
     "hooks" : {
        "pre-commit" : "npm run lint"
     }
  }
 # 组件化的添加前置调用

E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588144901078.png

再次测试提交, 发现, git 提交时 , 自动进行了语法检查, 有错误,提交失败

$ git  commit -m  "first commit "
#  [master (root-commit) e462b1f] first commit
#   2 files changed, 5 insertions(+)
#   create mode 100644 .gitignore
#   create mode 100644 src/index.js
#  
#  Administrator@MS-20180303ISRT MINGW64 /d/eclipse-workspace_edit/eslink/eslink/work/eslink_demo (
#  master)
#  $ git commit  -m  "commit 1"
#  husky > pre-commit (node v12.16.2)
#  
#  > eslink_demo@1.0.0 lint D:\eclipse-workspace_edit\eslink\eslink\work\eslink_demo
#  > eslint ./src
#  
#  
#  D:\eclipse-workspace_edit\eslink\eslink\work\eslink_demo\src\index.js
#    1:1   error  'cosole' is not defined                        no-undef
#    1:12  error  Strings must use singlequote                   quotes
#    1:16  error  Extra semicolon                                semi
#    1:17  error  Newline required at end of file but not found  eol-last

修改 index.js 文件语法 , 再次提交

# 添加暂存区
$ git  add  ./
# 提交到git 仓库
$ git  commit  -m  "commit 2"
#  husky > pre-commit (node v12.16.2)

#  > eslink_demo@1.0.0 lint D:\eclipse-workspace_edit\eslink\eslink\work\eslink_demo
#  > eslint ./src

#  [master fb00557] commit 2
#  1 file changed, 1 insertion(+), 1 deletion(-)


本次提交OK , 测试 git 利用husky 绑定 eslint 语法检查组件, 保证代码质量的流程;

git分支小结:

分支本质上是一个提交对象,所有的分支都会有机会被HEAD所引用(HEAD一个时刻只会指向一个分支)

当我们有新的提交的时候,HEAD会自动携带当前持有的分支向前移动

创建分支: git branch branch_name

切换分支: git checkout branch_name

创建& 切换 git checkout -b branch_name

普通删除: git branch -d branch_name

强制删除: git branch -D branch_name

合并分支: git merge branch_name

  1. 快进合并:  不会产生冲突, 两个节点处在同一分支合并 
  	2. 典型合并:  有可能产生冲突, 不同分支的两个节点合并
  	3. 解决冲突:  打开冲突文件, 修改代码, 要 add 文件 到合并分支, commit 

查看分支列表; get branch

版本穿梭: git branch 分支名 commitHash

查看已合并分支列表: git branch --merged

查看未合并的分支列表: git branch --no-merged # 一旦有分支信息, 需要检查是否需要合并

存储分支: git stash

分支切换注意点:

  1. 在切换分支的时候一定要使用git status 查看分支保证分支为提交状态

  2. 允许切换分支:

    1. 分支上所有的内容处于 已提交状态
    2. 分支上所有内容是初始化创建 处于未跟踪状态(避免), 切换后,会污染切换分支
    3. 分支上的内容是初始化创建的, 第一次处于已暂存状态(避免),切换后,会污染切换分支
  3. 不允许切换的分支:

    1. 分支上所有的内容处于已修改状态, 或 第二次修改以后的已暂存状态
  4. 分支上工作还未完成,但是需要到其他分支解决问题,如果又不想提交当前未完成状态的分支信息

  5. 尽量保证提交的分支是完成阶段任何的状态,而不要是临时中间过程, 因为后期调用分支时

    通常是看做完结状态来使用的;

  6. 可以使用分支存储 git stash

    1. 实际上 git 存储 仍然完成了提交, 只是git lot 不做记录, 查看git reflot 仍然可以看到有默认提交
  7. git stash apply : 将栈顶的工作内容还原, 但不修改该栈内容

  8. git stash drop : 将栈顶的工作内容删除, 去除栈顶内容,就应该将其删除

  9. git stash pop : 取出栈顶内容,并且将栈顶工作内容删除

  10. git stash list

  11. 后悔药:

    1. 撤销工作目录的修改 git checkout --filename --> reset --hard
    2. 撤销暂存区的修改 git reset HEAD filename --> reset --mixed
    3. 撤销提交: git commit --amend --> rest --soft
  12. reset 三部曲:

  13. HEAD 是一个指向分支的最新commitHash的指针

  14. HEAD~ 是当前最新commitHash的父对象(前一个commit对象的hash)

  15. commitHash组成了一个栈结构的数据, HEAD 指向栈顶

  16. 每个一个commitHash 都是栈结构中的一个数据 :

    1. HEAD@{0}
    2. HEAD@{1}
    3. HEAD@{2}
  回撤分支:  git   reset   --soft  HEAD~/[commitHash]  修改HEAD  , 暂存区和 工作目录不修改

​				    git   reset   [--mixed]  HEAD~ / [commitHash]   修改HEAD  和 暂存区    | 工作目录动

​				    git   reset   --hard   HEAD~ / [commitHash]   修改HEAD 和 暂存区  和 覆盖工作目录

git工作空间的暂存区只有一个 对应文件  .git/index  加密文件
  1. 路径reset 所有的路径reset都要省略第一步重置HEAD内容

  2. get reset [–mixed] commitHash filename

 所谓第一步重置HEAD内容, 我们知道HEAD本质上是一个分支,分支的本质是一个提交对象

一个提交对象指向一个树对象, 而树对象有可能指向多个文件git对象,  一个git对象代表一个文件

HEAD 可能代表一些列文件的集合, 因此 路径reset 必须忽略第一步, 避免多个文件同时被修改

用 commitHash  中filename 的内容重置暂存区
  1. git checkout 和 git reset --hard commitHash 的区别:

  2. 共同点 : 需要重置HEAD , 暂存区 , 工作目录

  3. 不同点: checkout 对工作目录是安全的 reset --hard 是强制覆盖

    ​ checkout 动HEAD是不会带着分支走而是切换分支

    ​ reset --hard 是HEAD带着分支一起动(类比commit对HEAD的修改)

    checkout +路径

    ​ git checkout commitHash filename

    ​ # 重置暂存区

    # 重置工作目录

    git checkout --filename

    ​ # 重置工作目录

  4. eslint js代码检查工具

    1. 需要安装node.js
    2. 下载 npm install eslint -D
    3. 使用
      1. 生成配置文件: npx eslint --init
      2. 检查js文件: npx eslint 目录名
      3. 初始化selint时 需要选择不同的标准规则
        1. 字符串必须使用单引号
        2. 语句结尾不能有分号
        3. 文件的最后必须要有换行
  5. eslint 和 git 结合

  6. 使用husky

  7. 为git 仓库设置钩子程序

  8. 使用

    1. 在仓库初始化完成之后,再去安装husky

    2. 在package.js文件中添加配置

      ​ “husky” :{

      ​ “pre-commit” : “npm run lint”

      ​ // 在git commit之前一定要通过npm run lint 的检查

      ​ // 只有npm run lint 不报错时 commit 才能真正的运行

      ​ // 钩子程序查看:

      ​ }

远程仓库;

项目经理创建远程仓库:

首先登陆github官网. 打开自己的仓库
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588152033421.png
)]

点击New , 新家一个空仓库 仓库名使用test
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588152074965.png
在github创建一个空仓库
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588152204936.png
查看仓库列表:
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588152320239.png

打开新建的test仓库:
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588153612929.png

可以看到,里面给出了我们使用该仓库的一些说明:

项目经理创建本地git仓库

我们在本地创建一个git 仓库, 然后推到github远程仓库test

文件文件夹:E:\桌面\linux 实验\git 远程仓库

在此打开git bash 终端:

初始化本地仓库,并完成一次提交,分支才能建立OK
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588154288236.png

项目经理配置本地认证用户信息:

查看本地git 配置:需要配置user.name 和user.email

git config list
# 该信息 保存到 .git/config 文件, 也可以直接修改配置文件的方式进行X手写容易格式错误X
git config  user.name "用户名"
git config  user.email "用户邮箱"

# 删除配置
git config  --global  unset  user.name 
git config  --global  unset  user.email

E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588154667608.png
可以看到我们配置信息中已经配置了user.name 和 user.email

还配置了http.sslcainfo ; 这是github中的一种SSH证书进行认证的方式

我们在github setting中可以添加本地的ssh公钥,来认证本地证书, 然后本地的代码就可每次使用ssh方式提交代码,会自动附带该配置项的证书文件, 通过认证,提交
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588154991313.png
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588155310985.png

目前我们还没有给该仓库添加sshkey 所以无法使用该认证方式

项目经理为远程仓库配置别名:
$ git remote  add  origin  https://github.com/cythinamissTack/test.git

# git  remote add  远程仓库别名  远程仓库url 
项目经理推送提交信息到远程仓库
git push  origin  master 
# git push  别名  分支名
# 注意 要能够push 成功, 需要:
#  配置的用户名和邮箱就是github注册的用户名和邮箱, 
#  别名也要是配置正确的 远程url

然后会弹出一个github的登录窗口, 录入你的github远程仓库用户名和密码
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588156536222.png
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588156551662.png
现在查看远程仓库:
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588156593787.png
发现我们创建的文件README.md 和 内容#test信息已经提交OK

员工克隆远程仓库到本地

员工在本地新家一个文件夹 E:\桌面\linux 实验\git 远程仓库2

打开git bash

命令:

git clone  url  (克隆时不需要git init)
# 默认克隆时为远程仓库起的别名为origin 
# 远程仓库名字"origin" 与分支名 "master" 一样, 在git 中并没有任何特别的含义,同时 "master" 是当你运行git init 时默认创建的起始分支名,并需要在首次提交后才生成分支记录文件.git/heads/master  此时HEAD 的连接文件才有效;
# "master"分支名仅仅因为他的默认广泛使用而且git 默认创建而已,
# "origin" 远程认知的默认别名, 我们git clone 会默认会创建的一个分支, 可以认为是远程仓库的代理, 他维护了远程仓库的url 和认证信息, 每次push 或者 pull 都是从该分支上
推送或者拉取分支信息,他会将请求发送到真正的远程仓库,并将结果返回给本地仓库

git clone -o  baby  url   # 则指定了远程仓库的别名为 baby 

项目经理邀请成员加入团队

如果你想与他人合作, 并向给他们提交的权限, 你需要把他们添加为"collaborators" ; 如 小明, Bea , jefe 都在Github 上注册了, 你想给他们推送的权限, 你可以将他们添加到你的项目, 这样做会给他们"推送"权限, 就是说他们对项目有读写的权限;

​ 点击gitHub右边的"Setting" 连接 , 选择 Repositories 可以看到每个仓库后面都有一个"collablorators" 成员设置
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588181783592.png
点击 collablorators
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588181932606.png
点击; Invita a collaborator 邀请 成员
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588182060696.png

填写要求成员的账户, 待用户同意后, 他就拥有了修改权限;
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588183832047.png

该用户同意后就可修改代码了;

员工克隆项目修改后提交

如果本项目是public的, 其他用户可以git clone 下载该项目, 但是没有提交权限

如果他直接提交会报错:
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588182362057.png
添加完成后就可以提交了
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588182660031.png
然后向远程仓库push

git  push 
# 可以直接push 的前提是本地以创建了远程仓库代理origin(在git clone 时自动创建 )  
# 也可以如下方式
git  push  别名  分支名(输入用户名  密码 , 推完之后会附带生成远程跟踪分支[远程分支代理])

E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588182986770.png
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588183348068.png

项目经理更新修改:

项目经理查看本地仓库的远程仓库别名, 本地仓库状态, 和当前工作区信息
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588183959923.png
发现, 当前项目已经和github不同, gitHub上的代码已被另一个人修改更新

查看本地本地当前分支和远程分支代理是否Ok
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588184516153.png

因此, 项目经理需要更新本地分支 利用 远程分支代理 提取

git  fetch  origin  
#git fetch   远程跟踪分支别名 

E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588184802684.png
该操作时将github上的远程分支信息 提取到本地 远程跟踪分支 (可以理解为就是一个本地分支, 但它又有与github远程分支通讯的代理功能)

我们可以切换到这个远程跟踪查看
命令:

git checkout  origin/master
# git  checkout  远程跟踪分支别名/远程分支名

E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588184998115.png
说明:

这里提示, 我们切换到一个分离的HEAD 状态, 我们可以仔细检查代码 , 根据经验修改和提交代码, 而且此状态下我们可以丢弃任何提交 去 切换到其他分区这 不会影响到其他的分区

分裂的HEAD状态 ,是因为这里有两个HEAD 对象 一个 是HEAD 一个是FETCH_HEAD

HEAD 指向当前该分支在本地的commit对象的层次关系(栈结构)

而 FETCH_HEAD 则 记录的是github远程分支的commit对象的层次关系(栈结构)
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588185428540.png
而 现在要检查远程提取的代码是否有效, 假设我们检查后需要修改下test.txt文件
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588186164804.png

如果没有问题就将其合并到本地分支

首先切换到本地分支master

git  checkout  master

E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588186297795.png

说明:

当我们切换到本地分支master时, 他给出提示, 我们离开了一个已提交状态的分裂HEAD分支, 该分支体并没有关联任何本地分支, 因此所有的数据都没有办法保存;

因此我们在master本地分支合并merge 这个远程跟踪分支 时 , 发现合并进来的仍然为我们使用

命令:

 git  fetch   origin/master

获取的 github上的分支状态;

此时我在本地修改合并后的分支, 比如添加README.md 记录更新等
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588186760907.png

有个想法, 如果我们在那么特殊的远程跟踪分支上push 代码会怎样?

切换到远程跟踪分支:
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588187381855.png

在这个远程跟踪分支中做提交:
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588187431845.png
这个远程跟踪分支我们不能直接提交,

按照说明:

我们可以将本次在该远程跟踪分支中做的提交保存到一个本地分支
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588189388171.png
我们已成功将这个远程跟踪分支提交信息保存在了一个新建的本地分支中;

追踪该分支, 可以看到其分支沿着主线,一致可以追踪到最初一个README.md 首次提交对象
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588189670525.png

测试远程跟踪分支是否可以pull操作
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588189873947.png
发现依然不能使用pull操作;

项目经理首次push 通过fetch后分支代码

命令:

git  push  origin  master
# git   push  别名   本地分支名

E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588191164892.png
这里我们操作时发现一个错误, 我们不可以像员工通过克隆仓库代码后, 直接通过git push 简单的命令就可以提交到远程仓库, 必须指明远程仓库别名(代理仓库) 本地仓库名 才可以push 代码

这是什么原因呢?

这是因为 当员工通过git clone 命令 将远程仓库克隆到本地时, git 会自动为本地创建一个远程跟踪仓库(代理仓库) 并未其指定默认别名 origin , 通过该代理仓库, 将远程仓库的代码fetch提取下来, 然后使用使用这个远程跟踪仓库内使用命令 git switch -c 远程仓库名 的方式 将该远程跟踪仓库拷贝一份到本地仓库, 并切换到这个拷贝出来的本地仓库, 如此一来, 这个本地仓库就拥有了远程仓库的相同代码. 且 该有代理仓库拷贝而来的本地仓库还保留了和代理仓库的关联关系, 每次在这个代理复制的本地仓库简单使用git push 命令发出后 , 会发送给代理仓库, 代理库保留了该本地仓库和远程仓库的关联关系; 代理仓库会自动根据两个仓库的关联关系, 补全代码为

git  push    origin   master   

然后将本地master 分会代码 提交和自动代码(使用和远程仓库代码一致) 进行冲突校验, 校验通过, 将代码通过url发送给远程仓库, 远程仓库进行代码更新

然而, 项目经理首次新初始化了项目基础代码, 通过git push origin mster 推送到远程仓库, 该过程索然会在本地建立远程跟踪仓库(代理仓库) ,并完成代码推送, 但是 本地的仓库并非这个代理仓库主动建立的, 两个之间并没有建立管理关系, 要想和员工那样简单的通过git push 完成推送, 就需要手动建立这种关联关系

命令;

git  branch  -u   origin/master 
# git  branch  -u  远程仓库别名/远程仓库分支名  
#  -u  是 --set-upstream-to 的简写
# 该命令也可以写成: git  branch  --set-upstream-to  origin/master

实践:
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588192791407.png

分支提交冲突解决:

刚刚由于项目经理修改了test.txt文件, 但是员工并不知道

现在员工也修改了test.txt文件, git add test.txt --> git commit

然后向远程仓库提交
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588193335852.png

返现提交失败, 提示可能其他人修改了相同的文件, 并建议, 你首先要integrate 融合 远程代码

因此需要通过 git pull 先拉取远程代码 ,合并后在提交
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588193566628.png

可见test.txt文件中明确注明了冲突

<<<<<<

本地提交的冲突信息

=====

远程提交的冲突信息

>>>>>>

按照业务修改, 和其他提交人员协商确定修改方案, 修改冲突信息:
E:\桌面\linux 实验\Git学习笔记\Git 使用笔记.assets\1588194269432.png
修改完成后, 注意不要忘记 重新 提交 修改

git add test.txt 

git commit  -m "functiom 12-14 Ok commit 2"

git  push 

成功!!!

至此,一个项目的协同开发简单过程分析OK

问题是, 通过命令行方式提交的代码,冲突提示并没有精确到文件, 加入文件很多,不好查找

扩展知识

  1. 远程跟踪分支以(remore_alias/branch_name) 形式命名, 如果你想要查看最后一次与远程仓库origin 通讯时, master 分支的状态, 你可以查看origin/master分支

  2. 当克隆一个分支时, 他通常会自动的创建一个跟踪origin/master 的mager分支, 且将建立克隆的本地分支和远程跟踪分支的关联关系

  3. 当你想要公开一个分支时, 需要将其推动到右写入权限的远程库上, 本地的分支并不会自动与远程仓库同步,你必须显示的推动想要公开的分支;

    git push  origin   branchname
    # 这是将本地分支推送到远程仓库同名的分支上 
    

    这里简化工作; 真正的工作为; Git 自动将branchname分支名展开为refs/heads/branchname: refs/heads/branchname

    你也可以运行 git push origin branchname:branchname 他们效果是一样的相当于说他将本地的branchname 分支 将其作为远程仓库的 branchname 分支

    因此我们可以指定别名远程分支的名字

    git push  origin  branchname:servername
    # 这是将本地分支branchname推送到异名的远程仓库分支servername
    
  4. git  fetch   origin    # 这是将远程分支提取到本地远程跟踪分支上
    #  下一次其他协作者从服务器上抓取数据时, 他们会在本地生成一个远程跟踪分支,origin/servicename
    #  指向服务器servicename分支的引用
    # 要特别注意一点,  当提取到新的远程跟踪分支时, 本地不会自动生成一份可编辑的副本, 换句话说,这种情况下,不会有一个新的servicename分支, 只有一个不可以改 的origin/servicename 指针
    
    git  merge  origin:servicename
    # 可以运行git merge   origin/servicename  将这些工作合并到当前所有分支
    

    如果想要创建一个servicename分支, 并且该分支建立在远程跟踪分支上:

    git  checkout  -b  localname   origin/servicename
    # 直接通过拉取远程分支的方式创建本地分支, 可以是异名的
    # 该命令有个简写的方式
    git  checkout  --track  origin/servicename   # 该方式建立的本地分支只能和远程分支同名
    
  5. 查看所有跟踪分支

    git  branch  --vv
    
小结:

###### 三个概念:

  1. 本地分支 : 我们使用git init 初始化的分支, 或者 使用 git clone 的分支

  2. 远程分支: 在github 或者码云或者私有云仓库, 是一个通过url 网络连接 push 和pull主要用来长期保存稳定版项目信息

  3. 远程跟踪分支: 他是远程分支状态的引用(他的信息与远程分支一致), 他们是你不能移动的本地分支

    ​ 当你作任何网络通信操作时,他们会自动移动, 我们可以切换到这个特殊的分支,但是不能进行push 和pull 操作 , 本地无法直接操作该分支移动分支状态, 即使可以在分支内执行git add git commit等操作, 但是却无法保留或者在使用 git checkout 其他分支时 将信息保存, 但是可以使用

    git switch -c 新的分支名 , 完成将当前远程跟踪分支的提交状态保存到一个新建的本地分支, 同时直接切换到这个新的分支, 而 在远程跟踪分支中的所有操作完全丢失, 因为他要始终保持和远程分支信息一致

    它作为一个分支的数据, 他作为远程分支和本地分支的双向代理存在,在本地可以使用他的别名指代该分支

    通过 git push 远程跟踪分支(远程分支别名) 本地分支 : 将本地分支通过该代理提交到远程分支

    通过 git pull 远程跟踪分支(远程分支别名) /远程分支名 : 将远程分支通过该代理提取到本地分支

##### 分支的推送和拉取:

  1. 确保本地分支已关联了远程跟踪分支

    1. 拉取数据: git pull
    2. 推送数据: git push
  2. 如果没有关联远程跟踪分支

    1. 拉取数据 git pull origin/master
    2. 推送数据: git push origin master
  3. 一个本地分支如何去拉取一个远程跟踪分支

    1. 当克隆的时候 会自动生成一个 master 本地分支(并且自动关联了远程跟踪分支)

    2. 在新建其他分支时, 可以指定想要的远程跟踪分支

      1.  git   checkout  -b  本地分支名    远程跟踪分支名
      2.  git   checkout  --track   远程跟踪分钟
      
    3. 将一个本地分支关联远程跟踪分支

      ​ git branch -u origin/master

      ​ # git branch -u 远程仓库别名/远程仓库分支名

      # -u 是 --set-upstream-to 的简写

      ​ # 该命令也可以写成: git branch --set-upstream-to origin/master

##### 团队协作:

  1. 项目经理初始化远程仓库

    一定要初始化一个空的仓库,在github上操作

  2. 项目经理创建本地仓库

    1. git remote 别名 远程仓库url
    2. git init
    3. 将基础源代码复制进来
    4. 修改用户名和邮箱配置信息
    5. git add
    6. git commit -m "init commit "
  3. 项目经理推送本地仓库到远程仓库

  4. git push 别名/分支名 (输入用户名 / 密码 , push 完之后会生成远程跟踪分支)

  5. 成员去克隆远程仓库

  6. git clone 远程仓库url( 会自动在当前目录下初始化.git工作空间,默认生成远程仓库别名origin

  7. 成员添加功能代码

    1. 修改文件
    2. git add
    3. git commit -m " function 1-12 OK"
    4. git push 别名 分支(输入用户名,密码 , 推送完成附带生成远程跟踪分支)

##### 冲突

  	1. git  本地操作会不会 有冲突?
     		1. 典型合并的时候可能会有冲突,两个分支修改了相同的文件
  2. git  远程协作的时候, 会不会有冲突?
 		1. push 是时候,  有个人提交到了相同文件的修改
 		2. pull 操作的时候,  别修改了相同文件, pull到本地也是会冲突

me 将这些工作合并到当前所有分支


如果想要创建一个servicename分支, 并且该分支建立在远程跟踪分支上:

```bash
git  checkout  -b  localname   origin/servicename
# 直接通过拉取远程分支的方式创建本地分支, 可以是异名的
# 该命令有个简写的方式
git  checkout  --track  origin/servicename   # 该方式建立的本地分支只能和远程分支同名
  1. 查看所有跟踪分支

    git  branch  --vv
    
小结:

###### 三个概念:

  1. 本地分支 : 我们使用git init 初始化的分支, 或者 使用 git clone 的分支

  2. 远程分支: 在github 或者码云或者私有云仓库, 是一个通过url 网络连接 push 和pull主要用来长期保存稳定版项目信息

  3. 远程跟踪分支: 他是远程分支状态的引用(他的信息与远程分支一致), 他们是你不能移动的本地分支

    ​ 当你作任何网络通信操作时,他们会自动移动, 我们可以切换到这个特殊的分支,但是不能进行push 和pull 操作 , 本地无法直接操作该分支移动分支状态, 即使可以在分支内执行git add git commit等操作, 但是却无法保留或者在使用 git checkout 其他分支时 将信息保存, 但是可以使用

    git switch -c 新的分支名 , 完成将当前远程跟踪分支的提交状态保存到一个新建的本地分支, 同时直接切换到这个新的分支, 而 在远程跟踪分支中的所有操作完全丢失, 因为他要始终保持和远程分支信息一致

    它作为一个分支的数据, 他作为远程分支和本地分支的双向代理存在,在本地可以使用他的别名指代该分支

    通过 git push 远程跟踪分支(远程分支别名) 本地分支 : 将本地分支通过该代理提交到远程分支

    通过 git pull 远程跟踪分支(远程分支别名) /远程分支名 : 将远程分支通过该代理提取到本地分支

##### 分支的推送和拉取:

  1. 确保本地分支已关联了远程跟踪分支

    1. 拉取数据: git pull
    2. 推送数据: git push
  2. 如果没有关联远程跟踪分支

    1. 拉取数据 git pull origin/master
    2. 推送数据: git push origin master
  3. 一个本地分支如何去拉取一个远程跟踪分支

    1. 当克隆的时候 会自动生成一个 master 本地分支(并且自动关联了远程跟踪分支)

    2. 在新建其他分支时, 可以指定想要的远程跟踪分支

      1.  git   checkout  -b  本地分支名    远程跟踪分支名
      2.  git   checkout  --track   远程跟踪分钟
      
    3. 将一个本地分支关联远程跟踪分支

      ​ git branch -u origin/master

      ​ # git branch -u 远程仓库别名/远程仓库分支名

      # -u 是 --set-upstream-to 的简写

      ​ # 该命令也可以写成: git branch --set-upstream-to origin/master

##### 团队协作:

  1. 项目经理初始化远程仓库

    一定要初始化一个空的仓库,在github上操作

  2. 项目经理创建本地仓库

    1. git remote 别名 远程仓库url
    2. git init
    3. 将基础源代码复制进来
    4. 修改用户名和邮箱配置信息
    5. git add
    6. git commit -m "init commit "
  3. 项目经理推送本地仓库到远程仓库

  4. git push 别名/分支名 (输入用户名 / 密码 , push 完之后会生成远程跟踪分支)

  5. 成员去克隆远程仓库

  6. git clone 远程仓库url( 会自动在当前目录下初始化.git工作空间,默认生成远程仓库别名origin

  7. 成员添加功能代码

    1. 修改文件
    2. git add
    3. git commit -m " function 1-12 OK"
    4. git push 别名 分支(输入用户名,密码 , 推送完成附带生成远程跟踪分支)

##### 冲突

  	1. git  本地操作会不会 有冲突?
     		1. 典型合并的时候可能会有冲突,两个分支修改了相同的文件
  2. git  远程协作的时候, 会不会有冲突?
 		1. push 是时候,  有个人提交到了相同文件的修改
 		2. pull 操作的时候,  别修改了相同文件, pull到本地也是会冲突
Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐