本文只是拋磚引玉; 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寫就以爲百般阻撓。。。