Danmo的学习之路(Git详细版)

12.3

基本概念

集中式(svn)

svn因为每次存的都是差异 需要的硬盘空间会相对的小一点  可是回滚的速度会很慢
优点: 
    代码存放在单一的服务器上 便于项目的管理
缺点: 
    服务器宕机: 员工写的代码得不到保障
    服务器炸了: 整个项目的历史记录都会丢失

分布式(git)

git每次存的都是项目的完整快照 需要的硬盘空间会相对大一点
    (Git团队对代码做了极致的压缩 最终需要的实际空间比svn多不了太多 可是Git的 回滚速度极快)
优点:
    完全的分布式
缺点:    
    学习起来比SVN陡峭

git的配置

git --version 查看版本

git config --system/–global…

	/etc/gitconfig 文件:操作系统中对所有用户都普遍适用的配置。若使用 git
config 时用 --system 选项,读写的就是这个文件。
	 ~/.gitconfig 文件:用户目录下的配置文件只适用于该用户。若使用 git
config 时用 --global 选项,读写的就是这个文件。
	 .git/config 文件:当前项目的 Git 目录中的配置文件(也就是工作目录
中的 .git/config 文件)什么选项也不加,这里的配置仅仅针对当前项目有效。

每一个级别的配置都会覆盖上层的相同配置。

配置内容

第一个要配置的是你个人的用户名称和电子邮件地址。这两条配置很重要,
次 Git 提交时都会引用这两条信息,说明是谁提交了更新
,所以会随更新内容一
起被永久纳入历史记录。

$ git config --global user.name "damu" 
$ git config --global user.email damu@example.com
要检查已有的配置信息,可以使用 git config --list 命令
删除配置信息 git config --global --unset user.email

底层命令(理解原理)

基础的 linux 命令

clear :清除屏幕

echo 'test content':往控制台输出信息 
	echo 'test content' > test.txt 在“Git Bash Here”的文件夹内创建一个.text文件,内容为引号内的部分。

ll :将当前目录下的 子文件&子目录平铺在控制台

find 目录名: 将对应目录下的子孙文件&子孙目录平铺在控制台

find 目录名 -type f :将对应目录下的文件平铺在控制台

rm 文件名 : 删除文件

mv 源文件 重命名文件: 重命名

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

vim 文件的 url(在英文模式下)

	 按 i 进插入模式 进行文件的编辑 
	 
	按 esc 键&按:键 进行命令的执行
	
	 q! 强制退出(不保存)
	 
	 wq 保存退出
	 
	 set nu 设置行号

.git目录

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

区域

工作区(不会被保存)、暂存区(暂时保存几次修改)和版本库。

git对象(数据对象)

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

存储为git对象

命令:

echo 'test content' | git hash-object -w --stdin 
	-w 选项指示 hash-object 命令存储数据对象;若不指定此选项,则该命令仅返回对应的键值(hash)
	 --stdin(standard input)选项则指示该命令从标准输入读取内容;若不指定此选项,则须在命令尾部给出待存储文件的路径 
git hash-object -w 文件路径 存文件 
git hash-object 文件路径 返回对应文件的键值 d670460b4b4aece5915caf5c68d12f560a9fe3e4

如果加-w,成功存储,那么.git/object 下的info和pack中会有内容。

一些解释:

  • hash-object 是一个键值对。
  • 加-w,既会存储,也会显示hash。
  • | 表示两个指令一起执行。
  • echo ‘test content’| git-hash-object -w --stdin (从控制台中拿内容)和 先输入echo ‘test content’ > test.txt ,再输入 git hash-object -w ./test.txt(从文件中拿内容) 的是一样的。 但是生成的hash不一样。
  • 只有第一次创建文件时可以从控制台中拿内容,参考下方“对一个文件进行简单版本控制”,修改文件再次存储时,只能采用从文件中拿内容的方式。
  • 关于warning:LF是windows中的换行符,CRLF是linux中的换行符,git认为空格不对,所以自动换成linux中的空格。

查询版本库内文件

命令: 
find .git/objects -type f 
返回: 
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4 
	这就是开始时 Git 存储内容的方式:一个文件对应一条内容。校验和的前两个字符用于命名子目录,余下的 38 个字符则用作文件名。
	即:存储后的目录名=hash的前两位,文件名=hash后边的38位。

根据键值拉取数据

命令: 
git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4 
	-p 选项可指示该命令自动判断内容的类型,并为我们显示格式友好的内容 
返回: 
对应文件的内容

如果直接用cat,会显示乱码(因为被压缩过)

显示内部存储的对象类型

命令:
git cat-file -t 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a
	cat-file -t 可以让 Git 告诉我们其内部存储的任何对象类型
返回:
blob

对两种存储方式(见上方粗体),都使用此命令,返回的都是blob,说明无论是存文件,还是存控制台中的内容,最终存到git仓库中都是一个git对象,这个git对象是blob类型的(是一个key-value键值对)。 所以git对象是存储内容的(但不能存储版本)。*

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

### 创建一个新文件并将其内容存入数据库 
命令: 
echo 'version 1' > test.txt 
git hash-object -w test.txt 
返回: 
83baae61804e65cc73a7201a7252750c76066a30 
### 向文件里写入新内容,并再次将其存入数据库 
命令: 
echo 'version 2' > test.txt 
git hash-object -w test.txt 
返回: 
1f7a7a472abf3dd9643fd615f6da379c4acb3e3a
	注意两次的hash不一样
### 查看数据库内容 
命令: 
find .git/objects -type f 
git cat-file -p 83baae61804e65cc73a7201a7252750c76066a30 
git cat-file -p 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a 

git cat-file -t 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a 
	利用 cat-file -t 命令,可以让 Git 告诉我们其内部存储的任何对象类型

备注:

  • 称git对象不能存储版本的原因是:首先创建一个新文件,存储一次,更新一次,再存储一次…任何再创建一个新文件,存储一次,更新一次,再存储一次…此时项目的版本包含两个文件,但每个git对象都只能查看一个文件的内容。即git对象只能代表“文件的不同版本”,不能代表“项目的不同版本”。
  • 在 Git 中,文件名并没有被保存——我们仅保存了文件的内容。
    在这里插入图片描述

12.4

树对象

树对象(tree object),它能解决文件名保存的问题,也允许我们将多个文件
组织到一起。Git 以一种类似于 UNIX 文件系统的方式存储内容。所有内容均以
树对象和数据对象(git 对象)的形式存储,其中树对象对应了 UNIX 中的目录项,
数据对象(git 对象)则大致上对应文件内容。一个树对象包含了一条或多条记录(每条记录含有一个指向 git 对象或者子树对象的 SHA-1 指针,以及相应的模式、类型、文件名信息)。一个树对象也可以包含另一个树对象。

树对象相当于 “版本的快照”。

查看暂存区

git ls-files -s 可查看暂存区

构建

第一步:创建暂存区

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

命令:
① git update-index --add --cacheinfo 100644 83baae61804e65cc73a7201a7252750c76066a30 test.txt 
	文件模式为 100644,表明这是一个普通文件 
	100755,表示一个可执行文件; 
	120000,表示一个符号链接。
	
	--add 选项: 
	因为此前该文件并不在暂存区中 首次需要—add 
	
	--cacheinfo 选项: 
	因为将要添加的文件位于 Git 数据库中,而不是位于当前目录下,所以需要—cacheinfo
	
② git write-tree 
通过① ②,可构建一个树对象。

第二步:更新版本
新增 new.txt 将 new.txt 和 test.txt 文件的第二个个版本塞入暂存区。并通过 write-tree 命令生成树对象。

命令: 
echo 'new file' > new.txt 

用vim为test.txt 写入新的内容,更新到第二个版本:
git update-index --cacheinfo 100644 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a test.txt
 
git update-index --add new.txt 
git write-tree

第三步:更新树对象
将第一个树对象加入第二个树对象,使其成为新的树对象。

命令: 
git read-tree --prefix=bak d8329fc1cc938780ffdd9f94e0d364e0ea74f579 (树对象的hash)
git write-tree 
read-tree 命令,可以把树对象读入暂存区

此处:
在这里插入图片描述

一般情况:
在这里插入图片描述

提交对象

相当于给树对象装了一个包裹,并提供了补充信息(作者、提交者、注释)

格式

提交对象的格式很简单:

  • 它先指定一个顶层树对象,代表当前项目快照;
  • 然后是作者/提交者信息(依据你的 user.name 和 user.email 配置来设定,外加一个时间戳);
  • 留空一行,最后是提交注释。

创建提交对象

创建提交对象 
echo 'first commit' | git commit-tree d8329f 
	(前面是树对象的hash)
	(以后每一次都要求在后面加上 上一个提交对象的hash)
	(hash不用输入完整)
返回:
fdf4fc3344e67ab068f836878b6c4951e3b15f3d

查看提交对象 
git cat-file -p fdf4fc3 
返回: 
tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579(-t 返回commit)
author Scott Chacon <schacon@gmail.com> 1243
committer Scott Chacon <schacon@gmail.com> 1243
first commit

接着,我们将创建另两个提交对象,它们分别引用各自的上一个提交(作为其
父提交对象):
echo 'second commit' | git commit-tree 0155eb -p fdf4fc3
cac0cab538b970a37ea1e769cbbde608743bc96d
echo 'third commit' | git commit-tree 3c4e9c -p cac0cab 
1a410efbd13591db07496601ebc7a059dd55cfe9

注意:git commit-tree 不但生成提交对象 而且会将对应的快照(树对象)提交到本地库中
在这里插入图片描述
提交对象把右边的对象都封装了。
只需要明白:项目的版本是一个提交对象,但本质上版本的快照是树对象。

高层命令

新建目录(文件夹)——命名为workspace
git init 初始化仓库,生成.git目录
此时workspace目录,就是工作区
版本库在./.git/objects
创建暂存区后,在./.git/index

CURD

CURD指:增加create、检索retrieve、更新update、删除delete。

git add

git add ./

  • 原理:将工作目录中修改的文件做成git对象放到版本库,再放到暂存区。
    (工作目录→版本库→暂存区)
    注意:此时版本库内是git对象!

  • 它会检查有几个文件发生了改变,工作目录中修改了几个文件,就生成几个git对象。并且生成git对象是增加,而不是覆盖(即它不会管你这个文件之前有没有git对象,它只管生对发生改变的文件生成新的git对象)。

git add 不仅可以把修改的文件放到暂存区,还可以把它们变成跟踪状态。

git commit

git commit -m “注释信息” 提交并加上注释
git commit -a 放到暂存区和提交到版本库一步完成(选项-a和-m可以一起用)

-a只能用于已跟踪过的文件

git commit 在vim中写完注释,再提交(用于注释很长的情况)

  • 只有在提交时,会参照暂存区,做成一个树对象,放到版本库里面,然后拿出树对象,加上注释,成为一个提交对象。

  • 一个完整的流程,至少包含git对象、树对象、提交对象各一个。一次提交只能有一个树对象和提交对象,git对象可以有很多。

以上总结:

	git操作最基本的流程:
	    创建工作目录 对工作目录进行修改
	    git add ./(下面是此高级命令包含的底层命令)
	        git hash-object -w 文件名(修改了多少个工作目录中的文件 此命令就要被执行多少次)
	        git update-index ...
	    git commit -m "注释内容"
	        git write-tree
	        git commit-tree

跟踪文件

  • 工作目录下面的所有文件都不外乎这两种状态:已跟踪 或 未跟踪
  • 已跟踪的文件是指本来就被纳入版本控制管理的文件,在上次快照中有它们的记录,工作一段时间后,它们的状态可能是已提交,已修改或者已暂存所有其他文件都属于未跟踪文件。它们既没有上次更新时的快照,也不在当前的暂存区域。
  • 使用 Git 时的文件状态变化周期如下图所示:
    在这里插入图片描述

untracked 未跟踪 unmodified未修改(也可以是提交后的状态)
modified修改未暂存 staged 暂存未提交

使用git status查看文件的状态,红色代表修改未暂存,绿色代表暂存未提交,什么也没有,则是提交后的状态。

如果加到暂存区后还要修改,则修改后还要继续add放到暂存区。

git diff            查看哪些修改还没有暂存
git diff --staged   查看哪些修改以及被暂存了 还没提交

移除

git rm 文件名 删除工作目录中对应的文件 再将修改添加到暂存区(最后还需要commit提交)

运行 git rm 就相当于运行了下面两条命令:

$ rm README.txt README
$ git add ...

重命名

git mv 原文件名 新文件名 将工作目录中的文件进行重命名 再将修改添加到暂存区

运行 git mv 就相当于运行了下面三条命令:

$ mv README.txt README
$ git rm README.txt
$ git add README

查看历史记录

git log 显示全部信息
git log --pretty=oneline 放在一行内显示
git log --oneline 放在一行内显示,并且只显示hash的前几位

git log
在这里插入图片描述
git log --pretty=oneline
在这里插入图片描述
git log --oneline
在这里插入图片描述
12.5

分支

本质:分支是活动的指针,指向提交对象。提交对象一直往前更新时,指针也在一直往前更新。

为什么我们要分支:
分支可以新开辟一块空间做事情,不影响之前的代码。
这段代码写得好,就合并分支;写得烂,就删掉分支。

创建分支

命令:git branch
作用:
为你创建了一个可以移动的新的指针。 比如,创建一个 testing 分支:git branch testing。这会在当前所在的提交对象上创建一个指针
注意:
git branch 分支名 创建 一个新分支,并不会自动切换到新分支中去

git branch -b 分支名: 创建分支,并且切换过去

切换分支

git checkout 分支名

切换分支的坑:(第一次提交之前)在切换分支之前,要先确保状态“干净”(全部commit),否则会污染其它分支。

删除分支

命令: git branch -d 分支名(空分支可以用-d,有内容的分支应先合并变为空分支,再-d;未合并,不需要的分支的用-D强制删除)
(不能自己删自己,删除前要切换到别的分支)

查看项目分叉历史

如果直接查看日志,可能看不到某些分支内的历史,这个指令可以看到所有历史:

git log --oneline --decorate --graph --all

如果觉得太复杂,可以给指令“配别名”:
git config --global alias.别名 “原指令”

在这里插入图片描述

补充

git branch -v
可以查看每一个分支的最后一次提交(可以被上方指令取代)
git branch name commitHash(commit对象的hash)
新建一个分支并且使分支指向对应的提交对象(用于临时查看以前版本的代码,但是此时分支还没有切过去,得再用git checkout)

合并

git merge 分支名(会将这个分支合并到现在所处的分支内)

快进合并:由于当前 master 分支所指向的提交是你当前提交的直接上游,所以 Git 只是简单的将指针向前移动。 换句话说,当你试图合并两个分支时,如果顺着一个
分支走下去能够到达另一个分支,那么 Git 在合并两者的时候,只会简单的
将指针向前推进(指针右移),因为这种情况下的合并操作没有需要解决的分
歧——这就叫做 “快进(fast-forward)

以一个实例讲讲快进合并和典型合并:

①我现在正在写一个项目iss53,写到50%。
②现在紧急要求改一个bug。
③我先将50%的iss53提交,然后新建并切换到hotfix。
④现在把bug改好了,把hotfix合并到master,并删掉master(此时为快进合并)

起先:
在这里插入图片描述
移动指针:
在这里插入图片描述
合并完成:
在这里插入图片描述
⑤在 hotfix 分支上所做的工作并没有包含到 iss53 分支中。 如果需要拉取 hotfix 所做的修改,可以使用 git merge master 命令将 master 分支合并入 iss53 分支,或者也可以等到 iss53 分支完成其使命,再将其合并回 master 分支。
⑥此时的合并,是两个分支的合并,就可能会产生冲突:
在这里插入图片描述

在这里插入图片描述

修改成这样即可:
在这里插入图片描述
⑦再git add即可。

存储

有时,当你在项目的一部分上已经工作一段时间后,所有东西都进入了混乱的状
态,而这时你想要切换到另一个分支做一点别的事情。 问题是,你不想仅仅因为
过会儿回到这一点而为做了一半的工作创建一次提交。 针对这个问题的答案是
git stash 命令
git stash 命令会将未完成的修改保存到一个栈上,而你
可以在任何时候重新应用这些改动(git stash apply)

git stash list:查看存储
git stash apply stash@{2} :应用存储
	(如果不指定一个储藏,Git 认为指定的是最近的储藏)
git stash drop 加上将要移除的储藏的名字来移除它
git stash pop 来应用储藏然后立即从栈上扔掉它(相当于apply和drop的结合,一般用这个)

在这里插入图片描述

后悔药

git checkout

命令:git checkout – 文件名
作用:将在工作目录中对文件的修改撤销。

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

git reset

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

git commit –amend

命令: git commit --amend
作用:
这个命令会将暂存区中的文件提交。
如果自上次提交以来你还未做任何修改(例如,在上次提交后马上执行了此命令),那么快照会保持不变,而你所修改的只是提交信息。

如果你提交后发现忘记了暂存某些需要的修改,可以像下面这样操作:
git commit -m ‘initial commit’
git add forgotten_file
git commit –amend
最终你只会有一个提交 - 第二次提交将代替第一次提交的结果。

reset三部曲

git reset --soft HEAD~
~可以用^表示:
HEAD 表示当前版本
HEAD^ 上一个版本
HEAD^^ 上上一个版本
HEAD^^^ 上上上一个版本

可以使用 ~数字表示:
HEAD~0 表示当前版本
HEAD~1 上一个版本
HEAD^2 上上一个版本
HEAD^3 上上上一个版本

也可以回退至指定版本:把HEAD~换成commithash
在这里插入图片描述
还可以这样:
在这里插入图片描述

使用该命令之前的状态:
在这里插入图片描述
之后的状态:
在这里插入图片描述
该命令相当于git commit –amend ,版本库切回到上一个版本,此时用git log就会看不到v3版本,但是用reflog还是可以看到。

git reset [–mixed] HEAD~

–mixed为默认值,可以不写(HEAD~也可以不写)

该命令在切换版本库的同时,切回上一个暂存区。

可以把HEAD~换成treehash,回退至指定版本的暂存区。

三部曲中只有该命令后边可以加文件名,有几个文件名就将几个文件从暂存区回退至工作目录。

git reset --hard HEAD~

切换版本库的同时,切回上一个暂存区,还切回上一个工作区。

这意味着在工作区所做的一切工作会被覆盖,因此慎用。

git checkout commithash & git reset --hard commithash区别:
1.  checkout只动HEAD    --hard动HEAD而且带着分支一起走
2.  checkout对工作目录是安全的   --hard是强制覆盖工作目录
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值