本文只是抛砖引玉; Phtml
在下在 Shopee 工做,以为水深火热不喜欢加班的同窗能够考虑一下git
拒绝 996,那就来 shopee,待遇 work life balance 两不: www.v2ex.com/t/672561#re…算法
国际劳动节又称 “五一国际劳动节”、“国际示威游行日”(International Workers' Day 或者 May Day),是世界上 80 多个国家的全国性节日。定在每一年的五月一日。它是全世界劳动人民共同拥有的节日。数据库
1884 年 10 月,美国和加拿大的八个国际性和全国性工人团体,在美国芝加哥举行一个集会,决定于 1886 年 5 月 1 日举行总罢工,迫使资本家实施八小时工做制。这一天终于来到了。1886 年 5 月 1 日,美国 2 万多个企业的 35 万工人停工上街,举行了声势浩大的示威游行,各类肤色,各个工种的工人一齐进行总罢工。仅芝加哥一个城市,就有 4.5 万名工人涌上街头。这下,美国的主要工业部门便处于瘫痪状态,火车变成了僵蛇,商店更是鸦雀无声,全部的仓库也都关门并贴上封条。api
1866 年,第一国际日内瓦会议提出八小时工做制的口号。 [4] 1886 年 5 月 1 日,以美国芝加哥为中心,在美国举行了约 35 万人参加的大规模罢工和示威游行,示威者要求改善劳动条件,实行八小时工做制。1886 年 5 月 3 日芝加哥政府出动警察进行镇压,开枪打死两人,事态扩大,5 月 4 日罢工工人在干草市场广场举行抗议,因为不明身份者向警察投掷炸弹,最终警察开枪,前后共有 4 位工人、7 位警察死亡,史称 “干草市场暴乱”(Haymarket Riot)或 “干草市场屠杀”(Haymarket Massacre)。在随后的宣判中有 8 位无政府主义者以谋杀罪被起诉,4 位无政府主义者被绞死,1 位在牢中自杀。bash
为记念此次伟大的工人运动及抗议随后的宣判,在世界范围内举行了工人的抗议活动。这些活动成为了 “国际劳动节” 的前身。服务器
1889 年 7 月,在恩格斯组织召开的第二国际成立大会上宣布将每一年的五月一日定为国际劳动节。网络
通过艰苦的流血斗争,终于得到了胜利。为记念此次工人运动,1889 年 7 月 14 日,由各国马克思主义者召集的社会主义者表明大会,在法国巴黎隆重开幕。大会上,会表明一致赞成:把 5 月 1 日定为国际无产阶级的共同节日。这一决定当即获得世界各国工人的积极响应。1890 年 5 月 1 日,欧美各国的工人阶级率先走向街头,举行盛大的示威游行与集会,争取合法权益。今后,每逢这一天世界各国的劳动人民都要集会、游行,以示庆祝,并公众放假。数据结构
五一国际劳动节,一块儿写一个简单的Git吧!分布式
Git is a distributed version-control system for tracking changes in source code during software development.
各位读者就算不了解git的原理,想必也会用三把斧git add; git commit; git push
,下面就简单说一下git是怎么作的版本管理的:跟踪文件的变化,使用commit做为标记,与远程服务器同步。
假如你来开发git这个工具,在初始化一个文件夹(repository)后,为了记录以后可能的修改,你须要记录当前全部须要跟踪的文件内容,最简单的就是所有复制一份好了。
文件是否变化了?比较一下文件哈希好了。
顾言思义,就是将当前的repository
状态存储起来,做为commit。你能够经过commit
恢复到任意状态,git tag
本质也只是给这个commit
一个tag
(别名),git branch
也是同样。
恢复到某一个commit
,就是将它所表明的repository
状态恢复起来,就是将文件所有内容以及当前commit恢复到那个状态。
git说本身是分布式的版本管理系统,是由于假如A、B、C三我的一块儿合做,理论上每一个人都有一份server的版本,并且能够独立开发,解决冲突。
原理说完了,但commit的管理是要用东西来存储读取管理的,Git没有用数据库,直接将其内容放到.git
文件夹里。
里面有什么内容呢?
.
|-- HEAD //指向branch、tag (ref: refs/heads/devbranch)
|-- index
|-- objects
| |-- 05
| | `-- 76fac355dd17e39fd2671b010e36299f713b4d
| |-- 0c
| | `-- 819c497e4eca8e08422e61adec781cc91d125d
| |-- fe
| | `-- 897108953cc224f417551031beacc396b11fb0
| |-- fe
| | `-- 897108953cc224f417551031beacc396b11fb0
| |-- info
|
`-- refs
|-- heads //各个branch的heads
| `-- master //此分支最新的commit id
| `-- devBranch // checkout -b branch就会生成的branch
`-- tags
`-- v0.1
复制代码
各位再结合
下面我展开讲讲:
HEAD
: 指向branch或者tag,标记当前是在哪一个分支或者tag上;index
: TODOobjects
:记录文件的内容,每一个文件夹名称是该object的sha1值的前两位,文件夹下的文件名称是sha1值的后18位;(tips:sha1算法,是一种加密算法,会计算当前内容的哈希值,做为object的文件名,获得的哈希值是一个用十六进制数字组成的字符串(长度为40))refs
heads
: heads
里的就是各个分支的HEAD
分别指向哪一个commit id
;简单说,就是 各个branch分别最新的commit是什么,这样子git checkout branch
就能够切换到对的地方tags
: 同理,这个文件夹里存的都是各个tag那么,新建一个branch的时候,只要在refs/heads
文件夹里新建branch 名字的文件,并将当前commit id存进去便可;
新建一个commit时,只要根据HEAD
文件,找到当前的branch或者tag
是什么,修改里面的内容便可。
有点很差懂?咱给出一个git的实例,默认在一个文件夹执行git init
后,添加一个文件并commit
的信息, commit id为017aa3d7851e8bbff78a697566b5f827b183483c
:
$ cat .git/HEAD
ref: refs/heads/master
$ cat .git/refs/heads/master
017aa3d7851e8bbff78a697566b5f827b183483c
复制代码
如上,HEAD
指向了master,而master
的commit id正是刚刚commit的id。
将当前的
repository
状态存储起来,做为commit。你能够经过commit
恢复到任意状态,git tag
本质也只是给这个commit
一个tag
(别名),git branch
也是同样。恢复到某一个
commit
,就是将它所表明的repository
状态恢复起来,就是将文件所有内容以及当前commit恢复到那个状态。
上面说了,管理文件夹(repository)状态,可是文件夹是能够嵌套的,与文件不同,须要有这层级关系,同时也要存文件内容,怎么作来区分呢?
咱们能够引入如下概念:
Tree:表明文件夹,由于git init
时,就是把当前文件夹./
做为项目来管理,那么接下来全部要追踪的项目无非就是./
里的文件或者文件夹而已;
Blob:文件,Tree里能够包含它;
关系以下图:
给点咱们写的数据结构代码你看看,要注意的是,tree
能够拥有blob
或者tree
,因此用了union
;parent
与next
做为链表使用,做为文件夹目录管理;
struct tree_entry_list {
struct tree_entry_list *next;
union {
struct tree *tree;
struct blob *blob;
} item;
struct tree_entry_list *parent;
};
struct tree {
struct tree_entry_list *entries;
};
复制代码
而commit
跟树同样,也是有层级的单链表,不过只有
struct commit {
struct commit *parents;
struct tree *tree;
char *commit_id[10];
char *author;
char *committer;
char *changelog;
};
复制代码
一图胜千言,看图吧:
云风参考过git的原理作过一个游戏资源仓库管理,我下面讲一下它跟git的区别,他的文章我以为比较绕,没有背景知识的人很难看明白。
咱们的引擎的一个重要特性就是,在 PC 上开发,在移动设备上运行调试。咱们须要频繁的将资源同步到设备上
程序以 c/s 结构运行时,在移动设备上先创建一个空的镜像仓库,同步 PC 端的资源仓库。运行流程是这样的:
首先在客户端启动的时候,向服务器索取一个根索引的 hash ,在本地镜像上设定根。
客户端请求一个文件路径时,从根开始寻找对应的目录索引文件,逐级查找。若是本地有所需的 hash 对象,就直接使用;不然向服务器请求,直到最后得到目标文件。api 的设计上,open 一个资源路径,要么返回最终的文件,要么返回一个 hash ,表示当前还缺乏这个 hash 对象;这样,能够经过网络模块请求这个对象;得到该对象后,无须理会这个对象是什么,简单写入镜像仓库,而后从新前面的过程,再次请求未完成的路径,最终就能打开所需的资源文件。
场景是:Client <- 他的游戏服务器 ,单向同步;
他是这样子作的,客户端的仓库是key-value
的文件数据库,key是文件的hash,value就是文件内容;
同步时,会从根到具体hash全量同步文件下载到数据库
;
假如客户端使用资源时,发现缺少这个文件,就用hash去服务器拉下来。
换言之,由于不须要管理本地版本,而且同步到上游,因此无需在本地记录全量的版本状态
场景是:Client <-> gitHub ,双向同步;
git 须要本地组织commit,切换本地有但服务器没有的版本(就是离线操做) ,同时还须要将变动同步到上游。
若是看完该文,让你跃跃欲试的话,请不要用C写,请不要用C写,请不要用C写。
从零开始写过几个大一点项目,每次都以为用C写项目太难受了,此次我写git commit
时,发现要读写文件,解析内容,我发出了心里的感叹:
太难了,不是写这个难,是C太难用了。。
想到我要遍历这些文件,根据目录获得tree的hash,而后还要update这棵树,把tree跟commit还要blob反序列存到文件里,还要读出来,以后还要组织链表操做,用C写就以为百般阻挠。。。