运维入门之git服务器

git是linus为了管理Linux内核代码而设计的管理工具,成为目前最流行也是应用最为广泛的版本控制工具

git的基本结构

这张表格只是大概描述git的几个区域,在官网有一个动态的说明文档git的结构及命令

  • Workaspace:用户的操作空间,也就是我们编辑文档的目录
  • Index :索引区,git add之后,会在索引区建立文档的一个索引,也可以理解为暂存区或者缓冲区;
  • Repository:这里指的是本地的仓库,真正存储数据和索引的地方;
  • Remote Repository:远程仓库,实际中应用最多的一种。

git的工作原理

git版本控制是基于类似快照的方式存在,当文件内容不发生变化时,则只建立快捷,当文件内容发生变化时,则通过复制文件+变化内容=新文件;文件在Repository中的存在形式是文件对象(包括数据+数据位置等信息)的hash值存在;
简单过程也可以用如下图表示:

  • 当文件A发生变化,文件B不变,我们的工作目录依然是两个文件,git add之后,索引区会对文件A进行重新求hash值并记录,git commit(提交)之后,文件A会重新保存一份,而文件B只是创建一个链接指向新的HEAD
  • master则指向新的HEAD,此时HEAD值已经发生变化
  • 图中黑色提交表示蓝色提交的父提交

git的配置文件

git有三种配置文件

  • 仓库特有:.git/config (git config)
  • 全局配置:~/.gitconfig(git config --global
  • 系统配置:/etc/git/gitconfig(git config --system

git对象类型

  • Blob对象:文件的每个版本表现为一个BLOB文件,可以理解为文件的存在形式
  • tree对象:每一级目录便是树状结构的一个节点,索引中的对象commit之后则创建树对象
  • 提交对象:保存版本库一次变化的元数据,作者、日期、邮箱、日志等,每个对象都指定一个目录树对象
  • 标签对象:用于对一个特定对象一个已读的名称

git中的文件分类

  • 已追踪(tracked):使用git add命令添加至索引中的文件
  • 被忽略(igonre):在版本库中通过“忽略文件列表[./.gitigonre]”明确声明的文件,支持正则表达,在仓库的根目录;
  • 未追踪(untracked):除了以上两种的其他文件

git分支

在程序的编写提交过程中,可能涉及多个工作组同时对代码进行修改、提交,为此便出现了分支,其结构如图(一以下内容中黄色圆圈表示一个commit):

分支的命名规则:

1、可以使用“/”,但是不可以“/”结尾

2、不能以“-”开头

3、以位于“/”后面的组件,不能以“.”开头

4、不能使用连续的“.”;

5、不能包含空白字符;

6、不能使用^、~、?、*、[等正则意义的符号

7、必须唯一;

8、分支名字始终指向目标分支的最近提交

最简单的命令如下:
git branch [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]

git branch $BRANCHNAME $START-POINT
例如:实现上图中的分支结构
[root@localhost myproject]#git branch B1 B

例如:查看分支

[root@localhost myproject]# git branch -l
B1
* master

例如:切换到分支B1

[root@localhost myproject]# git checkout B1
Switched to branch ‘B1’
[root@localhost myproject]#git branch -l
* B1
master

这里有一个HEAD与master的概念,个人理解HEAD就如同一个指针函数,当你想回溯到哪个节点上,HEAD直接指向那个节点即可;而master则表示最近的一次commit(提交),可以用下图理解:

此时我们就切换到了分支B1的工作环境下,使用git cat-file -p HEAD便可看到B1的tree对象

GIT分支的合并(一)

正所谓“天下大势,分久必合”,分支势必有合并的一天,结构如下:

基本命令如下:
git merge -m <msg> $FRANCHNAME <commit>

这里就有两个概念“^”和“~”:

  • ~:以当前提交向前的父提交,例如:~1表示父提交1,~2表示父提交2(分支合并提交中,表示父提交2)
  • ^:以当前分支父提交递归,例如:^1~1表示父提交1的父提交

这样的表述可能更加模糊,从下图即可直观的看到两者之间的关系;

  • F(HEAD)的分支父提交仅且只有两个:E(HEAD^1)和D1(HEAD^2),这里1和2的顺序是根据master来的(递归父提交优先),此时如果你使用HEAD^3则会报错,因为没有其他的分支父提交
  • D(HEAD~2)是E(HEAD^1)master线上的递归父提交,则表示为HEAD~2或者HEAD~1~1或者HEAD^1~1
  • E(HEAD~1\HEAD^1)因为即是F(HEAD)的递归父提交,又是分支合并的父提交,则有两种表示方式,C(HEAD~3)同理也有两种表示方式

    当然最简单的方法就是git log --graph或者git log --graph --pretty=oneline --abbrev-commit查看整个tree对象,然后查看到每个commit对应的hash值,直接调用hash值即可

[root@localhost myproject]# git log --graph --pretty=oneline --abbrev-commit
*   f50cb1f Merge branch 'devel'
|\  
| * 6beff3e v0.0.2-3
* |   b9ffb4a Merge branch 'devel'
|\ \  
| |/  
| * 5af2c01 v0.0.2-2
| * f31763f v0.0.2-1
* | fb84fb7 v0.0.4
* | cb22d49 v0.0.3
|/  
* 2304fe2 v0.0.2
* 86777c6 v0.0.1

git分支合并(二)

分支合并除了merge这样的方式之外还有一种,叫做rebase。有人称此过程为变基,也有人称为衍合;下面从图例就可以看到主要区别:

上图是HEAD指向节点D时,分支B指向B2时,我们切换至B分支,然后将master从节点D rebase至分支B的B2节点上git rebase master,则就会出现如上的结果;rebase与merge不同就是缺少了一个节点,在现有分支上将数据取&;
此时可以解释为:删除原有分支B节点,临时保存原数据以补丁追加至节点D之后。可以通过查看前后的各节点的hash值来确定


[root@localhost myproject]# git checkout B
Switched to branch 'B'
[root@localhost myproject]# git rebase  master      
First, rewinding head to replay your work on top of it...
Applying: B1
Applying: B2
[root@localhost myproject]# git log --graph --pretty=oneline --abbrev-commit
* 5fddaec B2
* 0835079 B1
* b8dac7d D
* 3beae4e C
* 0cf96de B
* 906ba55 A
[root@localhost myproject]# git checkout master
Switched to branch 'master'
[root@localhost myproject]# git log --graph --pretty=oneline --abbrev-commit
* b8dac7d D
* 3beae4e C
* 0cf96de B
* 906ba55 A

猜你喜欢

转载自blog.csdn.net/weixin_42867549/article/details/88563928