一、安装Git

二、使用Git前的最小配置。

Git作为一个版本控制系统,在后期使用过程中必然会有多个人共同参与到一个项目的开发与管理中去,为了方便区分某次提交是哪个用户提交的,我们需要在使用Git之前,将自己的【用户名】、【邮箱】信息配置进去,方便日后再版本变更的时候,Git及时方便地通知每个参与者。
1,配置user信息。包括user.name和user.email的配置,方法如下:

  1. git config --global user.name 'your_name'
  2. git config --global user.email 'your_email@domain.com'

【思考】上面配置命令中的global有什么作用呢?

2,config的三个作用域。
(1)缺省等同于local。

  1. git config --local //local的配置项只对某个仓库有效
  2. git config --global //global的配置项对当前用户的所有仓库都会有效
  3. git config --system //system的配置项对系统所有登录的用户有效

(2)显示config配置信息的方法,加 —list

  1. git config --list --local //显示local配置的信息
  2. git config --list --global //显示global配置的信息
  3. git config --list --system //显示system配置的信息

三、创建第一个Git仓库

1,创建Git仓库有两种方式:
(1),把已有的项目代码纳入Git管理,方法如下:

  1. cd 项目代码所在的文件夹
  2. git init

(2),新建的项目直接用Git管理,方法如下:

  1. cd 某个文件夹
  2. git init your_project //git会在当前路径下创建和项目名称同名的文件夹
  3. cd your_project

2,使用第二种方法创建git仓库。
(1)新建一个project文件夹,在该文件夹路径下调出命令窗口,然后执行

  1. git init my-pro

(2)在project文件夹下我们会得到一个空的、已经被git管理了的文件夹my-pro,如下图:
image.png
(3)在my-pro下执行 ls -al 命令,查看该文件夹下的内容。会发现有一个隐藏的.git文件,这个文件将会在后面记录版本管理过程中的相关信息。
image.png

(4)在my-pro下新建一个readme.md文件,并尝试执行如下命令,提交这个新增文件的更新行为。

  1. git commit -m'add a readme file'

结果如下图所示:
image.png
整个报错信息,说明了一件事,这个readme.md的文件目前还没有被我们的git管理起来,如果在这种情况下是无法执行commit操作的。

(5)使用如下命令,将readme.md纳入git管理。(我们会发现在vscode中readme.md的文件状态发生变化)

  1. git add readme.md

(6)使用如下命令,查看各个文件被git的管控状态:

  1. git status

改命令执行结果如下图:
image.png

(7)再次执行 git commit 命令,查看执行结果。
image.png

(8)这个时候,readme.md这个文件的版本状态才真正的被git管控了起来。

3,配置git的local用户信息。
如果我们同时配置了global与local信息,在进行文件修改提交的时候,git优先使用local的配置信息。

  1. git config --local user.name '卢大湿'
  2. git config --local user.email 'dashi@vip.com' //注意,这里使用真实邮箱,方便git将版本变更信息通知相关项目成员

四、使用commit多次提交,认识git使用流程

1,向我们之前创建的my-pro仓库里添加index.html文件。
**
(1),在my-pro文件夹下新建index.html文件,然后使用git status查看版本管理状态。
image.png

(2),执行如下命令,先将index.html添加到暂存区。

  1. git add index.html

(3),再次使用git status查看版本管理状态。
image.png

(4),使用如下命令,可以查看我们的【文件版本变化历史】,以及操作变更的用户信息。
image.png
由此也可以观察出,我们第一次执行readme.md添加的时候,在没有配置local信息的情况下,使用的是global的用户信息。当我们添加index.html的时候,因为已经配置了local,所以使用的是local中的用户信息。

(5),从上面的操作流程我们可以得出一个git内部版本管理的执行流程,具体如下图:

image.png
当我们新建文件之后,这个文件并没有被git管理起来,然后:
step1,当我们执行git add files 命令的时候,这个新增的文件将被记录在【暂存区】
step2,当我们执行git commit命令的时候,这个被记录在【暂存区】的文件才会更新到版本历史中去。

2,新增css文件夹,并在文件夹中新建style.css,并通过如下命令,继续提交管理style.css文件。

  1. git add css/style.css
  2. git commit css/style.css -m'add the style file'

3,修改index.html,然后重新执行**commit**操作。使得index.html中引入style.css中的样式并生效

4,然后在执行**git log**观察刚才一系列操作后,所有文件版本历史。
**
image.png

5,可以尝试用同样的方法,新增一个script.js文件。
这里可以引入并了解一下,git的批量处理命令:

  1. git add -u //将文件的修改、文件的删除,添加到暂存区。
  2. git add . //将文件的修改,文件的新建,添加到暂存区。
  3. git add -A //将文件的修改,文件的删除,文件的新建,添加到暂存区。

五、通过git log查看版本演进

1,使用git log 查看版本演进。

2,使用如下命令,可以使得所有变化较为简洁地展示。

  1. git log --oneline

执行结果:
image.png

3,使用如下命令,可以只查看最近几次的变更情况。

  1. git log --oneline -n2 //只查看最近两次的变更

4,如果我们设置了分支,可以通过如下命令查看所有分支的变更情况。

  1. git log --oneline --all

六、gitk:通过图形界面管理版本

在当前项目my-pro的目录下通过 gitk 命令,就可以调出图形化管理界面。

image.png

七、探秘.git目录

1,Git目录
‘Git目录’ 一般就是指项目根目录下的’.git’目录。’Git目录’是为你的项目存储所有历史和元信息的目录 - 包括所有的对象(commits,trees,blobs,tags), 这些对象指向不同的分支.
每一个项目只能有一个’Git目录’(这和SVN,CVS的每个子目录中都有此类目录相反), 这个叫’.git’的目录在你项目的根目录下(这是默认设置,但并不是必须的). 如果你查看这个目录的内容, 你可以看所有的重要文件:

  1. $>tree -L 1
  2. .
  3. |-- HEAD # 这个git项目当前处在哪个分支里
  4. |-- config # 项目的配置信息,git config命令会改动它
  5. |-- description # 项目的描述信息
  6. |-- hooks/ # 系统默认钩子脚本目录
  7. |-- index # 索引文件
  8. |-- logs/ # 各个refs的历史信息
  9. |-- objects/ # Git本地仓库的所有对象 (commits, trees, blobs, tags)
  10. # 存放对象 .git/objects/ 文件夹中的子文件夹都是以哈希值的前两位字符命名,
  11. # 每个object由40位字符组成,前两位字符用来当文件夹,后38位做文件。
  12. `-- refs/ # 标识你项目里的每个分支指向了哪个提交(commit)。
  13. refs/heads: #存放分支
  14. refs/tags: #存放tag,又叫里程牌 (当这次commit是具有里程碑意义的 比如项目1.0的时候 就可以打tag)

完整的git目录内容,可以通过如下命令完成:

cd .git   //进入git目录
ls -al   //展示git目录内容

2,查看目录相关命令
cat命令主要用来查看文件内容,创建文件,文件合并,追加文件内容等功能。
cat HEAD 查看HEAD文件的内容
git cat-file 命令 显示版本库对象的内容、类型及大小信息。
git cat-file -t b44dd71d62a5a8ed3 显示版本库对象的类型
git cat-file -s b44dd71d62a5a8ed3 显示版本库对象的大小
git cat-file -p b44dd71d62a5a8ed3 显示版本库对象的内容

八、commit、tree、blob三者的关系

1,通过分析我们新增style.css时的整个git内部记录来理解。
image.png
git为了很好的存储每一次版本变化的信息,会在每次执行commit的时候,对整个项目形成一个快照,这个快照内部按照tree与blob逐层嵌套下去,最终形成了当前commit之后整个项目版本的整体信息流。

2,我们通过命令,将Add style.css这次commit操作时上图中的关系,在项目中进行验证。
(1)使用 git log 命令,调出所有操作历史,找到Add style.css操作时生成的唯一id标识。
image.png

(2)使用如下命令,调出当前操作下的版本快照信息。

git cat-file -p 4a8bd87a4  //这里的4a8bd87a4只要能够唯一表示出此次commit,可以略写一部分

结果如下:
image.png

可以看到此次commit操作快照下有个tree。

(3)我们可以根据每次得到的tree的唯一id标识,进一步的剖析整个快照内容,跟第1步中的分析图进行对比理解。
image.png

九、深入理解.git文件中的objects

新建一个git仓库watch_git_objects,在该仓库中新建doc文件夹,并在该文件夹中新建readme文件,在readme文件中写入“hello,world”,以备后续测试使用。

1,先在watch_git_objects目录下,执行git status命令,查看结果。
image.png

2,这个时候我们还没有将任何文件加入到暂存区,我们再执行如下命令,观察此时.git中的objects内容:

find .git/objects -type f

我们发现,这个命令执行后没有打印出任何东西,说明objects此时内容为空,如下图:
image.png

3,执行命令将doc文件夹加入到暂存区,再次通过系列命令进行查看objects。

git add doc
git status
find .git/objects -type f

其结果如下:
image.png

4,通过下面的命令,进一步查看这个objects中的唯一id下,具体存放的内容:

Yooye-2:04,watch_git_objects yooye$ find .git/objects -type f #查看objects中存放的内容
.git/objects/2d/832d9044c698081e59c322d5a2a459da546469
Yooye-2:04,watch_git_objects yooye$ git cat-file -t 2d832d90  #查看objects中对应唯一id下的内容类型
blob
Yooye-2:04,watch_git_objects yooye$ git cat-file -p 2d832d90  #查看objects中唯一id下存放的内容
hello,world
Yooye-2:04,watch_git_objects yooye$

5,执行commit操作,并通过一系列命令查看objects中存放的内容及其相互关系:

Yooye-2:04,watch_git_objects yooye$ git commit doc -m'Add readme file' #【1】执行commit提交
[master (root-commit) e06684e] Add readme file
 1 file changed, 1 insertion(+)
 create mode 100644 doc/readme
Yooye-2:04,watch_git_objects yooye$ find .git/objects -type f  #【2】commit后,发现objects中多处很多信息
.git/objects/08/3e18d286d8d2a9eda8c62d9d98935dcc07ca4c
.git/objects/ba/8711bd7540faa22e4e76a1cf5c78501fa4e162
.git/objects/e0/6684e722d90d09953e25b92a2fa042061c25eb
.git/objects/2d/832d9044c698081e59c322d5a2a459da546469
Yooye-2:04,watch_git_objects yooye$ git cat-file -t 083e18d28 #【3-1】查看第一条objects信息类型
tree
Yooye-2:04,watch_git_objects yooye$ git cat-file -p 083e18d28 #【3-2】查看第一条objects信息内容
040000 tree ba8711bd7540faa22e4e76a1cf5c78501fa4e162    doc
Yooye-2:04,watch_git_objects yooye$ git cat-file -t ba8711bd7 #【4-1】查看第二条objects信息类型
tree
Yooye-2:04,watch_git_objects yooye$ git cat-file -p ba8711bd7 #【4-2】查看第二条objects信息内容
100644 blob 2d832d9044c698081e59c322d5a2a459da546469    readme
Yooye-2:04,watch_git_objects yooye$ git cat-file -t e06684e7  #【5-1】查看第三条objects信息类型
commit
Yooye-2:04,watch_git_objects yooye$ git cat-file -p e06684e7  #【5-2】查看第三条objects信息内容
tree 083e18d286d8d2a9eda8c62d9d98935dcc07ca4c
author yooye <597665748@qq.com> 1551319223 +0800
committer yooye <597665748@qq.com> 1551319223 +0800

Add readme file
Yooye-2:04,watch_git_objects yooye$ git cat-file -t 2d832d90  #【6-1】查看第四条objects信息类型
blob
Yooye-2:04,watch_git_objects yooye$ git cat-file -p 2d832d90  #【6-2】查看第四条objects信息类内容
hello,world
Yooye-2:04,watch_git_objects yooye$

上图中commit与objects的变化关系,可以用下图来进行具象化描述:
image.png

十、认识分离头指针及其注意事项

1,分离头指针(detached HEAD)的含义
image.png
通常,我们工作在某一个分支上,比如 master 分支。这个时候 master 指针和 HEAD 指针是一起前进的,每做一次提交,这两个指针就会一起向前挪一步。但是在某种情况下(例如 checkout 了某个具体的 commit),master 指针 和 HEAD 指针这种「绑定」的状态就被打破了,变成了分离头指针状态。
可以查看【这篇文章】,进一步了解HEAD指针。

2,基于前面的my-pro仓库,演示分离头指针的出现场景。
image.png

也就是说,当我们使用git checkout对某个commit进行操作的时候,我们的HEAD指针便于该仓库的分支产生分离,也就是‘You are in ‘detached HEAD’ state.’

3,分离头指针状态下的危险操作。
当我们处于【分离头指针状态】下,我们的操作是没有更仓库的任何分支挂钩的,如果在这种状态下对项目进行了大量的改动,当我们切出这个状态进入某个别的分支之后,刚才对项目所做的所有改动都会被git当做垃圾给清除掉,因为它觉得这些不与任何分支挂钩的内容是不重要的。下面我们演示这种危险操作:
(1)在分离头指针状态下,打开style.css进行部分修改编辑(例如:将边框改为蓝色)。

(2)在命令行中通过git status,查看结果。

Yooye-2:my-pro yooye$ git status
HEAD detached at 4a8bd87
Changes not staged for commit:   #git在提醒我们,当前的变更没有跟任何分支关联
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   css/style.css

no changes added to commit (use "git add" and/or "git commit -a")

(3)对此次变更执行commit操作。

Yooye-2:my-pro yooye$ git commit -am'change the box border-color' #【1】执行commit操作,正常来说我们应该先通过git add将变更添加到暂存区
[detached HEAD 413552e] change the box border-color  #git 提醒我们在分离头指针状态下执行了某个变更
 1 file changed, 1 insertion(+), 1 deletion(-)
Yooye-2:my-pro yooye$ git log  # 【2】查看整个变更历史
commit 413552ec3d7983f10ffcaf1879b72857f8675779 (HEAD)  #头指针指向当前变更,处于分离状态
Author: 卢大湿 <dashi@vip.com>
Date:   Thu Feb 28 11:24:35 2019 +0800

    change the box border-color

commit 4a8bd87a46e650b40c7a02c420bf0fa55a2ff487
Author: 卢大湿 <dashi@vip.com>
Date:   Wed Feb 27 13:40:30 2019 +0800

    add the style file

(4)这时如果我们得到新的任务,要求修复master分支下的某个问题。如果不新建分支或强制将上次修改绑定到已有分支,就可能导致上次修改内容丢失。

Yooye-2:my-pro yooye$ git checkout master  #切换到master分支进行操作
Warning: you are leaving 1 commit behind, not connected to #git发出警告,告诉你刚离开了一个没有与任何分支相关联的commit,该commit在后期可能会被丢掉
any of your branches:

  413552e change the box border-color

If you want to keep it by creating a new branch, this may be a good time
to do so with:

 git branch <new-branch-name> 413552e # git 提醒你通过这个方式,可以为这个commit单独创建一个新的分支

Switched to branch 'master'

(5)使用 gitk —all 命令查看可视化面板,看我们【修改边框颜色】的变更到底存在与否。
image.png
其实我们发现,这次commit变更并没有被记录下来。当然,如果这个时候我们醒悟了,想要将这个commit记录进来,可以执行后续步骤。

(6)使用在第4步git提示中出现的命令,将commit记录到新的分支。

git branch change-box-border-color 413552e

当我们再次通过gitk —all打开可视化面板后,发现这个commit已经被记录在一个新的分支中了。
image.png

十一、HEAD与branch之间的关系

可以查看【git官方-分支简介】,进一步理解分支及HEAD的移动机制。