天天看点

git基本概念与原理

                                                      git基本概念与原理

-----------------------------------------------------------------------------------------------------------------------------------------------

一、git的安装与简单配置

1、安装

apt install -y git-core

2、配置git名称与邮箱

git config --global user.name "chenux"

git config --global user.email "[email protected]"

git config --global --list   

mkdir 目录 && cd 目录

git init git_repo   #git_repo就是仓库,其目录下有个.git

git基本概念与原理

3、git设置优先级

git config --system:使对应配置针对系统内所有的用户有效

git config --global:使对应配置针对当前系统用户的所有仓库生效

git config --local:使对应配置只针对当前仓库有效

local选项设置的优先级最高。

4、仓库中有文件后,保存库状态

在仓库中执行命令git add . && git commit -m "status01"

给仓库里加了些文件

git基本概念与原理

5、gitk,图形化git管理工具,apt install -y gitk

git基本概念与原理

6、此图状态为在4中已经执行过的状态,此时输入指令更改文件内容

echo “aa11a1” >1.txt \

echo “b2b2b2” >> 2.txt \

touch project/pro-2.txt

执行后保存状态git add. && git commit -m “status02”,此时再启动gitk

git基本概念与原理

再次稍作修改后保存一次状态

git基本概念与原理

二、git对象

1、三种不同类型的git对象:

(1)blob:一个blob就是由一个文件转换而来,blob中只会存储文件的数据,而不会存储文件的元数据

(2)tree:一个tree就是有一个目录转换而来,tree只会存储一层目录信息,它只存储它的直接文件和直接子目录的信息,但子目录中的内容它不会保存

(3)commit:一个commit就是我们的git commit提交,它指向了一个tree,这个tree保存了某一时刻项目根目录中的直接文件和直接目录信息

总而言之,commit指向了tree,tree又指向了自己根下直接文件的blob或者子目录的tree,子目录的tree对象指向了子目录的文件blob和子子目录的tree,以此类推

2、每个git对象都有一个唯一的哈希码(sha1算法),它是一个40位的16进制数

3、在初始提交后再进行二次提交,若存在

文件f1没有修改,在此过程后,它的blob哈希没有改变;

文件f2修改内容,在此过程后文件为f22,它的blob哈希发生改变;

存放f1和f2的目录alpha,在此过程中它的tree哈希发生改变,但指向文件f1的blob仍为a以前的blob

git基本概念与原理

三、git过程

1、目录结构

git基本概念与原理

可以看到,仓库内部除了自己建的文件,还有一个.git目录,该隐藏目录在git init时候就已经生成了。

.git目录:可以称之为版本库

2、在之前提交的命令中,输入的是

(1)git add -a:选择将哪些变化的内容加入到下一次提交中,这些变化内容会被索引或者暂存起来,此时生成文件的blob

(2)git commit -m “statusname”:创建commit提交对象,执行命令后git会根据索引/暂存中的结构,创建出对应的tree对象,之后git会创建一个commit对象,将新创建的commit对象指向新创建的tree

(3)这个新的提交产生后,记录了一个状态,该提交也会指向前一次的提交,每个提交都会指向自己的父提交

git基本概念与原理

(4)图片所示,当修改3.txt后,由于它是位于上一次状态中,修改它后会变红,等git add 3.txt后它的状态变为绿色,表明已加入暂存区,做好随时被提交的准备。4.txt由于没有提交,一直是红色,表明还在工作区

git基本概念与原理

四、git使用

1、git log

显示所有的git提交,git log --oneline,git log的简单模式

git基本概念与原理

git cat-file -t 哈希值 查看对象的类型

git cat-file -p 哈希值 查看对象的内容

git rev-parse 13614 通过简短的哈希值获取到整个哈希值

2、有如下操作:

git init git_test

cd git_test

echo f1>f1                                                                                         echo f2>f2

git add .

git commit -m "test01"

echo -e "haha \nheihei" >> f1

git commit -m "test02"

我们可以得知f1产生了变化,如果我们此时后悔了对f1的操作,执行命令

git log --oneline,先找出对应提交的哈希值,之后git reset --hard 82a23e7

git基本概念与原理

不难发现,虽说文件恢复到test01的状态了,但是刚才test02没了,现在如果想再次回到test02,该如何操作?

(1)git reflog,输入后可以查看之前的test02哈希码,查询到后 git reset --hard 哈希码便可回复

git基本概念与原理

(2)验证下,恢复成功

git基本概念与原理

五、git分支

1、在实际环境中,文件的修改是纵容交错的,所以存在一个问题:文件回退时,是否会影响其它文件?这里就会引入一个概念:分支

git status,显示位于主分支master

git基本概念与原理

创建新分支时,默认以当前所在分支为基础创建,创建后分支的最新提交与master一样

(1)创建分支,使用命令git branch分支名

git基本概念与原理

创建后工作区仍处在master分支上,未切换到新建的slave分支。分支的创建,并不是说明slave复制了master的分支,而是git只是创建了slave分支指针,指向了master分支对应的最新提交。

逻辑图如下:

git基本概念与原理

(2)查看分支情况

git branch、git branch -v、git branch -vv

git基本概念与原理

(3)分支切换

git checkout 分支名

切换后工作区也随之切换,之后的git add与git commit命令影响切换后的分支

git基本概念与原理

现有操作

git基本概念与原理

切换到我的分支slave后,输入指令后再提交,此时逻辑图就变为了

git基本概念与原理

master上有5个提交,而slave上有6个提交。这时在切回master分支,看下f2文件,内容并没有改变。

git基本概念与原理

 同理,若此时在master分支修改任何文件,切换到slave分支是看不到master修改的文件,因此在项目时可以利用分支,负责某个项目a模块开发的修改文件在分支1,负责b模块开发的修改文件在分支2,后期项目合并时分支合并即可。具体的合并分支在后面。

六、head

(1)head指向分支

我们从之前图中可以看到,通常情况下,当处于哪个分支,head就指向了哪个分支,所以git是通过head找到自己所处的工作区,在git仓库下的.git里,可以查看head的文件内容,其内部显示就是目前指向的分支。

git基本概念与原理

(2)head指向提交

特殊情况下,head可以指向某个提交,这种情况称作头分离,detached head。

git基本概念与原理

如上图所示,head没有指向任何一个分支,而是指向了commit2这个提交。怎样才能出现这种效果呢?git checkout commit_hash,如图示

git基本概念与原理

此时输入指令,git log --oneline --all --graph

git基本概念与原理

再看下此时的git status

git基本概念与原理

分离头使用场景:

对该提交点的文件可以随便看看,或者做一些实验性的修改,并且可以将这些修改做成 提交,提交后会组成匿名分支,如果最后实验结果不满意可以丢弃之前实验行的提交, 如果实验结果满意,就可以创建一个新的分支,来永久保存这些提交。

示例:首先分离头已经指向了51fe144,此时输入了以下指令:

sed -i "s/\:/\-/g" 1.txt

git add 1.txt  && git commit -m "head_modify_1.txt"

echo headtest2 > 1.txt

git add 1.txt  && git commit -m "head_modify_1.txt-02"

修改了两次,提交了两次,我们此时通过图形工具看一下

gitk --all

git基本概念与原理

注:这里分离头选的提交刚好选到master分支的最新提交了,这不能说明分离头是从master分支分出来的

修改完成后,随便切换一个分支,会出现提示,比如我在git checkout test后,有图

git基本概念与原理

如果修改项目后实验结果满意,就可以使用提示的命令

git branch 分支名 哈希值

输入git branch headfile 65a96e4后

git基本概念与原理

如果不想保存实验性修改,切换分支后不用去管提示即可

七、差异比较

1、为比较差异,我们此处创建一个新的用来比对仓库

#git init git_test && cd git_test

#cat > test1 << eof

> 1

> 2

> 3

> eof

#cat > test2 << eof

> a

> b

> c

#git add . && git commit -m “new test1&2”

之后做出修改:

#sed -i “s/2//” test1 && echo haha >> test1

#sed -i "s/c/cdef/" test2

做出修改后,我们并没有git add将变化添加到暂存区,所以当前工作区和暂存区的内容是不同的,查看不同,使用命令git diff

git基本概念与原理

查看单个文件变化的命令:git diff -- 文件名,该命令可以跟多个文件,git diff -- test1 test2 ...

git基本概念与原理

2、查看工作区与当前分支的区别,使用命令git diff head,查看工作区与某个分支的区别,如果head未指向需要查看的那个分支,使用命令git diff 分支hash,比如说我目前在test分支,我查找test分支与之前status02分支的区别,找到status02的哈希码,之后便可以使用命令查看区别了。具体如下图:(使用另一个提交比较多的git仓库作示例)

git基本概念与原理

结论:git diff比较的是工作区与暂存区的差异,git head比较的是工作区与提交的区别

3、再次回到新建的git_diff库,我们继续做出两次修改

#echo test1 >>test1

#echo test2 >test2

#git add -a

#git commit -m "first modify"

#echo test1-2 >> test1

#echo test2-2 >> test2

#git commit -m “second modify”

查看git log --oneline后获得两次提交的哈希码,之后可以通过命令

git diff 提交hash1  提交hash2,此命令查看两次提交的差异

如下图所示:

git基本概念与原理

当然,图中7ac86fc也是我们head的指向处,此处使用命令git diff cd692e5 head也可以

如果比对这次提交与前一次的提交,使用命令git diff head head~,这是一种简易写法,其它简易写法如下:

head:等于head~0,表示最新的一次提交

head~:等于head~1,表示最新提交的前一次提交

head~~:等于head~2,表示最新提交的前前一次提交

head~~~:等于head~3,表示最新提交的前前前提交

另:根据提交名获取对应的哈希码,使用命令举例:

git rev-parse head~

git rev-parse master

4、如果是分支之间的比对,比如说git diff master slave,此时对比的是两个分支各自最新提交的比对。

如图所示

git基本概念与原理

总结:

#git diff==>比较工作区和暂存区

#git diff head==>比较工作区和当前分支最新的提交,head可以换成别的分支的名字,比如test分支,"#git diff test"表示比较当前工作区和test分支最新的提交之间的差异,也可以把head替换成任何一个commit的id,表示比较当前工作区

和对应提交之间的差异。

#git diff --cached==>比较暂存区和当前分支最新的提交

#git diff -- file1==>比较工作区和暂存中file1文件的差异

#git diff -- ./file1==>只比较工作区和暂存区中file1文件的差异

#git diff -- file1 file2==>比较暂存区file1和file2文件差异

#git diff -- dir1/ ==>只比较工作区和暂存区中dir1目录中所有文件的差异

#git diff head -- ./file1 ==>只比较工作区和当前分支最新的提交中file1文件的差异,head可以替换成分支名或者commitid

#git diff branch01 -- ./file1==>只比较工作区和branch01分支最新的提交中file1文件的差异

#git diff --cached branch01==>比较暂存区和branch01分支最新的提交

#git diff --cached branch01 --./file1==>只比较暂存区和branch01分支最新的提交中file1文件的差异

#git diff head~ head==>比较当前分支中最新的两个提交之间的差异

#git diff head~ head -- file1==>比较当前分支中最新的两个提交中的file1文件的差异

#git diff commit01 commit02==>比较两个commit之间的差异

#git diff commit01..commit02==>同比较两个commit之间的差异,与上个命令等效

#git diff branch01 branch02==>比较两个分支上最新提交之间的差异

#git diff branch01..branch02==>比较两个分支上最新提交之间的差异,与上个命令等效

三、撤销暂存中的变更

1、平时进行版本管理中,修改某处代码提交了,之后后悔了怎么办?

使用命令,git reset head,此操作为“文件修改已记录到暂存中,但后悔这么做,恢复到git add之前”,也就是把暂存区恢复到与最新的commit状态保持一致。如图所示

git基本概念与原理

从图中我们看出,git reset head撤销了之前的git add操作,f1和f2的修改又回到了工作区。

我们这里是撤销了所有文件的更改,如果只想撤销一个文件的更改,使用命令

git reset head -- f1

git基本概念与原理

2、git reset、git reset --hard和git reset --soft

(1)git reset = git reset --mixed

git reset head,将所有已经暂存的内容从暂存区撤销了(即暂存区与最近提交中的状态一致)

git reset commit_hash,将head指针指向该次提交,并且将提交中的内容同步到暂存区,但工作区中内容不受影响。产生的结果是工作区记录的是reset前的最新提交与reset后的提交的变化内容,在git add和git commit之后,文件依然是reset前的文件,但head指向了reset后的提交。此处示例git reset commit_hash:

首先我们新建了一个新git库,并做了7次提交,之后git reset到第3次提交

git基本概念与原理

此时我们git diff,可以看下工作区与第3次提交的差异

git基本概念与原理

这也是第3次提交与我们git reset前的最新提交相比产生的差异,哪怕是git add之后继续git commit,结果也是git reset前的结果,但是head此时在第3次的提交上。

git基本概念与原理

git reset --hard head,将所有区域恢复成了最近的提交中的状态(即工作区、暂存区都与最近提交中的状态一致)

(2)git reset --hard commit_hash,将head指向该次提交,并且将所有区域内容进行同步,也就是恢复到该次提交状态。此处示例git reset --hard commit_hash:

#echo "1 2 3" > f1

#echo "a b c" > f2

#git add .

#git commit -m "first add f1&f2"

#echo "456" >>f1

#git add f1

#git commit -m "second modify f1"

#echo "def" > f2

#git add f2

#git commit -m "third update f2"

#echo "linux" >> f1

#echo "chen" >>f2

#git commit -m "4th update f1&f2"

git基本概念与原理

git reset --hard commit_hash,回到first f1&f2这个提交点

git基本概念与原理

(2)git reset --soft

此命令只将head指针指向commitid对应的提交,但是不会操作暂存区和工作区,也就是说,当前分支中的最新提交会变成commitid对应的提交,工作区和暂存区中的内容或者变更不会受到任何影响。此处示例:git reset --soft

如图中所示,我们将提交指向了最初新建的commit,文件结果没有改变

git基本概念与原理

3、git checkout撤销文件

撤销工作区已修改但未git add进入暂存区的文件,使其回到上一次暂存后的状态,如果不存在上一次的暂存,则回到最新的提交状态。该命令的使用,对象文件必须之前被git add追踪过,若是新建的文件没有被追踪过,此撤销方法对其无效。

git checkout -- file,若是该目录全部撤销更改,git checkout -- .

git基本概念与原理

四、git合并分支

1、合并方向

git基本概念与原理

如图示,有两种情况如左右两图,分支b是基于分支a产生的分支,红色部分是分支a的提交,橙色部分是分支b的提交,左图为合并分支后合并分支的head在a上,分支b的head仍在原处;右图同理亦然。

2、fast-foward

git基本概念与原理

上图所示即为分支a与分支b的合并,不过我们也可以使用一种快捷的合并方式:fast-forward,也译为“快进”或者“快速重定向”,这种情况下的快速合并,最终结果会变为如图:

git基本概念与原理

此种情况为:基于分支a创建的分支b,分支a没有任何新提交产生,如果此时将分支a合并到分支b,只需要将分支A的指针指向到B分支的最新提交即可。这就是fast-forward。

git基本概念与原理

如图所示,右图分支a产生分支B后又产生了新的提交,所以不能用fast-forward的合并方式

示例:首先输入以下指令,slv1从master分出去之后,master再无新的提交,slv1产生了新的提交

#touch f1

#git add f1  

#git commit -m "add f1"

#echo f1> f1 && git add . && git commit -m "insert f1 in f1"

#git branch slv1

#git status

#git checkout slv1

#touch f2 && git add f2 && git commit -m "touch f2 at slv1"

#git log --oneline

#echo "f2 in slv1" > f2 && git add f2 && git commit -m "insert f2 in f2 at slv1"

输入指令之后,我们的git符合了可用fast-forward的模型

git基本概念与原理

此时我们进行分支合并

git merge 分支名

先git cheout 分支a ,再git merge 分支b:将分支b合并到分支A,

git基本概念与原理

图中所示,这种方式即为fast-forward,git log --oneline可用看到head同时指向了两个分支

git基本概念与原理

3、正常分支合并

建立个如下图的模型

git基本概念与原理

首先有如下操作:

#echo 1 > 1.txt && git add . && git commit -m "touch 1"

#echo 2 >> 1.txt && git add . && git commit -m "insert 2 to 1"                                                                             

#git branch slv01

#echo 3 >> 1.txt  && git add 1.txt && git commit -m "insert 3 to 1"

#git checkout slv01

#echo a > a.txt && git add a.txt && git commit -m "touch a"

#echo ab >> a.txt && git add a.txt && git commit -m "insert ab to a"

gitk --all看到模型

git基本概念与原理

此时再合并分支:git checkout master && git merge slv01

输入后会弹出nano编辑器,编辑器是需要为合并后的新提交而准备。

git基本概念与原理

不添加就用它的默认注释即可。

gitk后看到结构已变为:

git基本概念与原理

4、常用合并命令

#git merge 分支a:表示将分支a合并到当前分支。

#git merge --no-ff 分支a:表示将分支a合并到当前分支,但是明确指定不使用"fast-forward"的模式进行合并

#git merge --ff-only 分支a:表示将a分支合并到当前分支,但是只有在符合"fast-forward"模式的前提下才能合并成功,在不符合"fast-forward"模式的前提下,合并操作会自动终止,换句话说就是,当能使用"fast-forward"模式合并时,合并正常执行,当不能使用"fast-forward"模式合并时,则不进行合并。

#git merge --no-edit 分支a:表示将a分支合并到当前分支,但是没有编辑默认注释的机会,也就是说,在创建合并提交之前不会调用编辑器(上文的示例中会默认调用vim编辑器,以便使用者能够有机会编辑默认的注释信息),换句话说就是,让合并提交直接使用默认生成的注释,默认注释为" merge branch 'branchname' "

#git merge 分支a --no-ff -m "merge a into master,test merge message":表示将a分支合并到当前分支,并且使用-m参数指定合并提交对应的注释信息。

注意,为了保险起见,需要同时使用"--no-ff"参数,否则在满足"fast-forward"模式的情况下,会直接使用"fast-forward"模式进行合并,从而忽略了-m选项对应的注释信息(因为使用"fast-forward"模式合并后不会产生新提交,所以为提交准备的注释信息会被忽略)

5、合并冲突解决

如果两个分支中同一个文件中的同一行内容不一样,合并分支时就会出现冲突,此时需要我们认为介入确认,这就是解决冲突的过程。

示例:首先输入指令造成两条分支同一文件同一行内容不同

#git init git_test

#echo 1 > f1.txt && git add . && git commit -m "add 1 in f1"

#echo 2 >> f1.txt && git add f1.txt && git commit -m "add 2 in f1"

#sed -i "s/2/2master/" f1.txt

#git add f1.txt && git commit -m "modify 2 at master"

#git checkout -b slv01        --------------->新建并切换新分支                                                                                    

#sed -i "s/2/2slv01/" f1.txt

#git add f1.txt && git commit -m “modify 2 at slv01”

得到结果:

git基本概念与原理

切到master分支,进行合并,有结果

git基本概念与原理

(1)对于一样的内容已经合并,对于冲突内容给出提示,修复成一样的内容或者git merge --abort放弃合并。

此时再看f1.txt,会标出冲突结果:

当前分支中的冲突内容: "<<<<<<< head"与"=======" 之间。

另一条合并分支中的冲突内容: "======="与"<<<<<<< new" 之间。

git基本概念与原理

我们取消冲突,git merge --abort后查看git status,已经提示干净的工作区了

(2)更改冲突文件使其不冲突

将两个分支中的f1都修改后提交,变为2master 2slv01,之后git merge后就进入了nano编辑器编辑自己想要的注释了。

(3)合并后对于之前的slv01分支,就可以不要了,处于非slv01分支下删除slv01分支,git branch -d slv01。

当存在某个分支没有合并过并且需要删除时,git会提示,如果不予理会这种提示,可以使用命令:git branch -d 分支名

五、github

github:git的远程仓库

1、使用前准备

(1)https://github.com注册账号

注册好后登录账号,右上方选new repository

git基本概念与原理

继续进行创建远程仓库

git基本概念与原理

创建好以后屏幕左侧会有自己的远程仓库名,点击进去可以看到连接自己远程仓库的两种方式,https或者ssh

git基本概念与原理

(2)ssh方式添加公钥

右上角姓名处下箭头点击settings,之后选择ssh and gpg keys

git基本概念与原理

建立公钥私钥:

ssh-keygen -t rsa,建立密钥对

git基本概念与原理

去查看公钥文件,将文件内容写入github的ssh下

git基本概念与原理

点击add ssh key

至此,github上的远程仓库可以使用ssh方式连接了。

2、git clone

git clone [email protected]:json-chenux/test.git

注意:如果这里提示ssh拒绝连接的权限问题,需要将之前本机做过ssh免密登录时生成的id_rsa.pub文件中公钥内容粘贴至列表

git remote -v,可以看到本地仓库与远程仓库的对应关系

git基本概念与原理

图中orgin为远程仓库名称,可以更改

3、推送至远程仓库

git push,推送本地仓库至远程仓库

刚在github上的仓库建立好后,进入该仓库目录,输入一些命令:

#touch t1

#git add . && git commit -m "build t1"

#echo 123 > t1 && git add . && git commit -m "add 123 in t1"

#git checkout -b slv

#echo abc > t2 && git add t2 && git commit -m "built add t2"

之后测试远程连接的仓库,使用命令:

git push origin master:master,将本地master分支推送到远程master分支,

"master:master"中冒号左边的master代表你要推送的本地master分支,冒号右边的master代表推送到远程仓库中的master分支

命令结果:

git基本概念与原理

如果本地仓库master 分支推送至远程仓库并不存在的分支,即使用命令:

git push origin master:m1,远程仓库会自动创建新的分支m1。

#git push:如果git中只有一条分支,推送时可以使用命令git push,当远程仓库没有该分支,会自动新建这个分支。

当我们把新建的分支推向远程仓库时,需要输入指令

#git push --set-upstream origin slv:slv   ----------->git 1.x版本

#git push -u orgin slv:slv  ------------->git 2.x版本

,将此分支slv推到远程仓库后,等下次在slv分支文件做出改变时,位于slv分支时输入git push,便可以自动推送slv分支到远程slv分支了。

图示:

#git branch -vv:显示本地分支信息

#git branch -vva:显示本地与远程分支信息

图中origin只有master有,slv没有,说明slv没有推送至远程仓库

git基本概念与原理

将slv分支推入远程仓库,之后再git branch -vva,发现本地slv分支已经至远程仓库的myremote-slv分支。

git基本概念与原理

4、他人加入该远程仓库

使用命令:git remote add origin [email protected]:json-chenux/test.git

5、git pull

#git push --all:此命令表示当本地各分支与远程仓库各分支同名时,push所有分支的更新到对应的远程分支。

#git fetch:此命令表示获取远程仓库的更新到本地,但是不会更新本地分支中的代码。

#git pull:此命令表示当本地分支与上游分支同名时,对当前分支执行pull操作,对其他分支执行fetch操作,具体的差异主要取决于对应的远程分支有没有更新。

 #git pull remote brancha:此命令表示将remote仓库的a分支pull到本地当前所在分支,如果你想要pull到本地的a分支,需要先checkout到本地a分支中。

 #git pull remote brancha:branchb:此命令表示将远程仓库的a分支pull到本地的b分支,成功之后(如果操作失败,则后面的操作不会执行)再将远程a分支pull到本地的当前所在的分支。                                                                                                                     

继续阅读